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