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