Persoenliche Mediazentrale
ulrich
2021-04-11 630b44fd74991e2757b2870eb76abbf3ad0f616f
commit | author | age
b379f5 1 function Mediazentrale() {
cfa858 2   var self = this;
U 3   var appMenu;
4   var cache; // mustache templates
86bbf7 5   var ortPfad;
U 6   var mediaPfad;
e60cff 7   var katUrl;
U 8   var selTitel;
78d707 9   var katName;
f45e20 10
U 11   this.init = function () {
12     self.mediaPfad = '/';
13     self.ortPfad = '/';
14     self.cache = new Array();
15     self.appMenu = new AppMenu();
16     self.appMenu.init(
17             "data/menu/",
18             "hauptmenue.json",
78d707 19             "data/tpl/app-menu.txt",
f45e20 20             ".west",
U 21             "8em");
22
23     document.querySelector('.hamburger').addEventListener('click', function (e) {
24       self.menue_umschalten();
25     });
26     
27     self.addEvtListener('#mi-katalog', 'click', self.media_liste);
28     self.addEvtListener('#mi-orte', 'click', self.ablageort_liste);
29     self.addEvtListener('#mi-prefs', 'click', self.prefs_liste);
30     self.addEvtListener('#mi-player', 'click', self.abspieler_liste);
8d7d35 31     self.addEvtListener('#mi-listen', 'click', self.abspielliste_liste);
U 32     self.addEvtListener('#mi-list', 'click', self.titel_liste);
f45e20 33     
U 34     self.fusszeile_umschalten();
35     self.seitenleiste_umschalten();
36     self.dialog_unten_zeigen();
37   };
38   
8d7d35 39   /* ---------------- Entitaets-Listen ----------------- */
U 40
86bbf7 41   // auf der obersten Ebene werden die Kataloge angezeigt,
U 42   // darunter der Inhalt des aktuellen Pfades
43   this.media_liste = function() {
78d707 44     self.reset_top_buttons(); 
095119 45     //console.log("ortPfad: " + self.ortPfad + ", mediaPfad: " + self.mediaPfad);
78d707 46     document.querySelector('.bereich-name').textContent = '';    
86bbf7 47     if(self.ortPfad === '/') {
78d707 48       var bb = document.querySelector('.breadcrumb-behaelter');
U 49       bb.textContent = "Kataloge";
86bbf7 50       // Kataloge listen
f45e20 51       self.http_get('../api/store/Ablageort/liste/', function (responseText) {
8d7d35 52         //document.querySelector('#top-up-btn').removeEventListener('click', self.media_liste_herauf);
78d707 53         self.vorlage_laden_und_fuellen("data/tpl/katalog_root_liste.txt", JSON.parse(responseText), function (html) {
86bbf7 54           document.querySelector(".zentraler-inhalt").innerHTML = html;
U 55           self.addEvtListener('.entity-eintrag', 'click', function (event) {
56             var t = event.target;
78d707 57             self.katName = t.textContent;
86bbf7 58             self.http_get('../api/store/Ablageort/' + t.textContent, function(responseText) {
U 59               var ablageort = JSON.parse(responseText);
60               self.ortPfad = ablageort.url;
61               self.media_liste();
62             });
63           });
64         });
65       });
66     } else {
78d707 67       var bb = document.querySelector('.breadcrumb-behaelter');
U 68       var brPfad = self.katName + self.mediaPfad;
69       var breadcrumbs = brPfad.split('/');
70       var brLinks = "";
71       var brLinkPfad = "";
72       for(var index = 0; index < breadcrumbs.length; index++) {
73         // <a class="breadcrumb-link" href="#">breadcrumbs[index]</a>
74         if(index === 0) {
75           brLinkPfad = '/';
76         } else {
77           brLinkPfad = brLinkPfad + '/' + breadcrumbs[index];
78         }
79         brLinks = brLinks + "<a brlink='" + brLinkPfad + "' class='breadcrumb-link' href='#'>" + breadcrumbs[index] + "</a>";
80         //console.log('   breadcrumbs[' + index + ']: ' + breadcrumbs[index]);
81       }
82       bb.innerHTML = brLinks;
83       self.addEvtListener('.breadcrumb-link', 'click', function(event) {
095119 84         //console.log(event.target.attributes.brlink.nodeValue);
78d707 85         var neuerPfad = event.target.attributes.brlink.nodeValue;
U 86         self.mediaPfad = neuerPfad;
87         self.media_liste();
88       });
3271f1 89       var url = '..' + self.ortPfad + self.mediaPfad;
U 90       if(!url.endsWith('/')) {
91         url = url + '/';
92       }
93       self.http_get(url, function(responseText) {
78d707 94         self.vorlage_laden_und_fuellen("data/tpl/katalog_inhalt_liste.txt", JSON.parse(responseText), function (html) {
86bbf7 95           document.querySelector(".zentraler-inhalt").innerHTML = html;
U 96           self.addEvtListener('.entity-eintrag', 'click', function (event) {
97             var t = event.target;
3271f1 98             var tx = t.textContent;
86bbf7 99             if(t.classList.contains("entity-typ-folder")) {
3271f1 100               if(self.mediaPfad.endsWith('/')) {
U 101                 self.mediaPfad = self.mediaPfad + tx;                
102               } else {
103                 self.mediaPfad = self.mediaPfad + '/' + tx;
104               }
86bbf7 105               self.media_liste();
U 106             } else {
37eadf 107               if(t.classList.contains('selected')) {
78d707 108                 t.classList.add('added-to-playlist');
095119 109                 self.titelDazu();
37eadf 110               } else {
U 111                 self.removeClassMulti('selected');
112                 t.classList.add('selected');
113               }
e60cff 114               //self.selTitel = new Titel(t.textContent, self.ortPfad);       
86bbf7 115             }
U 116           });
8d7d35 117           self.addEvtListener('#top-up-btn', 'click', function(event) {
86bbf7 118             if(self.mediaPfad === '/') {
U 119               self.ortPfad = '/';              
120             } else {
121               var pos = self.mediaPfad.lastIndexOf('/');
3271f1 122               var parent;
U 123               if(pos > 1) {
124                 parent = self.mediaPfad.substring(0, pos);
125               } else {
126                 parent = '/';
127               }
86bbf7 128               self.mediaPfad = parent;
U 129             }
130             self.media_liste();
8d7d35 131           });
86bbf7 132         });
U 133       });
134     }
e60cff 135   };
245ac1 136   
a43e1a 137   this.ablageort_liste = function() {
78d707 138     self.entitaet_liste('Kataloge','../api/store/Ablageort/liste/', 
U 139       "data/tpl/ablageort_liste.txt", '../api/store/Ablageort/', 
e44ed0 140       "self.ablageort_form", function(responseText) {
U 141         var ablageort = JSON.parse(responseText);
142         self.ablageort_form(ablageort);
143       });
cf6509 144   };
U 145
146   this.prefs_liste = function() {
50e53e 147     self.entitaet_liste('Einstellungen','../api/store/Einstellung/liste/', 
78d707 148       "data/tpl/einstellung_liste.txt", '../api/store/Einstellung/', 
e44ed0 149       "self.prefs_form", function(responseText) {
U 150         var einstellung = JSON.parse(responseText);
151         self.prefs_form(einstellung);
152       });
cf6509 153   };
U 154
3d4bca 155   this.abspieler_liste = function() {
50e53e 156     self.entitaet_liste('Abspieler','../api/store/Abspieler/liste/', 
78d707 157       "data/tpl/abspieler_liste.txt", '../api/store/Abspieler/', 
e44ed0 158       "self.abspieler_form", function(responseText) {
U 159         var abspieler = JSON.parse(responseText);
160         self.abspieler_form(abspieler);
161       });
8d7d35 162   };
U 163   
164   this.abspielliste_liste = function() {
50e53e 165     self.entitaet_liste('Abspielliste','../api/store/Abspielliste/liste/', 
78d707 166       "data/tpl/abspielliste_liste.txt", '../api/store/Abspielliste/', 
e44ed0 167       "self.abspielliste_form", function(responseText) {
095119 168         //console.log("responseTest: '" + responseText + "'");
e44ed0 169         var abspielliste = JSON.parse(responseText);
U 170         self.abspielliste_form(abspielliste);
171       });
8d7d35 172   };
U 173   
c7030d 174   /* -------------------- Entitaets-Formulare ------------------ */  
8d7d35 175   
U 176   this.abspielliste_form = function(al) {
50e53e 177     self.entitaet_form('Abspielliste', al, al.name,
78d707 178       "data/tpl/form_abspielliste.txt", '../api/store/Abspielliste/',
9865bd 179       '#abspielliste-name', function(event) {
095119 180           if(event !== undefined) {
U 181             event.preventDefault();
182           }
c7030d 183           self.abspielliste_auswahl_fuellen();
U 184           self.abspielliste_liste();
185     });
3d4bca 186   };
71def1 187   
3d4bca 188   this.abspieler_form = function(pl) {
50e53e 189     self.entitaet_form('Abspieler', pl, pl.key,
78d707 190       "data/tpl/form_abspieler.txt", '../api/store/Abspieler/',
c7030d 191       '#abspieler-name', function() { 
U 192           self.abspieler_auswahl_fuellen();
193           self.abspieler_liste();
194     });
71def1 195   };
U 196
cf6509 197   this.prefs_form = function(k) {
78d707 198     self.entitaet_form('Einstellung', k, k.key,
U 199       "data/tpl/form_einstellung.txt", '../api/store/Einstellung/',
c7030d 200       '#einstellung-key', function() { 
U 201           self.prefs_liste();
202     });
a43e1a 203   };
cfa858 204
90f5d4 205   /* 
U 206    * Ablageort-Formular anzeigen
207    * 
208    * {"name":"Katalog 2","ort":"/home/ulrich/Videos","url":"/media/kat2"}: 
209    * 
210    * @param {type} ablageort  der Ablageort, der bearbeitet werden soll, leer fuer neuen Ort
211    * @returns {undefined} kein Rueckgabewert
212    */
213   this.ablageort_form = function(ort) {
78d707 214     self.entitaet_form('Katalog', ort, ort.name,
U 215       "data/tpl/form_ablageort.txt", '../api/store/Ablageort/',
c7030d 216       '#ablageort-name', function() { 
U 217         self.ablageort_liste();
218     });
b379f5 219   };
48f8f9 220   
748b6f 221   /* ------------------------------- UI-Dynamik ----------------------- */
48f8f9 222   
748b6f 223   self.reset_top_buttons = function() {
78d707 224     self.vorlage_laden_und_fuellen("data/tpl/top_btns.txt", '', function (html) {
748b6f 225       document.querySelector(".top-btns").innerHTML = html;
U 226     });
227   };
228   
229   this.abspieler_auswahl_fuellen = function() {
b56bb3 230     self.http_get('../api/store/Abspieler/liste/', function (responseText) {
78d707 231       self.vorlage_laden_und_fuellen("data/tpl/abs_sel.txt", JSON.parse(responseText), function (html) {
748b6f 232         document.querySelector(".abs-sel").innerHTML = html;
U 233       });    
234     });
235   };
236
237   this.abspielliste_auswahl_fuellen = function() {
238     self.http_get('../api/store/Abspielliste/', function (responseText) {
78d707 239       self.vorlage_laden_und_fuellen("data/tpl/pl_sel.txt", JSON.parse(responseText), function (html) {
748b6f 240         document.querySelector(".pl-sel").innerHTML = html;
b56bb3 241         self.addEvtListener('#playlist', 'change', function() {
U 242           self.titel_liste();
243         });
748b6f 244       });    
U 245     });
246   };
247   
248   /* Unterer Einblendbereich */
249   
250   this.dialog_unten_zeigen = function() {
78d707 251     self.vorlage_laden_und_fuellen("data/tpl/ctrl.txt", "", function (html) {
748b6f 252       var dlg = document.querySelector(".dialog-unten");
U 253       dlg.style.height = '4.5em';
254       dlg.innerHTML = html;
255       self.abspieler_auswahl_fuellen();
256       self.abspielliste_auswahl_fuellen();
095119 257       self.addEvtListener('#dazu-btn', 'click', self.titelDazu);
b56bb3 258       self.addEvtListener('#play-btn', 'click', self.play);
9e14ef 259       self.addEvtListener('#stop-btn', 'click', function() {
U 260         self.kommando('stop');
261       });
262       self.addEvtListener('#pause-btn', 'click', function() {
263         self.kommando('pause');
264       });
265       self.addEvtListener('#weiter-btn', 'click', function() {
266         self.kommando('weiter');
267       });
268       
269 /*
270     <button class="ctrl-btn ctrl-item" id="hier-btn" title="hier spielen"><i class="icon-tablet"></i></button>
271  */      
272       
095119 273       self.addEvtListener('#weg-btn', 'click', self.titelWeg);
U 274       self.addEvtListener('#leeren-btn', 'click', self.alleTitelEntfernen);
748b6f 275       self.media_liste();
U 276     });
277   };
278   
279   /* Titel einer Abspielliste */
280   
281   this.titel_liste = function() {
282     self.reset_top_buttons();
283     var plname = document.querySelector('#playlist').value;
78d707 284     document.querySelector('.bereich-name').textContent = 'Abspielliste ' + plname;
U 285     var bb = document.querySelector('.breadcrumb-behaelter');
286     bb.textContent = "";
748b6f 287     self.http_get('../api/alist/' + plname, function (responseText) {
78d707 288       self.vorlage_laden_und_fuellen("data/tpl/titel_liste.txt", JSON.parse(responseText), function (html) {
748b6f 289         document.querySelector(".zentraler-inhalt").innerHTML = html;
U 290         self.addEvtListener('.entity-eintrag', 'click', function (event) {
291           var t = event.target;
292           self.removeClassMulti('selected');
293           t.classList.add('selected');
294         });
295       });
296     });
297   };  
298   
b56bb3 299   /* ------------- Media-Steuerung ------------------------- */
U 300   
301   this.play = function() {
302     var abs = document.querySelector('#abspieler').value;
303     var lst = document.querySelector('#playlist').value;
304     console.log(
305       "play playlist.value: " + document.querySelector('#playlist').value + 
306       ", abspieler.value: " + document.querySelector('#abspieler').value);
307     self.http_get('../api/strg/' + abs + '/play/liste/' + lst, function(responseText) {
308       self.meldung_mit_timeout(responseText, 1500);
309     });
095119 310   };
U 311   
9e14ef 312   this.kommando = function(kommando) {
U 313     var abs = document.querySelector('#abspieler').value;
314     self.http_get('../api/strg/' + abs + '/' + kommando, function(responseText) {
315       self.meldung_mit_timeout(responseText, 1500);
316     });
317   };
318     
095119 319   /* ------------- Verwaltungsfunktionen Abspielliste -------------------- */
U 320   
321   self.alleTitelEntfernen = function() {
322     var plname = document.querySelector('#playlist').value;
323     self.http_delete('../api/alist/' + plname + '/alle', '', function(responseText) {
324       // DELETE    http://localhost:9090/mz/api/alist/liste1/0
325       //self.meldung_mit_timeout(responseText, 1500);
326       self.titel_liste();
327     });
328   };
329   
330   this.titelDazu = function() {
331     var elem = document.querySelector(".selected");
332     //var titelName = elem.textContent;
333     var titelName = elem.attributes.dateiName.nodeValue;
334     var album = elem.attributes.album.nodeValue;
335     var interpret = elem.attributes.interpret.nodeValue;
336     var anzName = elem.attributes.titelAnzName.nodeValue;
337     var titel;
338     if(self.mediaPfad.endsWith('/')) {
339       titel = new Titel(titelName, self.mediaPfad, self.ortPfad, interpret, anzName, album);
340     } else {
341       titel = new Titel(titelName, self.mediaPfad + '/', self.ortPfad, interpret, anzName, album);
342     }
343     var plname = document.querySelector('#playlist').value;
344     self.http_put('../api/alist/' + plname, JSON.stringify(titel), function(responseText) {
345       //self.meldung_mit_timeout(responseText, 1500);
346     });
347   };  
348   
349   this.titelWeg = function() {
350     var elem = document.querySelector(".selected");
351     var parentElem = elem.parentNode;
352     //console.log("elem: " + elem.nodeName + ", parent: " + parentElem.nodeName + ", len: " + parentElem.childNodes.length);
353     var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente
354     //console.log("liElems.anz: " + liElems.length);
355     var gefunden = false;
356     for(var i = 0; i < liElems.length && !gefunden; i++) {
357       //console.log(liElems.item(i).textContent);
358       if(liElems.item(i).classList.contains("selected")) {
359         gefunden = true;
360         var index = i;
361         //console.log(elem.textContent + ' hat Index ' + i);
362       }
363     }
364     // /mz/api/alist/[pl-name]/[nr] 
365     var plname = document.querySelector('#playlist').value;
366     self.http_delete('../api/alist/' + plname + '/' + index,'', function(responseText) {
367       // DELETE    http://localhost:9090/mz/api/alist/liste1/0
368       //self.meldung_mit_timeout(responseText, 1500);
369       self.titel_liste();
370     });
371     
b56bb3 372   };
U 373   
748b6f 374   /* ------------- Helfer fuer Entitaets-Formulare ----------------------- */
14638b 375   
U 376   /*
377    * url: '../api/store/Ablageort/liste/'
78d707 378    * tpl: "data/tpl/ablageort_liste.txt"
14638b 379    * storeUrl: '../api/store/Ablageort/'
U 380    * formFunc: "self.ablageort_form"
381    * cb: etwas wie
382    *   function(responseText){
383    *     var ablageort = JSON.parse(responseText);
384    *     self.ablageort_form(ablageort);
385    *   });
386    */
50e53e 387   this.entitaet_liste = function(bname, listUrl, tpl, storeUrl, formFunc, cb) {
14638b 388     self.reset_top_buttons();
50e53e 389     document.querySelector('.bereich-name').textContent = bname;
78d707 390     var bb = document.querySelector('.breadcrumb-behaelter');
U 391     bb.textContent = "";
14638b 392     self.http_get(listUrl, function (responseText) {
U 393       self.vorlage_laden_und_fuellen(tpl, JSON.parse(responseText), function (html) {
394         document.querySelector(".zentraler-inhalt").innerHTML = html;
395         self.addEvtListener('.entity-eintrag', 'click', function (event) {
396           var t = event.target;
397           self.http_get(storeUrl + t.textContent, cb);
398         });
399         //self.addEvtListener('#neu-btn', 'click', function (event) {
400         self.addEvtListener('#top-neu-btn', 'click', function(event) {
401           eval(formFunc + "(this)");
402         });        
403       });
404     });
405   };  
748b6f 406       
48f8f9 407   /*
c7030d 408    * dat: gefuelltes Datenobjekt bei Aenderung
U 409    * key: der alte schluesselbegriff bei Aenderung (z.B. al.name)
78d707 410    * tpl: "data/tpl/form_abspielliste.txt"
c7030d 411    * url: '../api/store/Abspielliste/'
U 412    * selector: '#abspielliste-name'
413    * cbOk: etwas wie
414    *    function() {
415    *       self.abspielliste_auswahl_fuellen();
416    *       self.abspielliste_liste();
417    *     });
418    * delSelector: '#abspielliste-name'
419    * cbDel: etwas wie
420    *    function() {
421    *       self.abspielliste_auswahl_fuellen();
422    *       self.abspielliste_liste();
423    *     });
424    */
425
50e53e 426   this.entitaet_form = function(bname, dat, key, tpl, url, selector, cb) {
U 427     document.querySelector('.bereich-name').textContent = bname;
c7030d 428     self.vorlage_laden_und_fuellen(tpl, dat, function (html) {
U 429       document.querySelector(".zentraler-inhalt").innerHTML = html;
430       const form = document.querySelector('form');      
431       form.addEventListener('submit', function(event) {
432         self.handle_submit(event, key, url, selector, cb);
433       });
434       self.addEvtListener('#cancel-btn', 'click', cb);
435       self.addEvtListener('#loeschen-btn', 'click', function(event) {
436         event.preventDefault();
437         self.handle_del_btn(selector, url, cb);
438       });
439     });
440   };
441   
442   /*
48f8f9 443    * existingKey: wenn die Entitaet existiert und geandert werden soll
U 444    *                 leer, wenn neue Entitaet 
445    */
446   this.handle_submit = function(event, existingKey, putUrl, keySelector, cb) {
447     event.preventDefault();
448     const data = new FormData(event.target);
449     const value = Object.fromEntries(data.entries());
095119 450     //console.log({ value });
U 451     //console.log(JSON.stringify(value));
48f8f9 452     var daten = JSON.stringify(value);
U 453     var formkey = document.querySelector(keySelector).value;
454     formkey = formkey.replace(' ', '').replace(/[\W]+/g, '');
455     if(typeof existingKey === "undefined" ||  existingKey.length < 1) {
456       // neu
457       self.http_put(putUrl + formkey, daten, function (responseText) {
458         if(typeof(cb) !== 'function') {
459           // ..
460         } else {
461           cb();
462         }
463       });
464     } else {
465       // aendern
466       self.http_put(putUrl + existingKey, daten, function (responseText) {
467         if(typeof(cb) !== 'function') {
468           // ..
469         } else {
470           cb();
471         }
472       });
473     }
474   };
475   
476   this.handle_del_btn = function(selectorKey, delUrl, cb) {
477     var pkey = document.querySelector(selectorKey).value;
478     var dlgdata = {"del-elem": pkey};
78d707 479     self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.txt', dlgdata, function() {
48f8f9 480       self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen);
U 481       self.addEvtListener('#ja-btn', 'click', function(event) {
095119 482         //console.log("loeschen geklickt.");
48f8f9 483         self.http_delete(delUrl + pkey, '', function (responseText) {
U 484           self.dialog_schliessen();
485           if(typeof(cb) !== 'function') {
486             // ..
487           } else {
488             cb();
489           }
490         });
491       });
492     });    
493   };  
748b6f 494   
U 495   /* ------------------ sonstige Helfer ----------------------- */
496       
7c22a2 497   this.addEvtListener = function(selector, eventName, func) {
U 498     document.querySelectorAll(selector).forEach(elem => { elem.addEventListener(eventName, func); });
499   };
500   
501   this.removeClassMulti = function(selector) {
502     document.querySelectorAll('.' + selector).forEach(elem => { elem.classList.remove(selector); });
503   };
504
f45e20 505   /* --------------------- asynchroner HTTP Client ----------------- */
faab2d 506   
f074f6 507   this.http_get = function (u, cb) {
b379f5 508     self.http_call('GET', u, null, cb);
U 509   };
f074f6 510
U 511   this.http_post = function (u, data, cb) {
b379f5 512     self.http_call('POST', u, data, cb);
U 513   };
514
90f5d4 515   this.http_put = function (u, data, cb) {
U 516     self.http_call('PUT', u, data, cb);
517   };
518   
5b7356 519   this.http_delete = function (u, data, cb) {
5f7e0b 520     // console.log("delete " + u);
5b7356 521     self.http_call('DELETE', u, data, cb);
U 522   };
523   
f074f6 524   this.http_call = function (method, u, data, scallback) {
b379f5 525     var xhr = new XMLHttpRequest();
U 526     var url = u;
f074f6 527     xhr.onreadystatechange = function () {
b379f5 528       if (this.readyState === 4 && this.status === 200) {
U 529         scallback(this.responseText);
530       }
531     };
532     xhr.open(method, url);
f074f6 533     if (method === 'GET') {
b379f5 534       xhr.send();
2597cd 535     } else if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
b379f5 536       xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
U 537       xhr.send(data);
538     }
539   };
8239d1 540   
f45e20 541   /* ------------------------ aus App-Vorlage -------------------  */
cfa858 542
f074f6 543   this.menue_umschalten = function () {
cfa858 544     var ham = document.querySelector(".hamburger");
U 545     ham.classList.toggle("is-active"); // hamburger-icon umschalten
546     self.appMenu.toggle(); // menue oeffnen/schliessen
547   };
548
f074f6 549   this.info_dialog_zeigen = function () {
78d707 550     self.dialog_laden_und_zeigen('data/tpl/dlg-info.txt', '');
cfa858 551     self.menue_umschalten();
U 552   };
553
f074f6 554   this.seitenleiste_umschalten = function () {
cfa858 555     var ostDiv = document.querySelector('.ost');
f074f6 556     if (ostDiv.classList.contains('ost-open')) {
cfa858 557       ostDiv.classList.remove('ost-open');
f074f6 558       ostDiv.style.flexBasis = '0em';
cfa858 559     } else {
f074f6 560       ostDiv.classList.add('ost-open');
U 561       ostDiv.style.flexBasis = '6em';
cfa858 562     }
U 563     self.menue_umschalten();
564   };
565
f074f6 566   this.fusszeile_umschalten = function () {
cfa858 567     var suedDiv = document.querySelector('.sued');
f074f6 568     if (suedDiv.classList.contains('sued-open')) {
cfa858 569       suedDiv.classList.remove('sued-open');
f074f6 570       suedDiv.style.height = '0';
cfa858 571     } else {
U 572       suedDiv.classList.add('sued-open');
f074f6 573       suedDiv.style.height = '1.5em';
cfa858 574     }
U 575     self.menue_umschalten();
576   };
577
f074f6 578   this.menu_message = function (msg) {
cfa858 579     self.meldung_mit_timeout(msg, 1500);
U 580     var suedDiv = document.querySelector('.sued');
f074f6 581     if (suedDiv.classList.contains('sued-open')) {
cfa858 582     } else {
U 583       suedDiv.classList.add('sued-open');
f074f6 584       suedDiv.style.height = '1.5em';
cfa858 585     }
U 586     self.menue_umschalten();
587   };
588
f074f6 589   this.message_1 = function () {
cfa858 590     self.menu_message('Eine Mitteilung.');
U 591   };
592
f074f6 593   this.message_2 = function () {
cfa858 594     self.menu_message('Was wir schon immer sagen wollten.');
U 595   };
596
f074f6 597   this.message_3 = function (text) {
cfa858 598     self.menu_message(text);
U 599   };
600
f074f6 601   this.meldung_mit_timeout = function (meldung, timeout) {
cfa858 602     var s = document.querySelector('.sued');
a43e1a 603     s.classList.add('sued-open');
U 604     s.style.height = '1.5em';
cfa858 605     s.textContent = meldung;
f074f6 606     setTimeout(function () {
cfa858 607       s.textContent = 'Bereit.';
f074f6 608       setTimeout(function () {
cfa858 609         var suedDiv = document.querySelector('.sued');
f074f6 610         if (suedDiv.classList.contains('sued-open')) {
U 611           suedDiv.classList.remove('sued-open');
612           suedDiv.style.height = '0';
cfa858 613         }
U 614       }, 500);
615     }, timeout);
616   };
8239d1 617   
f45e20 618   /* --------------------- Dialog-Funktionen ------------------------ */
cfa858 619
U 620   /*
f074f6 621    Einen Dialog aus Vorlagen erzeugen
U 622    
623    vurl - URL zur Dialogvorlage
624    msgTpl - URL mit einer Vorlage eines Mitteilungstextes (optional)
625    */
5b7356 626   this.dialog_laden_und_zeigen = function (vurl, msgTpl, cb) {
U 627     var vorlage = self.cache[vurl];
628     if(vorlage === undefined) {
629       self.http_get(vurl, function(antwort) {
630         self.cache[vurl] = antwort;
631         self.dialog_zeigen(vurl, msgTpl, cb);
f074f6 632       });
cfa858 633     } else {
5b7356 634       self.dialog_zeigen(vurl, msgTpl, cb);
cfa858 635     }
U 636   };
637
5b7356 638   this.dialog_zeigen = function (vurl, inhalt, cb) {
U 639     var dlg = document.querySelector(".dialog");
2597cd 640     self.html_erzeugen(vurl, inhalt, function (html) {
U 641       dlg.style.height = '7em';
642       dlg.innerHTML = html;
643       document.querySelector('.close-btn').addEventListener('click', self.dialog_schliessen);
644       if(typeof(cb) !== 'function') {
645         // ..
646       } else {
647         cb();
648       }
649     });
5b7356 650   };
2597cd 651   
f45e20 652   this.dialog_schliessen = function () {
cfa858 653     document.querySelector('.close-btn').removeEventListener('click', self.dialog_schliessen);
U 654     var dlg = document.querySelector('.dialog');
655     dlg.style.height = '0';
656     dlg.innerHTML = '';
657   };
658
f45e20 659   /* ---------------------   Vorlagen   ---------------------- */
cfa858 660
U 661   /*
f074f6 662    Das HTML erzeugen, das entsteht, wenn eine Vorlage mit Inhalt
U 663    gefüllt wird
664    
665    Das Füllen erfolgt asynchron, d.h. der Programmlauf geht nach dem
666    Aufruf weiter ohne auf das Laden und Füllen der Vorlage zu warten.
667    Das fertige HTML wird der Callback-Funktion übergeben
668    sobald die Vorlage geladen und gefüllt ist, unabhängig davon, wo der
669    Programmlauf zu diesem Zeitpunkt mittlerweile ist.
670    
671    vurl - URL zur Vorlagendatei
672    inhalt - die JSON-Struktur, deren Inhalt in die
673    Vorlage gefüllt werden soll
674    cb - Callback-Funktion, die gerufen wird, wenn die Vorlage gefüllt ist.
675    Dieser Callback-Funktion wird das fertige HTML übergeben
676    */
677   this.html_erzeugen = function (vurl, inhalt, cb) {
cfa858 678     var vorlage = self.cache[vurl];
f074f6 679     if (vorlage === undefined) {
cfa858 680       self.vorlage_laden_und_fuellen(vurl, inhalt, cb);
U 681     } else {
682       self.vorlage_fuellen(vurl, inhalt, cb);
683     }
684   };
685
f074f6 686   this.vorlage_fuellen = function (vurl, inhalt, cb) {
cfa858 687     cb(Mustache.render(self.cache[vurl], inhalt));
U 688   };
689
690   /*
f074f6 691    Eine Vorlage vom Server in den lokalen Speicher laden
U 692    vurl - der URL unter dem die Vorlage zu finden ist
693    inhalt - die JSON-Struktur, deren Inhalt in die
694    Vorlage gefüllt werden soll
695    cb - callback: Diese Funktion wird gerufen, wenn die Vorlage mit dem
696    Inhalt gefüllt ist
697    */
698   this.vorlage_laden_und_fuellen = function (vurl, inhalt, cb) {
cfa858 699     var xmlhttp = new XMLHttpRequest();
f074f6 700     xmlhttp.onreadystatechange = function () {
cfa858 701       if (this.readyState == 4 && this.status == 200) {
U 702         self.cache[vurl] = this.responseText;
703         self.vorlage_fuellen(vurl, inhalt, cb);
704       }
705     };
706     xmlhttp.open("GET", vurl, true);
707     xmlhttp.send();
708   };
709
710
711 }
712
f45e20 713 /* ----------- Objekte ---------------- */
U 714
715 function Ablageort(n, o, u) {
716   this.name = n;
717   this.ort = o;
718   this.url = u;
719 }
720
721 function Einstellung(k, v) {
722   this.key = k;
723   this.value = v;
724 }
725
726 function Abspieler(n, u) {
727   this.name = n;
728   this.url = u;
8d7d35 729 }
U 730
731 function Abspielliste(n) {
732   this.name = n;
e60cff 733 }
U 734
245ac1 735 function Titel(n, p, u, i, t, a) {
e60cff 736   this.katalogUrl = u;
2bdd78 737   this.pfad = p;
e60cff 738   this.name = n;
245ac1 739   this.interpret = i;
U 740   this.titelAnzName = t;
741   this.album  = a;
d6b78c 742 }