Persoenliche Mediazentrale
ulrich
2021-04-12 b5c0bc213cf115ee00a3336ab59abb6138cd0304
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",
0866ae 21             "6em");
f45e20 22
U 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() {
658c14 302     var bereichName = document.querySelector('.bereich-name').textContent;
U 303     if(bereichName === '') {
4f2589 304       var titel = self.titelErmitteln(document.querySelector(".selected"));
658c14 305       //var titelName = elem.textContent;
4f2589 306       /*
658c14 307       var titelName = elem.attributes.dateiName.nodeValue;
U 308       var album = elem.attributes.album.nodeValue;
309       var interpret = elem.attributes.interpret.nodeValue;
310       var anzName = elem.attributes.titelAnzName.nodeValue;
311       var titel;
312       if(self.mediaPfad.endsWith('/')) {
313         titel = new Titel(titelName, self.mediaPfad, self.ortPfad, interpret, anzName, album);
314       } else {
315         titel = new Titel(titelName, self.mediaPfad + '/', self.ortPfad, interpret, anzName, album);
316       }
4f2589 317       */
1c5fa4 318       var playername = document.querySelector('#abspieler').value;
U 319       /*      
320       HTTP POST /mz/api/strg/abspieler/play mit Titel im Body
658c14 321       
1c5fa4 322       url: /media/test/M/Muenchener-Freiheit/01-Ohne-Dich-schlaf-ich-heut-Nacht-nicht-ein.mp3      
658c14 323       */
U 324       console.log('plname: ' + playername + ' url: ' + titel.katalogUrl + titel.pfad + titel.name);
1c5fa4 325       self.http_post('../api/strg/' + playername, JSON.stringify(titel), function(responseText) {
658c14 326         self.meldung_mit_timeout(responseText, 1500);
1c5fa4 327       });      
658c14 328     } else {
U 329       var abs = document.querySelector('#abspieler').value;
330       var lst = document.querySelector('#playlist').value;
331       console.log(
332         "play playlist.value: " + document.querySelector('#playlist').value + 
333         ", abspieler.value: " + document.querySelector('#abspieler').value);
334       self.http_get('../api/strg/' + abs + '/play/liste/' + lst, function(responseText) {
335         self.meldung_mit_timeout(responseText, 1500);
336       });
337     }
095119 338   };
U 339   
9e14ef 340   this.kommando = function(kommando) {
U 341     var abs = document.querySelector('#abspieler').value;
342     self.http_get('../api/strg/' + abs + '/' + kommando, function(responseText) {
343       self.meldung_mit_timeout(responseText, 1500);
344     });
345   };
346     
095119 347   /* ------------- Verwaltungsfunktionen Abspielliste -------------------- */
U 348   
349   self.alleTitelEntfernen = function() {
350     var plname = document.querySelector('#playlist').value;
351     self.http_delete('../api/alist/' + plname + '/alle', '', function(responseText) {
352       // DELETE    http://localhost:9090/mz/api/alist/liste1/0
353       //self.meldung_mit_timeout(responseText, 1500);
354       self.titel_liste();
355     });
356   };
357   
358   this.titelDazu = function() {
4f2589 359     var titel = self.titelErmitteln(document.querySelector(".selected"));
095119 360     //var titelName = elem.textContent;
4f2589 361     /*
095119 362     var titelName = elem.attributes.dateiName.nodeValue;
U 363     var album = elem.attributes.album.nodeValue;
364     var interpret = elem.attributes.interpret.nodeValue;
365     var anzName = elem.attributes.titelAnzName.nodeValue;
366     var titel;
367     if(self.mediaPfad.endsWith('/')) {
368       titel = new Titel(titelName, self.mediaPfad, self.ortPfad, interpret, anzName, album);
369     } else {
370       titel = new Titel(titelName, self.mediaPfad + '/', self.ortPfad, interpret, anzName, album);
371     }
4f2589 372     */
095119 373     var plname = document.querySelector('#playlist').value;
U 374     self.http_put('../api/alist/' + plname, JSON.stringify(titel), function(responseText) {
375       //self.meldung_mit_timeout(responseText, 1500);
376     });
377   };  
378   
379   this.titelWeg = function() {
380     var elem = document.querySelector(".selected");
381     var parentElem = elem.parentNode;
382     //console.log("elem: " + elem.nodeName + ", parent: " + parentElem.nodeName + ", len: " + parentElem.childNodes.length);
383     var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente
384     //console.log("liElems.anz: " + liElems.length);
385     var gefunden = false;
386     for(var i = 0; i < liElems.length && !gefunden; i++) {
387       //console.log(liElems.item(i).textContent);
388       if(liElems.item(i).classList.contains("selected")) {
389         gefunden = true;
390         var index = i;
391         //console.log(elem.textContent + ' hat Index ' + i);
392       }
393     }
394     // /mz/api/alist/[pl-name]/[nr] 
395     var plname = document.querySelector('#playlist').value;
396     self.http_delete('../api/alist/' + plname + '/' + index,'', function(responseText) {
397       // DELETE    http://localhost:9090/mz/api/alist/liste1/0
398       //self.meldung_mit_timeout(responseText, 1500);
399       self.titel_liste();
400     });
401     
b56bb3 402   };
U 403   
748b6f 404   /* ------------- Helfer fuer Entitaets-Formulare ----------------------- */
14638b 405   
U 406   /*
407    * url: '../api/store/Ablageort/liste/'
78d707 408    * tpl: "data/tpl/ablageort_liste.txt"
14638b 409    * storeUrl: '../api/store/Ablageort/'
U 410    * formFunc: "self.ablageort_form"
411    * cb: etwas wie
412    *   function(responseText){
413    *     var ablageort = JSON.parse(responseText);
414    *     self.ablageort_form(ablageort);
415    *   });
416    */
50e53e 417   this.entitaet_liste = function(bname, listUrl, tpl, storeUrl, formFunc, cb) {
14638b 418     self.reset_top_buttons();
50e53e 419     document.querySelector('.bereich-name').textContent = bname;
78d707 420     var bb = document.querySelector('.breadcrumb-behaelter');
U 421     bb.textContent = "";
14638b 422     self.http_get(listUrl, function (responseText) {
U 423       self.vorlage_laden_und_fuellen(tpl, JSON.parse(responseText), function (html) {
424         document.querySelector(".zentraler-inhalt").innerHTML = html;
425         self.addEvtListener('.entity-eintrag', 'click', function (event) {
426           var t = event.target;
427           self.http_get(storeUrl + t.textContent, cb);
428         });
429         //self.addEvtListener('#neu-btn', 'click', function (event) {
430         self.addEvtListener('#top-neu-btn', 'click', function(event) {
431           eval(formFunc + "(this)");
432         });        
433       });
434     });
435   };  
748b6f 436       
48f8f9 437   /*
c7030d 438    * dat: gefuelltes Datenobjekt bei Aenderung
U 439    * key: der alte schluesselbegriff bei Aenderung (z.B. al.name)
78d707 440    * tpl: "data/tpl/form_abspielliste.txt"
c7030d 441    * url: '../api/store/Abspielliste/'
U 442    * selector: '#abspielliste-name'
443    * cbOk: etwas wie
444    *    function() {
445    *       self.abspielliste_auswahl_fuellen();
446    *       self.abspielliste_liste();
447    *     });
448    * delSelector: '#abspielliste-name'
449    * cbDel: etwas wie
450    *    function() {
451    *       self.abspielliste_auswahl_fuellen();
452    *       self.abspielliste_liste();
453    *     });
454    */
455
50e53e 456   this.entitaet_form = function(bname, dat, key, tpl, url, selector, cb) {
U 457     document.querySelector('.bereich-name').textContent = bname;
c7030d 458     self.vorlage_laden_und_fuellen(tpl, dat, function (html) {
U 459       document.querySelector(".zentraler-inhalt").innerHTML = html;
460       const form = document.querySelector('form');      
461       form.addEventListener('submit', function(event) {
462         self.handle_submit(event, key, url, selector, cb);
463       });
464       self.addEvtListener('#cancel-btn', 'click', cb);
465       self.addEvtListener('#loeschen-btn', 'click', function(event) {
466         event.preventDefault();
467         self.handle_del_btn(selector, url, cb);
468       });
469     });
470   };
471   
472   /*
48f8f9 473    * existingKey: wenn die Entitaet existiert und geandert werden soll
U 474    *                 leer, wenn neue Entitaet 
475    */
476   this.handle_submit = function(event, existingKey, putUrl, keySelector, cb) {
477     event.preventDefault();
478     const data = new FormData(event.target);
479     const value = Object.fromEntries(data.entries());
095119 480     //console.log({ value });
U 481     //console.log(JSON.stringify(value));
48f8f9 482     var daten = JSON.stringify(value);
U 483     var formkey = document.querySelector(keySelector).value;
484     formkey = formkey.replace(' ', '').replace(/[\W]+/g, '');
485     if(typeof existingKey === "undefined" ||  existingKey.length < 1) {
486       // neu
487       self.http_put(putUrl + formkey, daten, function (responseText) {
488         if(typeof(cb) !== 'function') {
489           // ..
490         } else {
491           cb();
492         }
493       });
494     } else {
495       // aendern
496       self.http_put(putUrl + existingKey, daten, function (responseText) {
497         if(typeof(cb) !== 'function') {
498           // ..
499         } else {
500           cb();
501         }
502       });
503     }
504   };
505   
506   this.handle_del_btn = function(selectorKey, delUrl, cb) {
507     var pkey = document.querySelector(selectorKey).value;
508     var dlgdata = {"del-elem": pkey};
78d707 509     self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.txt', dlgdata, function() {
48f8f9 510       self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen);
U 511       self.addEvtListener('#ja-btn', 'click', function(event) {
095119 512         //console.log("loeschen geklickt.");
48f8f9 513         self.http_delete(delUrl + pkey, '', function (responseText) {
U 514           self.dialog_schliessen();
515           if(typeof(cb) !== 'function') {
516             // ..
517           } else {
518             cb();
519           }
520         });
521       });
522     });    
523   };  
748b6f 524   
U 525   /* ------------------ sonstige Helfer ----------------------- */
526       
7c22a2 527   this.addEvtListener = function(selector, eventName, func) {
U 528     document.querySelectorAll(selector).forEach(elem => { elem.addEventListener(eventName, func); });
529   };
530   
531   this.removeClassMulti = function(selector) {
532     document.querySelectorAll('.' + selector).forEach(elem => { elem.classList.remove(selector); });
533   };
4f2589 534   
U 535   self.titelErmitteln = function(elem) {
536     var titelName = elem.attributes.dateiName.nodeValue;
537     var album = elem.attributes.album.nodeValue;
538     var interpret = elem.attributes.interpret.nodeValue;
539     var anzName = elem.attributes.titelAnzName.nodeValue;
540     var titel;
541     if(self.mediaPfad.endsWith('/')) {
542       titel = new Titel(titelName, self.mediaPfad, self.ortPfad, interpret, anzName, album);
543     } else {
544       titel = new Titel(titelName, self.mediaPfad + '/', self.ortPfad, interpret, anzName, album);
545     }
546     return titel;
547   };
7c22a2 548
f45e20 549   /* --------------------- asynchroner HTTP Client ----------------- */
faab2d 550   
f074f6 551   this.http_get = function (u, cb) {
b379f5 552     self.http_call('GET', u, null, cb);
U 553   };
f074f6 554
U 555   this.http_post = function (u, data, cb) {
b379f5 556     self.http_call('POST', u, data, cb);
U 557   };
558
90f5d4 559   this.http_put = function (u, data, cb) {
U 560     self.http_call('PUT', u, data, cb);
561   };
562   
5b7356 563   this.http_delete = function (u, data, cb) {
5f7e0b 564     // console.log("delete " + u);
5b7356 565     self.http_call('DELETE', u, data, cb);
U 566   };
567   
f074f6 568   this.http_call = function (method, u, data, scallback) {
b379f5 569     var xhr = new XMLHttpRequest();
U 570     var url = u;
f074f6 571     xhr.onreadystatechange = function () {
b379f5 572       if (this.readyState === 4 && this.status === 200) {
U 573         scallback(this.responseText);
574       }
575     };
576     xhr.open(method, url);
f074f6 577     if (method === 'GET') {
b379f5 578       xhr.send();
2597cd 579     } else if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
b379f5 580       xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
U 581       xhr.send(data);
582     }
583   };
8239d1 584   
f45e20 585   /* ------------------------ aus App-Vorlage -------------------  */
cfa858 586
f074f6 587   this.menue_umschalten = function () {
cfa858 588     var ham = document.querySelector(".hamburger");
U 589     ham.classList.toggle("is-active"); // hamburger-icon umschalten
590     self.appMenu.toggle(); // menue oeffnen/schliessen
591   };
592
f074f6 593   this.info_dialog_zeigen = function () {
78d707 594     self.dialog_laden_und_zeigen('data/tpl/dlg-info.txt', '');
cfa858 595     self.menue_umschalten();
U 596   };
597
f074f6 598   this.seitenleiste_umschalten = function () {
cfa858 599     var ostDiv = document.querySelector('.ost');
f074f6 600     if (ostDiv.classList.contains('ost-open')) {
cfa858 601       ostDiv.classList.remove('ost-open');
f074f6 602       ostDiv.style.flexBasis = '0em';
cfa858 603     } else {
f074f6 604       ostDiv.classList.add('ost-open');
U 605       ostDiv.style.flexBasis = '6em';
cfa858 606     }
U 607     self.menue_umschalten();
608   };
609
f074f6 610   this.fusszeile_umschalten = function () {
cfa858 611     var suedDiv = document.querySelector('.sued');
f074f6 612     if (suedDiv.classList.contains('sued-open')) {
cfa858 613       suedDiv.classList.remove('sued-open');
f074f6 614       suedDiv.style.height = '0';
cfa858 615     } else {
U 616       suedDiv.classList.add('sued-open');
f074f6 617       suedDiv.style.height = '1.5em';
cfa858 618     }
U 619     self.menue_umschalten();
620   };
621
f074f6 622   this.menu_message = function (msg) {
cfa858 623     self.meldung_mit_timeout(msg, 1500);
U 624     var suedDiv = document.querySelector('.sued');
f074f6 625     if (suedDiv.classList.contains('sued-open')) {
cfa858 626     } else {
U 627       suedDiv.classList.add('sued-open');
f074f6 628       suedDiv.style.height = '1.5em';
cfa858 629     }
U 630     self.menue_umschalten();
631   };
632
f074f6 633   this.message_1 = function () {
cfa858 634     self.menu_message('Eine Mitteilung.');
U 635   };
636
f074f6 637   this.message_2 = function () {
cfa858 638     self.menu_message('Was wir schon immer sagen wollten.');
U 639   };
640
f074f6 641   this.message_3 = function (text) {
cfa858 642     self.menu_message(text);
U 643   };
644
f074f6 645   this.meldung_mit_timeout = function (meldung, timeout) {
cfa858 646     var s = document.querySelector('.sued');
a43e1a 647     s.classList.add('sued-open');
U 648     s.style.height = '1.5em';
cfa858 649     s.textContent = meldung;
f074f6 650     setTimeout(function () {
cfa858 651       s.textContent = 'Bereit.';
f074f6 652       setTimeout(function () {
cfa858 653         var suedDiv = document.querySelector('.sued');
f074f6 654         if (suedDiv.classList.contains('sued-open')) {
U 655           suedDiv.classList.remove('sued-open');
656           suedDiv.style.height = '0';
cfa858 657         }
U 658       }, 500);
659     }, timeout);
660   };
8239d1 661   
f45e20 662   /* --------------------- Dialog-Funktionen ------------------------ */
cfa858 663
U 664   /*
f074f6 665    Einen Dialog aus Vorlagen erzeugen
U 666    
667    vurl - URL zur Dialogvorlage
668    msgTpl - URL mit einer Vorlage eines Mitteilungstextes (optional)
669    */
5b7356 670   this.dialog_laden_und_zeigen = function (vurl, msgTpl, cb) {
U 671     var vorlage = self.cache[vurl];
672     if(vorlage === undefined) {
673       self.http_get(vurl, function(antwort) {
674         self.cache[vurl] = antwort;
675         self.dialog_zeigen(vurl, msgTpl, cb);
f074f6 676       });
cfa858 677     } else {
5b7356 678       self.dialog_zeigen(vurl, msgTpl, cb);
cfa858 679     }
U 680   };
681
5b7356 682   this.dialog_zeigen = function (vurl, inhalt, cb) {
U 683     var dlg = document.querySelector(".dialog");
2597cd 684     self.html_erzeugen(vurl, inhalt, function (html) {
U 685       dlg.style.height = '7em';
686       dlg.innerHTML = html;
687       document.querySelector('.close-btn').addEventListener('click', self.dialog_schliessen);
688       if(typeof(cb) !== 'function') {
689         // ..
690       } else {
691         cb();
692       }
693     });
5b7356 694   };
2597cd 695   
f45e20 696   this.dialog_schliessen = function () {
cfa858 697     document.querySelector('.close-btn').removeEventListener('click', self.dialog_schliessen);
U 698     var dlg = document.querySelector('.dialog');
699     dlg.style.height = '0';
700     dlg.innerHTML = '';
701   };
702
f45e20 703   /* ---------------------   Vorlagen   ---------------------- */
cfa858 704
U 705   /*
f074f6 706    Das HTML erzeugen, das entsteht, wenn eine Vorlage mit Inhalt
U 707    gefüllt wird
708    
709    Das Füllen erfolgt asynchron, d.h. der Programmlauf geht nach dem
710    Aufruf weiter ohne auf das Laden und Füllen der Vorlage zu warten.
711    Das fertige HTML wird der Callback-Funktion übergeben
712    sobald die Vorlage geladen und gefüllt ist, unabhängig davon, wo der
713    Programmlauf zu diesem Zeitpunkt mittlerweile ist.
714    
715    vurl - URL zur Vorlagendatei
716    inhalt - die JSON-Struktur, deren Inhalt in die
717    Vorlage gefüllt werden soll
718    cb - Callback-Funktion, die gerufen wird, wenn die Vorlage gefüllt ist.
719    Dieser Callback-Funktion wird das fertige HTML übergeben
720    */
721   this.html_erzeugen = function (vurl, inhalt, cb) {
cfa858 722     var vorlage = self.cache[vurl];
f074f6 723     if (vorlage === undefined) {
cfa858 724       self.vorlage_laden_und_fuellen(vurl, inhalt, cb);
U 725     } else {
726       self.vorlage_fuellen(vurl, inhalt, cb);
727     }
728   };
729
f074f6 730   this.vorlage_fuellen = function (vurl, inhalt, cb) {
cfa858 731     cb(Mustache.render(self.cache[vurl], inhalt));
U 732   };
733
734   /*
f074f6 735    Eine Vorlage vom Server in den lokalen Speicher laden
U 736    vurl - der URL unter dem die Vorlage zu finden ist
737    inhalt - die JSON-Struktur, deren Inhalt in die
738    Vorlage gefüllt werden soll
739    cb - callback: Diese Funktion wird gerufen, wenn die Vorlage mit dem
740    Inhalt gefüllt ist
741    */
742   this.vorlage_laden_und_fuellen = function (vurl, inhalt, cb) {
cfa858 743     var xmlhttp = new XMLHttpRequest();
f074f6 744     xmlhttp.onreadystatechange = function () {
cfa858 745       if (this.readyState == 4 && this.status == 200) {
U 746         self.cache[vurl] = this.responseText;
747         self.vorlage_fuellen(vurl, inhalt, cb);
748       }
749     };
750     xmlhttp.open("GET", vurl, true);
751     xmlhttp.send();
752   };
753
754
755 }
756
f45e20 757 /* ----------- Objekte ---------------- */
U 758
759 function Ablageort(n, o, u) {
760   this.name = n;
761   this.ort = o;
762   this.url = u;
763 }
764
765 function Einstellung(k, v) {
766   this.key = k;
767   this.value = v;
768 }
769
770 function Abspieler(n, u) {
771   this.name = n;
772   this.url = u;
8d7d35 773 }
U 774
775 function Abspielliste(n) {
776   this.name = n;
e60cff 777 }
U 778
245ac1 779 function Titel(n, p, u, i, t, a) {
e60cff 780   this.katalogUrl = u;
2bdd78 781   this.pfad = p;
e60cff 782   this.name = n;
245ac1 783   this.interpret = i;
U 784   this.titelAnzName = t;
785   this.album  = a;
d6b78c 786 }