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