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