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