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