From 002c445416c96ec3af57df02e86ac8d5aaecf38b Mon Sep 17 00:00:00 2001
From: ulrich@undisclosed
Date: Fri, 08 May 2020 15:36:26 +0000
Subject: [PATCH] ui2 begonnen

---
 web/ui2/data/menu/edit.json         |   27 +
 web/ui2/data/tpl/app-menu.tpl       |   20 +
 web/ui2/data/tpl/inhalt.tpl         |    3 
 web/ui2/js/app-menu.js              |  137 +++++++
 web/ui2/stile.css                   |  322 ++++++++++++++++
 web/ui2/data/menu/untermenue-1.json |   27 +
 web/ui2/js/data.js                  |  148 +++++++
 web/ui2/js/vorlagen.js              |   66 +++
 web/ui2/js/app.js                   |  186 +++++++++
 web/ui2/data/menu/datei.json        |   27 +
 web/ui2/data/menu/nutzer.json       |   27 +
 web/ui2/data/menu/hauptmenue.json   |   27 +
 web/ui2/data/tpl/dlg-info.tpl       |    8 
 web/ui2/font/pikto.ttf              |    0 
 web/ui2/index.html                  |   75 +++
 web/ui2/data/menu/untermenue-2.json |   27 +
 16 files changed, 1,127 insertions(+), 0 deletions(-)

