From b379f5d6fa95c9c938c38ce592739ea732847821 Mon Sep 17 00:00:00 2001
From: ulrich
Date: Sun, 04 Apr 2021 18:08:17 +0000
Subject: [PATCH] Durchstich Neuer Ablageort

---
 www/ui/data/ablageort.css                        |   20 +
 www/ui/data/formulare.css                        |  145 +++++++++++
 src/de/uhilger/mediaz/App.java                   |    2 
 www/ui/data/menu/hauptmenue.json                 |    5 
 src/de/uhilger/mediaz/api/StoreTestHandler.java  |    1 
 www/ui/js/app.js                                 |   76 +++++
 www/ui/index.html                                |   37 +-
 src/de/uhilger/mediaz/api/StoreHandler.java      |  125 +++++++++
 www/ui/data/test.html                            |   28 ++
 src/de/uhilger/mediaz/api/AblageTestHandler.java |   11 
 src/de/uhilger/mediaz/conf/Store.java            |    2 
 www/ui/app.css                                   |  145 +++++++++++
 src/mediaz_de_DE.properties                      |    1 
 src/de/uhilger/mediaz/Server.java                |   76 ++++-
 www/ui/data/tpl/form_ablageort.tpl               |   13 +
 www/ui/data/ablageort.html                       |   43 +++
 16 files changed, 683 insertions(+), 47 deletions(-)

diff --git a/src/de/uhilger/mediaz/App.java b/src/de/uhilger/mediaz/App.java
index 777c985..351bb27 100644
--- a/src/de/uhilger/mediaz/App.java
+++ b/src/de/uhilger/mediaz/App.java
@@ -53,7 +53,7 @@
    *
    * @param args Kommandozeilenparameter
    */
