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