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