diff --git a/web/ui2/data/menu/datei.json b/web/ui2/data/menu/datei.json
new file mode 100644
index 0000000..7cbedb9
--- /dev/null
+++ b/web/ui2/data/menu/datei.json
@@ -0,0 +1,27 @@
+{
+  "menue": {
+    "menuetitel": "Datei",
+    "wurzel": false,
+    "vorgaenger": {
+      "vtitel": "Hauptmenü",
+      "vverweis": "hauptmenue.json"
+    },
+    "inhalt": [
+      {
+        "titel": "Neuer Text",
+        "umenue": false,
+        "funktion": "app.datei_neuer_text"
+      },
+      {
+        "titel": "noch mehr",
+        "umenue": true,
+        "verweis": "untermenue-2.json"
+      },
+      {
+        "titel": "Benachrichtigung 2",
+        "umenue": false,
+        "funktion": "app.message_2"
+      }
+    ]
+  }
+}
diff --git a/web/ui2/data/menu/edit.json b/web/ui2/data/menu/edit.json
new file mode 100644
index 0000000..24f547c
--- /dev/null
+++ b/web/ui2/data/menu/edit.json
@@ -0,0 +1,27 @@
+{
+  "menue": {
+    "menuetitel": "Untermenü 1",
+    "wurzel": false,
+    "vorgaenger": {
+      "vtitel": "Hauptmenü",
+      "vverweis": "hauptmenue.json"
+    },
+    "inhalt": [
+      {
+        "titel": "Benachrichtigung 1",
+        "umenue": false,
+        "funktion": "app.message_1"
+      },
+      {
+        "titel": "noch mehr",
+        "umenue": true,
+        "verweis": "untermenue-2.json"
+      },
+      {
+        "titel": "Benachrichtigung 2",
+        "umenue": false,
+        "funktion": "app.message_2"
+      }
+    ]
+  }
+}
diff --git a/web/ui2/data/menu/hauptmenue.json b/web/ui2/data/menu/hauptmenue.json
new file mode 100644
index 0000000..da2c9e5
--- /dev/null
+++ b/web/ui2/data/menu/hauptmenue.json
@@ -0,0 +1,27 @@
+{
+  "menue": {
+    "menuetitel": "Hauptmenü",
+    "wurzel": true,
+    "vorgaenger": {
+      "vtitel": "",
+      "vverweis": ""
+    },
+    "inhalt":  [
+      {
+        "titel": "Datei",
+        "umenue": true,
+        "verweis": "datei.json"
+      },
+      {
+        "titel": "Bearbeiten",
+        "umenue": true,
+        "verweis": "edit.json"
+      },
+      {
+        "titel": "Nutzer",
+        "umenue": true,
+        "verweis": "nutzer.json"
+      }
+    ]
+  }
+}
diff --git a/web/ui2/data/menu/nutzer.json b/web/ui2/data/menu/nutzer.json
new file mode 100644
index 0000000..deec071
--- /dev/null
+++ b/web/ui2/data/menu/nutzer.json
@@ -0,0 +1,27 @@
+{
+  "menue": {
+    "menuetitel": "Untermenü 1",
+    "wurzel": false,
+    "vorgaenger": {
+      "vtitel": "Hauptmenü",
+      "vverweis": "hauptmenue.json"
+    },
+    "inhalt": [
+      {
+        "titel": "Benachrichtigung 1",
+        "umenue": false,
+        "funktion": "app.message_1"
+      },
+      {
+        "titel": "noch mehr",
+        "umenue": true,
+        "verweis": "untermenue-2.json"
+      },
+      {
+        "titel": "Abmelden",
+        "umenue": false,
+        "funktion": "app.fm_logout"
+      }
+    ]
+  }
+}
diff --git a/web/ui2/data/menu/untermenue-1.json b/web/ui2/data/menu/untermenue-1.json
new file mode 100644
index 0000000..24f547c
--- /dev/null
+++ b/web/ui2/data/menu/untermenue-1.json
@@ -0,0 +1,27 @@
+{
+  "menue": {
+    "menuetitel": "Untermenü 1",
+    "wurzel": false,
+    "vorgaenger": {
+      "vtitel": "Hauptmenü",
+      "vverweis": "hauptmenue.json"
+    },
+    "inhalt": [
+      {
+        "titel": "Benachrichtigung 1",
+        "umenue": false,
+        "funktion": "app.message_1"
+      },
+      {
+        "titel": "noch mehr",
+        "umenue": true,
+        "verweis": "untermenue-2.json"
+      },
+      {
+        "titel": "Benachrichtigung 2",
+        "umenue": false,
+        "funktion": "app.message_2"
+      }
+    ]
+  }
+}
diff --git a/web/ui2/data/menu/untermenue-2.json b/web/ui2/data/menu/untermenue-2.json
new file mode 100644
index 0000000..00c0268
--- /dev/null
+++ b/web/ui2/data/menu/untermenue-2.json
@@ -0,0 +1,27 @@
+{
+  "menue": {
+    "menuetitel": "Untermenü 2",
+    "wurzel": false,
+    "vorgaenger": {
+      "vtitel": "Untermenü 1",
+      "vverweis": "untermenue-1.json"
+    },
+    "inhalt":  [
+      {
+        "titel": "Funktion U2.1",
+        "umenue": false,
+        "funktion": "app.message_3('U2.1')"
+      },
+      {
+        "titel": "Funktion U2.2",
+        "umenue": false,
+        "funktion": "app.message_3('U2.2')"
+      },
+      {
+        "titel": "Funktion U2.3",
+        "umenue": false,
+        "funktion": "app.message_3('U2.3')"
+      }
+    ]
+  }
+}
diff --git a/web/ui2/data/tpl/app-menu.tpl b/web/ui2/data/tpl/app-menu.tpl
new file mode 100644
index 0000000..de9b1e4
--- /dev/null
+++ b/web/ui2/data/tpl/app-menu.tpl
@@ -0,0 +1,20 @@
+{{#menue}}
+  <p class="app-menu-kopf">
+    {{menuetitel}}
+  </p>
+  <ul class="app-menu">
+    {{^wurzel}}
+      <li class="app-menu-item-back bitem" data-verweis="{{vorgaenger.vverweis}}">
+        &#10094; {{vorgaenger.vtitel}}</i>
+      </li>
+    {{/wurzel}}                  
+    {{#inhalt}}          
+      {{#umenue}}          
+        <li class="app-menu-item smenu" data-verweis="{{verweis}}">{{titel}}&nbsp;&#10095;</li>
+      {{/umenue}}          
+      {{^umenue}}          
+        <li class="app-menu-item mitem" data-verweis="{{funktion}}" >{{titel}}&nbsp;<span class="app-menu-item-submark">&#10095;</span></i></li>
+      {{/umenue}}          
+    {{/inhalt}}
+  </ul>
+{{/menue}}
\ No newline at end of file
diff --git a/web/ui2/data/tpl/dlg-info.tpl b/web/ui2/data/tpl/dlg-info.tpl
new file mode 100644
index 0000000..692ace2
--- /dev/null
+++ b/web/ui2/data/tpl/dlg-info.tpl
@@ -0,0 +1,8 @@
+<div class="dlg-info">
+  <span class="close-btn pointer-cursor">&#10006;</span>
+  <div class="dlg-behaelter">
+    <div class="dlg-info-app-titel">app-vorlage</div>
+    <div class="dlg-info-app-info">Eine Vorlage f&uuml;r Apps von <a href='https://uhilger.de'>Ulrich Hilger</a>.</div>
+    <div class="dlg-info-app-info">Weitere Infos im <a href='/gitblit/docs/web!app-vorlage.git'>Code-Repository</a>.</div>
+  </div>
+</div>
diff --git a/web/ui2/data/tpl/inhalt.tpl b/web/ui2/data/tpl/inhalt.tpl
new file mode 100644
index 0000000..56f553e
--- /dev/null
+++ b/web/ui2/data/tpl/inhalt.tpl
@@ -0,0 +1,3 @@
+<div>
+  
+</div>
diff --git a/web/ui2/font/pikto.ttf b/web/ui2/font/pikto.ttf
new file mode 100644
index 0000000..175b3f4
--- /dev/null
+++ b/web/ui2/font/pikto.ttf
Binary files differ
diff --git a/web/ui2/index.html b/web/ui2/index.html
new file mode 100644
index 0000000..65e9f32
--- /dev/null
+++ b/web/ui2/index.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Nutzerverwaltung</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" />
+    <link href="https://fonts.googleapis.com/css?family=Roboto+Condensed" rel="stylesheet">
+    <link rel="stylesheet" type="text/css" href="stile.css">
+  </head>
+  <body>
+    <!-- Kopfzeile -->
+    <div class="nord">
+      <div id="nav-menu">
+        <div id="nav-toggle" class="hamburger hamburger--elastic">
+          <div class="hamburger-box">
+            <div class="hamburger-inner"></div>
+          </div>
+        </div>
+      </div>
+      <div class="app-titel">
+        <span id="app-titel">Nutzerverwaltung</span>
+      </div>
+    </div>
+    <div class="inhalt">
+      <!-- westliche Seitenleiste -->
+      <div class="west">
+        westliche Seitenleiste
+      </div>
+      <div class="zentrum-behaelter">
+        <!-- Einblendbereich -->
+        <div class="dialog"></div>
+        <!-- Breadcrumb -->
+        <div class="breadcrumb">
+          <a class="bc-link">Ordner 1</a> / 
+          <a class="bc-link">Ordner 2</a>
+        </div>
+        <!-- zentraler Inhaltsbereich -->
+        <div class="zentrum">
+          <div class="zentraler-inhalt">
+            <div class="zentrum-liste" id="nutzer">
+              <figure>
+                <i class="demo-icon icon-folder">&#xe800;</i> 
+                <figcaption class="i-name">icon-folder</figcaption>
+              </figure>
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- oestliche Seitenleiste -->
+      <div class="ost ost-open">
+        &ouml;stliche Seitenleiste
+      </div>
+    </div>
+    <!-- Fusszeile -->
+    <div class="sued sued-open">
+      Fußzeile
+    </div>
+    <!-- Skripte -->
+    <script src="/jslib/mustache/mustache.min.js"></script>
+    <script src="/jslib/moment/moment-with-locales.min.js"></script>
+    <script src="/jslib/numeral/numeral.min.js"></script>    
+    <script src="js/app-menu.js"></script>
+    <script src="js/vorlagen.js"></script>
+    <script src="js/data.js"></script>
+    <script src="js/app.js"></script>
+    <script>
+      var app;
+      document.addEventListener('DOMContentLoaded', function () {
+        app = new AppVorlage();
+        app.init();
+      });
+    </script>
+  </body>
+</html>
diff --git a/web/ui2/js/app-menu.js b/web/ui2/js/app-menu.js
new file mode 100644
index 0000000..6a3b11e
--- /dev/null
+++ b/web/ui2/js/app-menu.js
@@ -0,0 +1,137 @@
+function AppMenu() {
+  var self = this;
+  var _app_menu_selector;
+  var _app_menu_mbreite;
+  var _app_menu_url_prefix = "";
+  var _app_menu_template;
+
+  /*
+   * die nachfolgenden Funktionen steuern das ein- und
+   * ausblenden des menues
+   */
+  this.init = function (url_prefix, mdesc, mtpl, mselector, mbreite) {
+    self._app_menu_selector = mselector;
+    self._app_menu_mbreite = mbreite;
+    var menu = document.querySelector(self._app_menu_selector);
+    menu.style.flexBasis = '0em';
+    self._app_menu_url_prefix = url_prefix;
+    /*
+      Die Menue-Vorlage wird einmal zu Beginn geladen und
+      waehrend dem Programmlauf immer wieder neu zum Rendern
+      einer dynamisch gelandenen Menuebeschreibung verwendet
+    */
+    var request = new XMLHttpRequest();
+    request.open("GET", mtpl);
+    request.addEventListener('load', function(event) {
+       if (request.status >= 200 && request.status < 300) {
+          self._app_menu_template = request.responseText;
+          Mustache.parse(self._app_menu_template);   // optional, speeds up future uses
+          self.app_menu_laden(mdesc);
+       } else {
+          console.warn(request.statusText, request.responseText);
+       }
+    });
+    request.send();
+  };
+
+  this.app_menu_do_toggle = function(elem) {
+    self.toggle();
+  };
+
+  this.toggle = function() {
+    var menuDiv = document.querySelector(self._app_menu_selector);
+    if(menuDiv.classList.contains('app-menu-open')) {
+      menuDiv.classList.remove('app-menu-open');
+      menuDiv.style.flexBasis = '0em';
+    } else {
+      menuDiv.classList.add('app-menu-open');
+      menuDiv.style.flexBasis = self._app_menu_mbreite;
+    }
+  };
+
+  /*
+   * ab hier Steuerung des Menueinhalts
+   */
+
+
+  /*
+   * Menuebeschreibung als JSON-Datei laden
+   * mdesc: der URL einer JSON-Datei mit einer Menuebeschreibung
+   * richtung: z.Zt. unbenutzt: Animationsrichtung
+   */
+  this.app_menu_laden = function(mdesc, richtung) {
+    var xmlhttp = new XMLHttpRequest();
+    var url = self._app_menu_url_prefix + mdesc;
+    xmlhttp.onreadystatechange = function() {
+      if (this.readyState == 4 && this.status == 200) {
+        self.app_menu_bauen(JSON.parse(this.responseText), richtung);
+      }
+    };
+    xmlhttp.open("GET", url, true);
+    xmlhttp.send();
+  };
+
+  /*
+    Aus einer Menuebeschreibung im JSON-Format mit Hilfe
+    von Mustache und der zu Beginn geladenen HTML-Vorlage
+    ein div-Element zusammenbauen, das als Menue eingeblendet
+    werden kann und dem Element _app_menu_selector hinzufuegen
+  */
+  this.app_menu_bauen = function(menuejs, richtung) {
+
+    // neues Menue als div-Element zusammensetzen
+    var menuDiv = document.createElement("div");
+    menuDiv.classList.add('app-menu-content');
+    menuDiv.style.position = 'relative';
+    menuDiv.innerHTML = Mustache.render(self._app_menu_template, menuejs);
+
+    // altes Menue loeschen
+    self.app_menu_remove_event_listener_multi('.smenu', 'click', self.app_menu_klick_herunter);
+    self.app_menu_remove_event_listener_multi('.bitem', 'click', self.app_menu_klick_herauf);
+    self.app_menu_remove_event_listener_multi('.mitem', 'click', self.app_menu_ausfuehren);
+    var menu = document.querySelector(self._app_menu_selector);
+    menu.innerHTML = '';
+
+    // neues Menue hinzufuegen
+    menu.append(menuDiv);
+    self.app_menu_add_event_listener_multi('.smenu', 'click', self.app_menu_klick_herunter);
+    self.app_menu_add_event_listener_multi('.bitem', 'click', self.app_menu_klick_herauf);
+    self.app_menu_add_event_listener_multi('.mitem', 'click', self.app_menu_ausfuehren);
+
+    menuDiv = document.querySelector('.app-menu-content');
+    menuDiv.classList.add('slidein-from-right');
+  };
+
+  this.app_menu_klick_herunter = function() {
+    self.app_menu_laden(this.getAttribute('data-verweis'), 'herunter');
+  };
+
+  this.app_menu_klick_herauf = function() {
+    self.app_menu_laden(this.getAttribute('data-verweis'), 'herauf');
+  };
+
+  this.app_menu_ausfuehren = function() {
+    var functionName = this.getAttribute('data-verweis');
+    eval(functionName + "(this)");
+  };
+
+  /* --- Helferlein ---*/
+  /*
+    sel - '.smenu'
+    evt - 'click' fuer onclick
+    func - der verweis auf die funktion
+  */
+  this.app_menu_remove_event_listener_multi = function(sel, evt, func) {
+    var elem = document.querySelectorAll(sel);
+    for (var index = 0; index < elem.length; index++) {
+      elem[index].removeEventListener(evt, func);
+    }
+  };
+
+  this.app_menu_add_event_listener_multi = function(sel, evt, func) {
+    var elem = document.querySelectorAll(sel);
+    for (var index = 0; index < elem.length; index++) {
+      elem[index].addEventListener(evt, func);
+    }
+  };
+}
diff --git a/web/ui2/js/app.js b/web/ui2/js/app.js
new file mode 100644
index 0000000..ad224ea
--- /dev/null
+++ b/web/ui2/js/app.js
@@ -0,0 +1,186 @@
+function AppVorlage() {
+  var self = this;
+  var appMenu;
+  var vorlagen;
+  var api;
+  var userid;
+  var pfad = '';
+  var loc;
+  var modus = 'kacheln';
+  var PERS_DIR = "Persoenlich";
+  var PUB_DIR = "Oeffentlich";
+  var DAV_DIR = "Austausch";
+  var BASE_DIR = "$basis";
+  var DATA_DIR = "$daten";
+  var WWW_DIR = "www";
+
+  this.datei_neuer_text = function () {
+    self.meldung_mit_timeout("Neuer Text", 1500);
+  };
+
+  /* Funktionen aus App-Vorlage */
+
+  this.init = function () {
+    self.vorlagen = new Vorlagen();
+    self.appMenu = new AppMenu();
+    self.appMenu.init(
+            "data/menu/",
+            "hauptmenue.json",
+            "data/tpl/app-menu.tpl",
+            ".west",
+            "8em");
+    document.querySelector('.hamburger').addEventListener('click', function (e) {
+      self.menue_umschalten();
+    });
+    self.um_get_login();
+    self.um_get_user_list();
+    self.loc = window.location.protocol + '//' + window.location.host;
+  };
+
+  this.login_zeigen = function() {
+    self.meldung_mit_timeout("Benutzer: " + self.userid, 1500);
+  };
+  
+  this.menue_umschalten = function () {
+    var ham = document.querySelector(".hamburger");
+    ham.classList.toggle("is-active"); // hamburger-icon umschalten
+    self.appMenu.toggle(); // menue oeffnen/schliessen
+  };
+
+  this.info_dialog_zeigen = function () {
+    self.dialog_laden_und_zeigen('data/tpl/dlg-info.tpl', '');
+    self.menue_umschalten();
+  };
+
+  this.seitenleiste_umschalten = function () {
+    var ostDiv = document.querySelector('.ost');
+    if (ostDiv.classList.contains('ost-open')) {
+      ostDiv.classList.remove('ost-open');
+      ostDiv.style.flexBasis = '0em';
+    } else {
+      ostDiv.classList.add('ost-open');
+      ostDiv.style.flexBasis = '6em';
+    }
+    self.menue_umschalten();
+  };
+
+  this.fusszeile_umschalten = function () {
+    var suedDiv = document.querySelector('.sued');
+    if (suedDiv.classList.contains('sued-open')) {
+      suedDiv.classList.remove('sued-open');
+      suedDiv.style.height = '0';
+    } else {
+      suedDiv.classList.add('sued-open');
+      suedDiv.style.height = '1.5em';
+    }
+    self.menue_umschalten();
+  };
+
+  this.meldung_mit_timeout = function (meldung, timeout) {
+    var s = document.querySelector('.sued');
+    s.textContent = meldung;
+    setTimeout(function () {
+      s.textContent = 'Bereit.';
+      setTimeout(function () {
+        var suedDiv = document.querySelector('.sued');
+        if (suedDiv.classList.contains('sued-open')) {
+          suedDiv.classList.remove('sued-open');
+          suedDiv.style.height = '0';
+        }
+      }, 500);
+    }, timeout);
+  };
+
+  /* Dialog-Funktionen */
+
+  /*
+   Einen Dialog aus Vorlagen erzeugen
+   
+   vurl - URL zur Dialogvorlage
+   msgTpl - URL mit einer Vorlage eines Mitteilungstextes (optional)
+   */
+  this.dialog_laden_und_zeigen = function (vurl, msgTpl) {
+    if (msgTpl !== '') {
+      fetch(msgTpl)
+              .then(data => {
+                // Handle data
+                self.dialog_zeigen(vurl, data);
+              }).catch(error => {
+        // Handle error
+      });
+    } else {
+      self.dialog_zeigen(vurl, '');
+    }
+  };
+
+  this.dialog_zeigen = function (vurl, inhalt) {
+    var dlg = document.querySelector(".dialog");
+    self.vorlagen.html_erzeugen(
+            vurl,
+            inhalt,
+            function (html) {
+              //dlg.html(html);
+              dlg.style.height = '5em';
+              dlg.innerHTML = html;
+              document.querySelector('.close-btn').addEventListener('click', self.dialog_schliessen);
+              //dlg.slideDown(300);
+            });
+  };
+
+  this.dialog_schliessen = function () {
+    document.querySelector('.close-btn').removeEventListener('click', self.dialog_schliessen);
+    //$('.dialog').slideUp(300);
+    var dlg = document.querySelector('.dialog');
+    //dlg.style.display = "none";
+    dlg.style.height = '0';
+    dlg.innerHTML = '';
+  };
+
+  /* API functions */
+  
+  this.um_get_user_list = function() {
+    var m = 'getUserNameList';
+    var u = '../svc/' + m;
+    self.fm_get(u, "json", function (antwort) {
+      var elem = document.getElementById('nutzer');
+      elem.textContent = antwort;
+    });
+  }
+  
+
+  /* -------- An- und Abmelden ------------- */
+
+  this.um_get_login = function() {
+    var m = '?c=de.uhilger.um.pub.SessionManager&m=getSessionUser';
+    var u = '../pub' + m;
+    self.fm_get(u, "text", function (resp) {
+      self.userid = resp;
+      self.login_zeigen();
+      //document.querySelector("#userMenu").textContent = resp;
+    });
+  };
+
+  this.um_logout = function() {
+    var m = '?c=de.uhilger.um.pub.SessionManager&m=expireSession';
+    var u = '../pub' + m;
+    self.fm_get(u, "text", function (resp) {
+      //$('#userMenu').text('nicht angemeldet');
+      window.location.href = '../logout.html';
+    });
+  };
+
+  /* -------- ajax helper functions ----------- */
+
+  this.fm_get = function (u, dtype, scallback) {    
+    var xmlhttp = new XMLHttpRequest();
+    var url = u;
+    xmlhttp.onreadystatechange = function() {
+      if (this.readyState == 4 && this.status == 200) {
+        scallback(this.responseText);
+      }
+    };
+    xmlhttp.open("GET", url, true);
+    xmlhttp.send();
+  };
+
+}
diff --git a/web/ui2/js/data.js b/web/ui2/js/data.js
new file mode 100644
index 0000000..821ba31
--- /dev/null
+++ b/web/ui2/js/data.js
@@ -0,0 +1,148 @@
+/*
+ Dateiverwaltung - File management in your browser
+ Copyright (C) 2017 Ulrich Hilger, http://uhilger.de
+ 
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+
+/*
+ * In data.js finden sich die Objekte vom Browser-Client 
+ * der Dateiverwaltung
+ */
+
+
+
+/* ----- Objekte ----- */
+
+function IssueList(il) {
+  this.issues = il;
+}
+
+function CompilerIssue(sn, ms, ki, ln) {
+  var self = this;
+  this.sourceName = sn;
+  this.message = ms;
+  this.kind = ki;
+  this.lineNumber = ln;
+}
+
+function FileList(fl) {
+  this.files = fl;
+}
+
+function FileRef(obj) {
+  var self = this;
+  this.fr = obj;
+  this.fnx;
+  this.fext = '';
+
+  this.typeClass = function () {
+    if (modus == 'kacheln') {
+      if (self.fr.isDirectory) {
+        return 'fa-folder ordner';
+      } else {
+        return 'fa-file datei';
+      }
+    } else {
+      if (self.fr.isDirectory) {
+        return 'fa-folder ordner';
+      } else {
+        return 'fa-file-o datei';
+      }
+    }
+  };
+
+  this.mini = function () {
+    var miniatur = false;
+    var namen = self.fr.absolutePath.split('/');
+    if (namen.length > 0) {
+      self.fnx = decodeURIComponent(namen[namen.length - 1]);
+    } else {
+      self.fnx = decodeURIComponent(self.fr.absolutePath);
+    }
+    if (self.fnx.indexOf('.jpg') > -1 || self.fnx.indexOf('.png') > -1 || 
+            self.fnx.indexOf('.gif') > -1 || self.fnx.indexOf('.jpeg') > -1) {
+      miniatur = true;
+    }
+    return miniatur;
+  };
+
+  this.dia = function () {
+    return fm_slideshow;
+  };
+
+  this.miniurl = function () {
+    // var userid = $('#userMenu').text();
+    if (self.fext === '') {
+      //self.fext = '';
+      var dotpos = self.fnx.indexOf('.');
+      if (dotpos > -1) {
+        var fny = self.fnx;
+        self.fnx = self.fnx.substring(0, dotpos);
+        self.fext = fny.substr(dotpos);
+      }
+    }
+    var path = fm_get_path(app.userid);
+    var imgurl = loc + path + '/' + self.fnx + '_tn' + self.fext;
+    return imgurl;
+
+  };
+
+  this.bildurl = function () {
+    // var userid = $('#userMenu').text();
+    if (self.fext === '') {
+      //self.fext = '';
+      var dotpos = self.fnx.indexOf('.');
+      if (dotpos > -1) {
+        var fny = self.fnx;
+        self.fnx = self.fnx.substring(0, dotpos);
+        self.fext = fny.substr(dotpos);
+      }
+    }
+    var path = fm_get_path(app.userid);
+    var imgurl = loc + path + '/' + self.fnx + self.fext;
+    return imgurl;
+  };
+
+  this.fileName = function () {
+
+    var namen = self.fr.absolutePath.split('/');
+    if (namen.length > 0) {
+      return decodeURIComponent(namen[namen.length - 1]);
+    } else {
+      return decodeURIComponent(self.fr.absolutePath);
+    }
+
+  };
+
+  this.fileDate = function () {
+    return moment(self.fr.lastModified).format("YYYY-MM-DD-hh-mm-ss-SSS");
+  };
+
+  this.fileSize = function () {
+    return numeral(self.fr.length).format("0.00 b");
+  };
+}
+
+function BcrFiles(fl) {
+  this.files = fl;
+}
+
+function BcrFile(rp, n) {
+  this.relPath = rp;
+  this.fName = n;
+}
+
diff --git a/web/ui2/js/vorlagen.js b/web/ui2/js/vorlagen.js
new file mode 100644
index 0000000..d76cd94
--- /dev/null
+++ b/web/ui2/js/vorlagen.js
@@ -0,0 +1,66 @@
+
+
+function Vorlagen() {
+  var self = this;
+  this.cache = {}; // mustache templates
+
+  /*
+    Das HTML erzeugen, das entsteht, wenn eine Vorlage mit Inhalt
+    gefüllt wird
+
+    Das Füllen erfolgt asynchron, d.h. der Programmlauf geht nach dem
+    Aufruf weiter ohne auf das Laden und Füllen der Vorlage zu warten.
+    Das fertige HTML wird der Callback-Funktion übergeben
+    sobald die Vorlage geladen und gefüllt ist, unabhängig davon, wo der
+    Programmlauf zu diesem Zeitpunkt mittlerweile ist.
+
+    vurl - URL zur Vorlagendatei
+    inhalt - die JSON-Struktur, deren Inhalt in die
+              Vorlage gefüllt werden soll
+    cb - Callback-Funktion, die gerufen wird, wenn die Vorlage gefüllt ist.
+          Dieser Callback-Funktion wird das fertige HTML übergeben
+  */
+  this.html_erzeugen = function(vurl, inhalt, cb) {
+    var vorlage = self.cache[vurl];
+    if(vorlage === undefined) {
+      self.vorlage_laden_und_fuellen(vurl, inhalt, cb);
+    } else {
+      self.vorlage_fuellen(vurl, inhalt, cb);
+    }
+  };
+
+  this.vorlage_fuellen = function(vurl, inhalt, cb) {
+    cb(Mustache.render(self.cache[vurl], inhalt));
+  };
+
+  /*
+    Eine Vorlage vom Server in den lokalen Speicher laden
+    vurl - der URL unter dem die Vorlage zu finden ist
+    inhalt - die JSON-Struktur, deren Inhalt in die
+              Vorlage gefüllt werden soll
+    cb - callback: Diese Funktion wird gerufen, wenn die Vorlage mit dem
+            Inhalt gefüllt ist
+  */
+  this.vorlage_laden_und_fuellen = function(vurl, inhalt, cb) {
+    /*
+    $.ajax({
+      url: vurl,
+      type: "GET",
+      dataType : "text"
+    }).done(function( vorlage ) {
+      self.cache[vurl] = vorlage;
+      self.vorlage_fuellen(vurl, inhalt, cb);
+    });
+    */
+    var xmlhttp = new XMLHttpRequest();
+    xmlhttp.onreadystatechange = function() {
+      if (this.readyState == 4 && this.status == 200) {
+        self.cache[vurl] = this.responseText;
+        self.vorlage_fuellen(vurl, inhalt, cb);
+      }
+    };
+    xmlhttp.open("GET", vurl, true);
+    xmlhttp.send();
+  };
+
+}
diff --git a/web/ui2/stile.css b/web/ui2/stile.css
new file mode 100644
index 0000000..e3ee310
--- /dev/null
+++ b/web/ui2/stile.css
@@ -0,0 +1,322 @@
+/* 
+    Created on : 24.01.2020, 09:08:45
+    Author     : ulrich
+*/
+
+
+
+
+
+
+/* aus App-Vorlage */
+
+html, body {
+  margin: 0;
+  padding: 0;
+  height: 100%; /* Anmerkung 2 */
+  font-size: larger;
+  font-family: 'Roboto Condensed';
+}
+body {
+  min-height: 0; /* Anmerkung 1 */
+  display: flex;
+  flex-flow: column;
+}
+.inhalt {
+  display: flex;
+  flex-flow: row;
+  height: 100%; /* Anmerkung 2 */
+  min-height: 0; /* Anmerkung 1 */
+  background-color: #ededed;
+  overflow: hidden;
+}
+.nord {
+  background-color: black;
+  display: flex;
+  flex-flow: row;
+  height: 2em;
+  align-items: center;
+}
+.sued {
+  height: 1.5em;
+  overflow: hidden;
+  transition: all 0.3s ease-in;
+  background-color: lightgray;
+}
+.west {
+  flex-grow: 0;
+  flex-shrink: 0;
+  flex-basis: 4em;
+  background-color: white;
+  transition: all 0.3s ease-in;
+  overflow: hidden;
+  white-space: nowrap;
+}
+.ost {
+  flex-grow: 0;
+  flex-shrink: 0;
+  flex-basis: 6em;
+  transition: all 0.3s ease-in;
+  background-color: antiquewhite;
+  overflow: hidden;
+}
+.zentrum-behaelter {
+  display: flex;
+  flex-flow: column;
+  /* background-color: #eaeaea; */
+  width: 100%;
+}
+
+.zentrum {
+  width: 100%;
+  height: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
+  -webkit-overflow-scrolling: touch;
+}
+
+.zentraler-inhalt {
+  padding: 0.5em;
+}
+
+/*
+  Anmerkungen:
+  1.) min.height: 0 fuer body und inhalt ist gegen einen Bug, vgl.
+      http://stackoverflow.com/questions/33859811/understanding-flexbox-and-overflowauto
+  2.) height 100% fuer html, body und inhalt sorgt dafuer, dass sich alles
+      immer ueber das gesamte Browserfenster ausdehnt.
+*/
+
+.app-titel {
+  margin-left: 0.6em;
+  color: white;
+}
+
+.pointer-cursor {
+  cursor: pointer;
+}
+
+.breadcrumb {
+  background-color: beige;
+  padding: 0.2em;
+  font-size: medium;
+}
+
+.dialog {
+  position: relative;
+  /* height: 0.1em; */
+  transition: all 0.3s ease-in;
+}
+
+.dlg-behaelter {
+  line-height: 1.6;
+  padding: 0.4em;
+}
+
+.dlg-info {
+  background-color: #dcf2fb; /* blau */ 
+  padding: 0.4em;
+}
+
+/*
+  Close Button
+
+  <div>
+    <span class="close-btn">&#10006;</span>
+  </div>
+*/
+
+.close-btn {
+  position: absolute;
+  top: 0px;
+  right: 0.4em;
+  margin: 0;
+  padding: 0;
+  font-size: 1.3em;
+  color: #b8b8b8;
+}
+
+/* für app-menu */
+
+
+.app-menu {
+  margin: 0;
+  padding: 0;
+}
+
+.app-menu-kopf {
+  text-align: center;
+}
+
+ul.app-menu {
+	list-style: none;
+}
+
+.app-menu-item-back {
+  margin-bottom: 0.3em;
+  cursor: pointer;
+}
+
+.app-menu-item {
+  text-align: right;
+  cursor: pointer;
+}
+
+.app-menu-item-submark {
+  color: transparent;
+  cursor: pointer;
+}
+
+/*
+  Das div-Element, das das Menue aufnimmt erhaelt
+  die Klasse app-menu-content
+*/
+.app-menu-content {
+  overflow: hidden;
+}
+
+/* für Hamburger Icon */
+
+.hamburger {
+  display: inline-block;
+  cursor: pointer;
+  transition-property: opacity, filter;
+  transition-duration: 0.15s;
+  transition-timing-function: linear;
+  font: inherit;
+  color: inherit;
+  text-transform: none;
+  background-color: transparent;
+  border: 0;
+  margin: 0;
+  overflow: visible;
+}
+
+.hamburger:hover {
+  opacity: 0.7;
+}
+
+.hamburger-box {
+  width: 40px;
+  height: 24px;
+  display: inline-block;
+  position: relative;
+}
+
+.hamburger-inner {
+  display: block;
+  top: 50%;
+  margin: 0;
+}
+
+.hamburger-inner, .hamburger-inner::before, .hamburger-inner::after {
+  width: 30px;
+  height: 4px;
+  background-color: white; /* #000; */
+  border-radius: 4px;
+  position: absolute;
+  transition-property: transform;
+  transition-duration: 0.15s;
+  transition-timing-function: ease;
+}
+
+.hamburger-inner::before, .hamburger-inner::after {
+  content: "";
+  display: block;
+}
+
+.hamburger-inner::before {
+  top: -10px;
+}
+
+.hamburger-inner::after {
+  bottom: -10px;
+}
+
+/*
+ * Elastic
+ */
+.hamburger--elastic .hamburger-inner {
+  top: 2px;
+  transition-duration: 0.275s;
+  transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
+}
+
+.hamburger--elastic .hamburger-inner::before {
+  top: 10px;
+  transition: opacity 0.125s 0.275s ease;
+}
+
+.hamburger--elastic .hamburger-inner::after {
+  top: 20px;
+  transition: transform 0.275s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+}
+
+.hamburger--elastic.is-active .hamburger-inner {
+  transform: translate3d(0, 10px, 0) rotate(135deg);
+  transition-delay: 0.075s;
+}
+
+.hamburger--elastic.is-active .hamburger-inner::before {
+  transition-delay: 0s;
+  opacity: 0;
+}
+
+.hamburger--elastic.is-active .hamburger-inner::after {
+  transform: translate3d(0, -20px, 0) rotate(-270deg);
+  transition-delay: 0.075s;
+}
+
+/* Font für Piktogramme mit Fontello aus FontAwesome erzeugt */
+
+@font-face {
+  font-family: 'pikto';
+  src: url('font/pikto.ttf?37040783') format('truetype');
+  font-weight: normal;
+  font-style: normal;
+}
+ 
+ [class^="icon-"]:before, [class*=" icon-"]:before {
+  font-family: "pikto";
+  font-style: normal;
+  font-weight: normal;
+  speak: none;
+ 
+  display: inline-block;
+  text-decoration: inherit;
+  width: 1em;
+  margin-right: .2em;
+  text-align: center;
+  /* opacity: .8; */
+ 
+  /* For safety - reset parent styles, that can break glyph codes*/
+  font-variant: normal;
+  text-transform: none;
+ 
+  /* fix buttons height, for twitter bootstrap */
+  line-height: 1em;
+ 
+  /* Animation center compensation - margins should be symmetric */
+  /* remove if not needed */
+  margin-left: .2em;
+ 
+  /* you can be more comfortable with increased icons size */
+  /* font-size: 120%; */
+ 
+  /* Font smoothing. That was taken from TWBS */
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+ 
+  /* Uncomment for 3D effect */
+  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
+}
+ 
+.icon-folder:before { content: '\e800'; } /* '' */
+.icon-folder-open:before { content: '\e801'; } /* '' */
+.icon-th-large:before { content: '\e802'; } /* '' */
+.icon-th-list:before { content: '\e803'; } /* '' */
+.icon-doc-text:before { content: '\f0f6'; } /* '' */
+.icon-folder-empty:before { content: '\f114'; } /* '' */
+.icon-folder-open-empty:before { content: '\f115'; } /* '' */
+.icon-doc-inv:before { content: '\f15b'; } /* '' */
+.icon-doc-text-inv:before { content: '\f15c'; } /* '' */
\ No newline at end of file

--
Gitblit v1.9.3