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