-  public static void main(String[] args) {
+  public static void main(String[] args) throws ClassNotFoundException {
     rb = ResourceBundle.getBundle(RB_NAME);
     logger.info(new File(".").getAbsolutePath());
     
diff --git a/src/de/uhilger/mediaz/Server.java b/src/de/uhilger/mediaz/Server.java
index 7fbef25..375d7af 100644
--- a/src/de/uhilger/mediaz/Server.java
+++ b/src/de/uhilger/mediaz/Server.java
@@ -21,7 +21,11 @@
 import de.uhilger.mediaz.api.AblageTestHandler;
 import de.uhilger.mediaz.api.FileHandler;
 import de.uhilger.mediaz.api.StopServerHandler;
+import de.uhilger.mediaz.api.StoreHandler;
 import de.uhilger.mediaz.api.StoreTestHandler;
+import de.uhilger.mediaz.conf.Store;
+import de.uhilger.mediaz.entity.Ablageort;
+import de.uhilger.mediaz.entity.ConfigurationElement;
 import java.io.File;
 import java.io.IOException;
 import java.util.logging.Logger;
@@ -30,76 +34,83 @@
 import java.util.logging.Level;
 
 /**
- * Die Klasse Server stellt Methoden zur Ausführung eines 
- * HTTP-Servers bereit
- * 
+ * Die Klasse Server stellt Methoden zur Ausführung eines HTTP-Servers
+ * bereit
+ *
  * @author Ulrich Hilger
  * @version 0.1, 25.03.2021
  */
 public class Server {
-  
+
   private static final Logger logger = Logger.getLogger(Server.class.getName());
-  
+
   public static final String RB_SERVER_START_MSG = "msgServerStart";
   public static final String RB_WEBROOT = "webroot";
+  public static final String RB_STORE = "store";
   //public static final String RB_UI_ROOT = "uiroot";
   public static final String RB_STOP_SERVER = "stopServer";
   public static final String RB_ABLAGE_TEST = "testAblage";
   public static final String RB_STORE_TEST = "testStore";
   public static final String RB_SLASH = "slash";
-  
+
   private int port;
-  
+
   private String ctx;
-  
+
   /**
    * Ein neues Objekt der Kalsse Server erzeugen
-   * @param port  der Port, über den dieser Server erreichbar sein soll
+   *
+   * @param port der Port, über den dieser Server erreichbar sein soll
    */
   public Server(int port) {
     this.port = port;
   }
-  
+
   /**
    * Den Port angeben, unter dem der Server erreichbar sein soll
-   * 
+   *
    * @param port der Port, unter dem der Server erreichbar sein soll
    */
   public void setPort(int port) {
     this.port = port;
   }
-  
+
   /**
-   * Den Namen des Kontexts angeben, über den dieser Server 
-   * erreichbar sein soll
+   * Den Namen des Kontexts angeben, über den dieser Server erreichbar sein
+   * soll
+   *
    * @param ctxName Name des Kontexts, unter dem der Server aufrufbar sein soll
    */
   public void setContextName(String ctxName) {
     String slash = App.getRs(RB_SLASH);
-    if(!ctxName.startsWith(slash)) {
+    if (!ctxName.startsWith(slash)) {
       this.ctx = slash + ctxName;
     } else {
       this.ctx = ctxName;
     }
   }
-  
+
   /**
-   * Die Endpunkte ('Context'e) einrichten, unter denen die Dienste 
-   * dieses Servers erreichbar sein sollen und den Server starten
-   * 
-   * @throws IOException wenn etwas schief geht, finden sich Angaben 
-   * in diesem Objekt 
+   * Die Endpunkte ('Context'e) einrichten, unter denen die Dienste dieses
+   * Servers erreichbar sein sollen und den Server starten
+   *
+   * @throws IOException wenn etwas schief geht, finden sich Angaben in diesem
+   * Objekt
+   * @throws java.lang.ClassNotFoundException
    */
-  public void start() throws IOException {
+  public void start() throws IOException, ClassNotFoundException {
     logger.log(Level.INFO, App.getRs(RB_SERVER_START_MSG), Integer.toString(port));
-    
+
     String wwwData = App.getInitParameter(App.getRs(App.RB_AP_WWW_DATA));
     File wwwDir = new File(wwwData);
     //String ui = App.getInitParameter(App.getRs(App.RB_AP_UI));
     //File uiDir = new File(ui);
 
     HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
-    server.createContext(ctx + App.getRs(RB_WEBROOT), new FileHandler(wwwDir.getAbsolutePath()));
+    server.createContext(ctx + App.getRs(RB_WEBROOT), 
+            new FileHandler(wwwDir.getAbsolutePath()));
+    ablageorteEinklinken(server);
+    server.createContext(ctx + App.getRs(RB_STORE), new StoreHandler());
     //server.createContext(ctx + App.getRs(RB_UI_ROOT), new FileHandler(uiDir.getAbsolutePath()));    
     server.createContext(ctx + App.getRs(RB_STOP_SERVER), new StopServerHandler());
     server.createContext(ctx + App.getRs(RB_ABLAGE_TEST), new AblageTestHandler());
@@ -108,4 +119,21 @@
     server.start();
   }
 
+  private void ablageorteEinklinken(HttpServer server) throws ClassNotFoundException, IOException {
+    Store store = new Store();
+    String conf = App.getInitParameter(App.getRs(App.RB_AP_CONF));
+    File ablageortDir = new File(conf, Ablageort.class.getSimpleName());
+    File[] orte = ablageortDir.listFiles();
+    if (orte != null) {
+      for (File ort : orte) {
+        ConfigurationElement elem = store.readFromFile(ort);
+        if (elem instanceof Ablageort) {
+          Ablageort ablageort = (Ablageort) elem;
+          server.createContext(ctx + ablageort.getUrl(), 
+                  new FileHandler(new File(ablageort.getOrt()).getAbsolutePath()));
+        }
+      }
+    }
+  }
+
 }
diff --git a/src/de/uhilger/mediaz/api/AblageTestHandler.java b/src/de/uhilger/mediaz/api/AblageTestHandler.java
index e43f4c4..b22a6f5 100644
--- a/src/de/uhilger/mediaz/api/AblageTestHandler.java
+++ b/src/de/uhilger/mediaz/api/AblageTestHandler.java
@@ -21,19 +21,20 @@
 
   @Override
   public void handle(HttpExchange e) throws IOException {
-    Ablageort ablage = new Ablageort();
-    ablage.setName("Katalog");
-    ablage.setOrt("/home/ulrich/Videos");
+    Ablageort ablageort = new Ablageort();
+    ablageort.setName("Katalog");
+    ablageort.setOrt("/home/ulrich/Videos");
+    ablageort.setUrl("/media/test");
     
     Gson gson = new Gson();
-    File mediaOrdner = new File(ablage.getOrt());
+    File mediaOrdner = new File(ablageort.getOrt());
     File[] files = mediaOrdner.listFiles();
     String json = gson.toJson(files);
     
     StringBuilder sb = new StringBuilder();
     sb.append(json);
     
-    json = gson.toJson(ablage);
+    json = gson.toJson(ablageort);
     sb.append(json);
     
     byte[] b = sb.toString().getBytes();
diff --git a/src/de/uhilger/mediaz/api/StoreHandler.java b/src/de/uhilger/mediaz/api/StoreHandler.java
new file mode 100644
index 0000000..4e317bb
--- /dev/null
+++ b/src/de/uhilger/mediaz/api/StoreHandler.java
@@ -0,0 +1,125 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package de.uhilger.mediaz.api;
+
+import com.google.gson.Gson;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import de.uhilger.mediaz.App;
+import de.uhilger.mediaz.Server;
+import de.uhilger.mediaz.conf.Store;
+import de.uhilger.mediaz.entity.Ablageort;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author ulrich
+ */
+public class StoreHandler extends Store implements HttpHandler  {
+  
+  private static final Logger logger = Logger.getLogger(StoreHandler.class.getName());
+
+  
+  /*
+  
+    HTTP GET: lies einen Ablageort und schreibe JSON
+    HTTP PUT: schreibe einen neuen Ablageort auf die Platte
+    HTTP POST: schreibe Aenderungen auf die Platte
+    HTTP DELETE: loesche den Ablageort
+  
+    Beispiele:
+  
+    HTTP GET an /mz/api/store/Ablageort/Katalog
+    liest den Ablageort namens "Katalog"
+  
+    HTTP POST an /mz/api/store/Ablageort
+    schreibt den neuen Ablageort im Body der Anfrage
+  
+    HTTP PUT an /mz/api/store/Ablageort
+    sucht den Ablageort mit dem Namen laut Body der Anfrage 
+    und schreibt den Inhalt aus der Anfrage in die Datei
+  
+    HTTP DELETE an /mz/api/store/Ablageort/Katalog
+    löscht den Ablageort namens "Katalog"
+  
+  */
+  
+  public static final String HTTP_GET = "GET";
+  public static final String HTTP_PUT = "PUT";
+  public static final String HTTP_POST = "POST";
+  public static final String HTTP_DELETE = "DELETE";
+
+  @Override
+  public void handle(HttpExchange e) throws IOException {
+    String method = e.getRequestMethod();
+    String path = e.getRequestURI().toString();
+    String[] elems = path.split(App.getRs(Server.RB_SLASH));
+    String type = "";
+    String elemName = "";
+    switch(method) {
+      case HTTP_GET:
+        type = elems[elems.length - 2];
+        elemName = elems[elems.length - 1];
+        //this.readFromFile(file);
+        break;
+        
+      case HTTP_PUT:
+        type = elems[elems.length - 1];
+        elemName = "noch bauen: lesen aus Body";
+        break;
+        
+      case HTTP_POST:
+        type = elems[elems.length - 1];
+        elemName = bodyLesen(e);
+        if(type.equalsIgnoreCase("Ablageort")) {
+          Gson gson = new Gson();
+          Ablageort ort = gson.fromJson(elemName, Ablageort.class);
+          elemName = ort.getName();
+        }
+        break;
+        
+      case HTTP_DELETE:
+        type = elems[elems.length - 2];
+        elemName = elems[elems.length - 1];
+        break;
+    }
+    
+    
+    String response = "Method: " + method + ", Path: " + path + 
+            ", Type: " + type + ", elemName: " + elemName;
+    logger.info(response);
+    e.sendResponseHeaders(200, response.length());
+    OutputStream os = e.getResponseBody();
+    os.write(response.getBytes());
+    os.close();        
+  }
+  
+  
+  private String bodyLesen(HttpExchange e) throws IOException {
+    InputStream is = e.getRequestBody();
+    BufferedReader r = new BufferedReader(new InputStreamReader(is));
+    StringBuilder sb = new StringBuilder();
+    String line = r.readLine();
+    while(line != null) {
+      sb.append(line);
+      line = r.readLine();
+    }
+    r.close();
+    // {"Ablageort":{"name":"test1","ort":"test2","url":"test3"}}
+    //String data = sb.toString();
+    //data = data.substring(1, data.length() - 1);
+    //String json = data.substring(data.indexOf("{"));
+    // {"name":"test1","ort":"test2","url":"test3"}
+    String json = sb.toString();
+    logger.info("json: " + json);
+    return json;
+  }
+}
diff --git a/src/de/uhilger/mediaz/api/StoreTestHandler.java b/src/de/uhilger/mediaz/api/StoreTestHandler.java
index 8e040a0..e1da7c3 100644
--- a/src/de/uhilger/mediaz/api/StoreTestHandler.java
+++ b/src/de/uhilger/mediaz/api/StoreTestHandler.java
@@ -30,6 +30,7 @@
     Ablageort ort = new Ablageort();
     ort.setName("Katalog");
     ort.setOrt("/home/ulrich/Videos");
+    ort.setUrl("/media/test");
     Store store = new Store();
     File file = store.writeToFile(ort);
     try {
diff --git a/src/de/uhilger/mediaz/conf/Store.java b/src/de/uhilger/mediaz/conf/Store.java
index 546aeee..fcfe3ae 100644
--- a/src/de/uhilger/mediaz/conf/Store.java
+++ b/src/de/uhilger/mediaz/conf/Store.java
@@ -94,4 +94,6 @@
     logger.info(parts[parts.length-2]);
     return parts[parts.length-2];
   }
+  
+  
 }
diff --git a/src/mediaz_de_DE.properties b/src/mediaz_de_DE.properties
index b8e6f6f..b95252e 100644
--- a/src/mediaz_de_DE.properties
+++ b/src/mediaz_de_DE.properties
@@ -9,6 +9,7 @@
 # HTTP-Endpunkte
 webroot=/
 # uiroot=/ui
+store=/api/store
 stopServer=/api/server/stop
 testAblage=/api/test/ablage
 testStore=/api/test/store
diff --git a/www/ui/app.css b/www/ui/app.css
index 5827ce8..d5bae40 100644
--- a/www/ui/app.css
+++ b/www/ui/app.css
@@ -117,3 +117,148 @@
   font-size: 1.3em;
   color: #b8b8b8;
 }
+
+/* ab hier Mediazentrale */
+
+.entity-formular {
+  display: flex;
+  flex-flow: column;
+}
+
+.entity-element {
+  margin: 0.4rem;
+}
+
+/*
+@media (min-width: 800px) {
+  .zentrum-behaelter {
+    padding: 0 1em 0 1em;
+  }
+  .zentrum-behaelter, .nord {
+    margin: 0 10% 0 10%;
+  }
+}
+
+
+/* von Skeleton */
+
+/* Buttons
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+  display: inline-block;
+  height: 38px;
+  padding: 0 30px;
+  color: #555;
+  text-align: center;
+  font-size: 11px;
+  font-weight: 600;
+  line-height: 38px;
+  letter-spacing: .1rem;
+  text-transform: uppercase;
+  text-decoration: none;
+  white-space: nowrap;
+  background-color: transparent;
+  border-radius: 4px;
+  border: 1px solid #bbb;
+  cursor: pointer;
+  box-sizing: border-box; }
+.button:hover,
+button:hover,
+input[type="submit"]:hover,
+input[type="reset"]:hover,
+input[type="button"]:hover,
+.button:focus,
+button:focus,
+input[type="submit"]:focus,
+input[type="reset"]:focus,
+input[type="button"]:focus {
+  color: #333;
+  border-color: #888;
+  outline: 0; }
+.button.button-primary,
+button.button-primary,
+input[type="submit"].button-primary,
+input[type="reset"].button-primary,
+input[type="button"].button-primary {
+  color: #FFF;
+  background-color: #33C3F0;
+  border-color: #33C3F0; }
+.button.button-primary:hover,
+button.button-primary:hover,
+input[type="submit"].button-primary:hover,
+input[type="reset"].button-primary:hover,
+input[type="button"].button-primary:hover,
+.button.button-primary:focus,
+button.button-primary:focus,
+input[type="submit"].button-primary:focus,
+input[type="reset"].button-primary:focus,
+input[type="button"].button-primary:focus {
+  color: #FFF;
+  background-color: #1EAEDB;
+  border-color: #1EAEDB; }
+
+
+/* Forms
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="text"],
+input[type="tel"],
+input[type="url"],
+input[type="password"],
+textarea,
+select {
+  height: 38px;
+  padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
+  background-color: #fff;
+  border: 1px solid #D1D1D1;
+  border-radius: 4px;
+  box-shadow: none;
+  box-sizing: border-box; }
+/* Removes awkward default styles on some inputs for iOS */
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="text"],
+input[type="tel"],
+input[type="url"],
+input[type="password"],
+textarea {
+  -webkit-appearance: none;
+     -moz-appearance: none;
+          appearance: none; }
+textarea {
+  min-height: 65px;
+  padding-top: 6px;
+  padding-bottom: 6px; }
+input[type="email"]:focus,
+input[type="number"]:focus,
+input[type="search"]:focus,
+input[type="text"]:focus,
+input[type="tel"]:focus,
+input[type="url"]:focus,
+input[type="password"]:focus,
+textarea:focus,
+select:focus {
+  border: 1px solid #33C3F0;
+  outline: 0; }
+label,
+legend {
+  display: block;
+  margin-bottom: .5rem;
+  font-weight: 600; }
+fieldset {
+  padding: 0;
+  border-width: 0; }
+input[type="checkbox"],
+input[type="radio"] {
+  display: inline; }
+label > .label-body {
+  display: inline-block;
+  margin-left: .5rem;
+  font-weight: normal; }
diff --git a/www/ui/data/ablageort.css b/www/ui/data/ablageort.css
new file mode 100644
index 0000000..923d8ab
--- /dev/null
+++ b/www/ui/data/ablageort.css
@@ -0,0 +1,20 @@
+/*
+To change this license header, choose License Headers in Project Properties.
+To change this template file, choose Tools | Templates
+and open the template in the editor.
+*/
+/* 
+    Created on : 04.04.2021, 17:02:13
+    Author     : ulrich
+*/
+
+
+
+.entity-formular {
+  display: flex;
+  flex-flow: column;
+}
+
+.entity-element {
+  margin: 0.4rem;
+}
\ No newline at end of file
diff --git a/www/ui/data/ablageort.html b/www/ui/data/ablageort.html
new file mode 100644
index 0000000..34ee44d
--- /dev/null
+++ b/www/ui/data/ablageort.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+  Mediazentrale - Personal Media Center
+  Copyright (C) 2021  Ulrich Hilger
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU Affero General Public License as
+  published by the Free Software Foundation, either version 3 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Affero General Public License for more details.
+
+  You should have received a copy of the GNU Affero General Public License
+  along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+<html>
+  <head>
+    <title>Ablageort</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link rel="stylesheet" type="text/css" href="../app.css">
+    <link rel="stylesheet" type="text/css" href="formulare.css">
+    <link rel="stylesheet" type="text/css" href="ablageort.css">
+
+  </head>
+  <body>
+    <div class="entity-formular">
+      Ablageort
+      
+      <input class="entity-element" type="text" id="ablageort-name" placeholder="Name" >
+      <input class="entity-element" type="text" id="ablageort-ort" placeholder="Pfad" >
+      <input class="entity-element" type="text" id="ablageort-url" placeholder="URL" >
+      <div class="entity-buttons">
+        <button class="button-primary" id="ok-btn">Speichern</button>
+        <button class="button" id="cancel-btn">Abbrechen</button>
+      </div>
+      
+    </div>
+  </body>
+</html>
diff --git a/www/ui/data/formulare.css b/www/ui/data/formulare.css
new file mode 100644
index 0000000..a4c677c
--- /dev/null
+++ b/www/ui/data/formulare.css
@@ -0,0 +1,145 @@
+/*
+To change this license header, choose License Headers in Project Properties.
+To change this template file, choose Tools | Templates
+and open the template in the editor.
+*/
+/* 
+    Created on : 04.04.2021, 17:05:29
+    Author     : ulrich
+*/
+
+
+
+@media (min-width: 800px) {
+  .zentrum-behaelter {
+    padding: 0 1em 0 1em;
+  }
+  .zentrum-behaelter, .nord {
+    margin: 0 10% 0 10%;
+  }
+}
+
+
+
+/* von Skeleton */
+
+/* Buttons
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+  display: inline-block;
+  height: 38px;
+  padding: 0 30px;
+  color: #555;
+  text-align: center;
+  font-size: 11px;
+  font-weight: 600;
+  line-height: 38px;
+  letter-spacing: .1rem;
+  text-transform: uppercase;
+  text-decoration: none;
+  white-space: nowrap;
+  background-color: transparent;
+  border-radius: 4px;
+  border: 1px solid #bbb;
+  cursor: pointer;
+  box-sizing: border-box; }
+.button:hover,
+button:hover,
+input[type="submit"]:hover,
+input[type="reset"]:hover,
+input[type="button"]:hover,
+.button:focus,
+button:focus,
+input[type="submit"]:focus,
+input[type="reset"]:focus,
+input[type="button"]:focus {
+  color: #333;
+  border-color: #888;
+  outline: 0; }
+.button.button-primary,
+button.button-primary,
+input[type="submit"].button-primary,
+input[type="reset"].button-primary,
+input[type="button"].button-primary {
+  color: #FFF;
+  background-color: #33C3F0;
+  border-color: #33C3F0; }
+.button.button-primary:hover,
+button.button-primary:hover,
+input[type="submit"].button-primary:hover,
+input[type="reset"].button-primary:hover,
+input[type="button"].button-primary:hover,
+.button.button-primary:focus,
+button.button-primary:focus,
+input[type="submit"].button-primary:focus,
+input[type="reset"].button-primary:focus,
+input[type="button"].button-primary:focus {
+  color: #FFF;
+  background-color: #1EAEDB;
+  border-color: #1EAEDB; }
+
+
+/* Forms
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="text"],
+input[type="tel"],
+input[type="url"],
+input[type="password"],
+textarea,
+select {
+  height: 38px;
+  padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
+  background-color: #fff;
+  border: 1px solid #D1D1D1;
+  border-radius: 4px;
+  box-shadow: none;
+  box-sizing: border-box; }
+/* Removes awkward default styles on some inputs for iOS */
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="text"],
+input[type="tel"],
+input[type="url"],
+input[type="password"],
+textarea {
+  -webkit-appearance: none;
+     -moz-appearance: none;
+          appearance: none; }
+textarea {
+  min-height: 65px;
+  padding-top: 6px;
+  padding-bottom: 6px; }
+input[type="email"]:focus,
+input[type="number"]:focus,
+input[type="search"]:focus,
+input[type="text"]:focus,
+input[type="tel"]:focus,
+input[type="url"]:focus,
+input[type="password"]:focus,
+textarea:focus,
+select:focus {
+  border: 1px solid #33C3F0;
+  outline: 0; }
+label,
+legend {
+  display: block;
+  margin-bottom: .5rem;
+  font-weight: 600; }
+fieldset {
+  padding: 0;
+  border-width: 0; }
+input[type="checkbox"],
+input[type="radio"] {
+  display: inline; }
+label > .label-body {
+  display: inline-block;
+  margin-left: .5rem;
+  font-weight: normal; }
diff --git a/www/ui/data/menu/hauptmenue.json b/www/ui/data/menu/hauptmenue.json
index b0685f0..44f268a 100644
--- a/www/ui/data/menu/hauptmenue.json
+++ b/www/ui/data/menu/hauptmenue.json
@@ -8,6 +8,11 @@
     },
     "inhalt":  [
       {
+        "titel": "Neuer Ablageort",
+        "umenue": false,
+        "funktion": "app.form_ablageort_neu"
+      },
+      {
         "titel": "Seite umschalten",
         "umenue": false,
         "funktion": "app.seitenleiste_umschalten"
diff --git a/www/ui/data/test.html b/www/ui/data/test.html
new file mode 100644
index 0000000..00949d9
--- /dev/null
+++ b/www/ui/data/test.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!--
+  Mediazentrale - Personal Media Center
+  Copyright (C) 2021  Ulrich Hilger
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU Affero General Public License as
+  published by the Free Software Foundation, either version 3 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Affero General Public License for more details.
+
+  You should have received a copy of the GNU Affero General Public License
+  along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+<html>
+  <head>
+    <title>TODO supply a title</title>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  </head>
+  <body>
+    <div>TODO write content</div>
+  </body>
+</html>
diff --git a/www/ui/data/tpl/form_ablageort.tpl b/www/ui/data/tpl/form_ablageort.tpl
new file mode 100644
index 0000000..d6132bf
--- /dev/null
+++ b/www/ui/data/tpl/form_ablageort.tpl
@@ -0,0 +1,13 @@
+    <div class="entity-formular">
+      Ablageort
+      
+      <input class="entity-element" type="text" id="ablageort-name" placeholder="Name" />
+      <input class="entity-element" type="text" id="ablageort-ort" placeholder="Pfad" />
+      <input class="entity-element" type="text" id="ablageort-url" placeholder="URL" />
+      <div class="entity-buttons">
+        <button class="button-primary" id="ok-btn">Speichern</button>
+        <button class="button" id="cancel-btn">Abbrechen</button>
+      </div>
+      
+    </div>
+
diff --git a/www/ui/index.html b/www/ui/index.html
index d206386..2a2f3df 100644
--- a/www/ui/index.html
+++ b/www/ui/index.html
@@ -1,7 +1,24 @@
 <!DOCTYPE html>
+<!--
+  Mediazentrale - Personal Media Center
+  Copyright (C) 2021  Ulrich Hilger
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU Affero General Public License as
+  published by the Free Software Foundation, either version 3 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU Affero General Public License for more details.
+
+  You should have received a copy of the GNU Affero General Public License
+  along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
 <html>
   <head>
-    <title>App-Vorlage</title>
+    <title>Mediazentrale</title>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta name="apple-mobile-web-app-capable" content="yes" />
@@ -21,7 +38,7 @@
         </div>
       </div>
       <div class="app-titel">
-        <span id="app-titel">App-Vorlage</span>
+        <span id="app-titel">Mediazentrale</span>
       </div>
     </div>
     <div class="inhalt">
@@ -36,19 +53,7 @@
         <div class="zentrum">
           <div class="zentraler-inhalt">
             <p>
-              Hier kann beliebiger Inhalt erscheinen.
-            </p>
-            <p>
-              Wenn dessen Darstellung mehr
-              Platz benötigt als das Anzeigegerät bietet wird ein
-              Rollbalken eingeblendet. Beim Rollen zu anfangs nicht sichtbaren
-              Teilen des Inhalts bleiben die den Inhaltsbereich
-              umschließenden Elemente sichtbar.
-            </p>
-            <p>
-              Ein Klick auf das Hamburger-Piktogramm oben links bzw. dessen
-              Antippen blendet ein Menü ein von dem aus weitere Funktionen
-              ausgelöst werden können.
+              Hier erschient der Media-Inhalt.
             </p>
           </div>
         </div>
@@ -70,7 +75,7 @@
     <script>
 		var app;
 		document.addEventListener('DOMContentLoaded', function () {
-			app = new AppVorlage();
+			app = new Mediazentrale();
 			app.init();
 		});
     </script>
diff --git a/www/ui/js/app.js b/www/ui/js/app.js
index 4eaffef..f7cd6be 100644
--- a/www/ui/js/app.js
+++ b/www/ui/js/app.js
@@ -1,10 +1,84 @@
-function AppVorlage() {
+function Ablageort(n, o, u) {
+  this.name = n;
+  this.ort = o;
+  this.url = u;
+}
+
+
+
+function Mediazentrale() {
   var self = this;
   var appMenu;
   // var vorlagen;
   var cache; // mustache templates
 
 
+
+  this.form_ablageort_neu = function() {
+    self.vorlage_laden_und_fuellen("data/tpl/form_ablageort.tpl", "", function(html) {
+      document.querySelector(".zentraler-inhalt").innerHTML = html;
+      self.addEvtListener('#ok-btn', 'click', function() {
+        // hier neuen Ablageort speichern
+        var a = new Ablageort(
+          document.querySelector('#ablageort-name').value,
+          document.querySelector('#ablageort-ort').value,
+          document.querySelector('#ablageort-url').value
+        );
+        // {"name":"Katalog","ort":"/home/ulrich/Videos","url":"/media/test"}
+        //var daten = self.serialisieren(a);
+        var daten = JSON.stringify(a);
+        self.http_post('../api/store/Ablageort', daten, function(){
+          // hier die Antwort verarbeiten
+        });
+      });
+      self.addEvtListener('#cancel-btn', 'click', function() {
+        // hier die Aktion abbrechen
+      });
+    });
+  };
+
+  this.addEvtListener = function(selector, eventName, func) {
+    var elems = document.querySelectorAll(selector);
+    var index;
+    for (index = 0; index < elems.length; index++) {
+      elems[index].addEventListener(eventName, func);
+    }
+  };
+  
+  this.http_get = function(u, cb)  {
+    self.http_call('GET', u, null, cb);
+  };
+  
+  this.http_post = function(u, data, cb) {
+    self.http_call('POST', u, data, cb);
+  };
+
+  this.http_call = function (method, u, data, scallback) {    
+    var xhr = new XMLHttpRequest();
+    var url = u;
+    xhr.onreadystatechange = function() {
+      if (this.readyState === 4 && this.status === 200) {
+        scallback(this.responseText);
+      }
+    };
+    xhr.open(method, url);
+    if(method === 'GET')  {
+      xhr.send();
+    } else if(method === 'POST' || method === 'PUT') {
+      xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+      xhr.send(data);
+    }
+  };
+  
+  this.serialisieren = function(obj) {
+    return '{"' + obj.constructor.name + '":' + JSON.stringify(obj) + '}';
+  };
+  
+
+
+
+  /* ab hier aus App-Vorlage */ 
+  
   this.init = function() {
     //self.vorlagen = new Vorlagen();
     self.cache = new Array();

--
Gitblit v1.9.3