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