Persoenliche Mediazentrale
ulrich
2021-04-08 dfb7d34f88efbb3eb7632ae628ccfd4576824477
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;
f45e20 7
U 8   this.init = function () {
9     self.mediaPfad = '/';
10     self.ortPfad = '/';
11     self.cache = new Array();
12     self.appMenu = new AppMenu();
13     self.appMenu.init(
14             "data/menu/",
15             "hauptmenue.json",
16             "data/tpl/app-menu.tpl",
17             ".west",
18             "8em");
19
20     document.querySelector('.hamburger').addEventListener('click', function (e) {
21       self.menue_umschalten();
22     });
23     
24     self.addEvtListener('#mi-katalog', 'click', self.media_liste);
25     self.addEvtListener('#mi-orte', 'click', self.ablageort_liste);
26     self.addEvtListener('#mi-prefs', 'click', self.prefs_liste);
27     self.addEvtListener('#mi-player', 'click', self.abspieler_liste);
28     
29     self.fusszeile_umschalten();
30     self.seitenleiste_umschalten();
31     self.dialog_unten_zeigen();
32   };
33   
34   this.abspieler_auswahl_fuellen = function() {
35     self.http_get('../api/store/Abspieler/', function (responseText) {
36       /*
37        {"ArrayList": [{"name":"Wohnz","url":"http://rpi4-wz:9090/"},{"name":"Arbz","url":"http://rpi4-az:9090/"}]}
38        */
39       self.vorlage_laden_und_fuellen("data/tpl/abs_sel.tpl", JSON.parse(responseText), function (html) {
40         document.querySelector(".abs-sel").innerHTML = html;
41       });    
42     });
43   };
44
45   /* Unterer Einblendbereich */
46   
47   this.dialog_unten_zeigen = function() {
48     self.vorlage_laden_und_fuellen("data/tpl/ctrl.tpl", "", function (html) {
49       var dlg = document.querySelector(".dialog-unten");
50       dlg.style.height = '4.5em';
51       dlg.innerHTML = html;
52       self.abspieler_auswahl_fuellen();
53     });
54   };
55
86bbf7 56   
U 57   // auf der obersten Ebene werden die Kataloge angezeigt,
58   // darunter der Inhalt des aktuellen Pfades
59   this.media_liste = function() {
60     if(self.ortPfad === '/') {
61       // Kataloge listen
f45e20 62       self.http_get('../api/store/Ablageort/liste/', function (responseText) {
86bbf7 63         self.vorlage_laden_und_fuellen("data/tpl/katalog_root_liste.tpl", JSON.parse(responseText), function (html) {
U 64           document.querySelector(".zentraler-inhalt").innerHTML = html;
65           self.addEvtListener('.entity-eintrag', 'click', function (event) {
66             var t = event.target;
67             self.http_get('../api/store/Ablageort/' + t.textContent, function(responseText) {
68               var ablageort = JSON.parse(responseText);
69               self.ortPfad = ablageort.url;
70               self.media_liste();
71             });
72           });
73         });
74       });
75     } else {
76       // Pfad listen
f61a32 77       // console.log("vorher ortPfad: " + self.ortPfad);
U 78       //console.log("vorher mediaPfad: " + self.mediaPfad);
3271f1 79       //self.http_get('..' + self.ortPfad + '/' + self.mediaPfad + '/', function(responseText) {
U 80       var url = '..' + self.ortPfad + self.mediaPfad;
81       if(!url.endsWith('/')) {
82         url = url + '/';
83       }
f61a32 84       //console.log("url: " + url);      
3271f1 85       self.http_get(url, function(responseText) {
ca9872 86         //console.log(responseText);
86bbf7 87         self.vorlage_laden_und_fuellen("data/tpl/katalog_inhalt_liste.tpl", JSON.parse(responseText), function (html) {
U 88           document.querySelector(".zentraler-inhalt").innerHTML = html;
f61a32 89           //console.log("mediaPfad bei Anzeige: " + self.mediaPfad);
86bbf7 90           self.addEvtListener('.entity-eintrag', 'click', function (event) {
U 91             var t = event.target;
3271f1 92             var tx = t.textContent;
f61a32 93             //console.log("tx: " + tx);
U 94             //console.log("mediaPfad nach Auswahl: " + self.mediaPfad);
86bbf7 95             if(t.classList.contains("entity-typ-folder")) {
3271f1 96               if(self.mediaPfad.endsWith('/')) {
U 97                 self.mediaPfad = self.mediaPfad + tx;                
98               } else {
99                 self.mediaPfad = self.mediaPfad + '/' + tx;
100               }
101               //self.mediaPfad = self.mediaPfad + t.textContent;
f61a32 102               //console.log("mediaPfad neu: " + self.mediaPfad);
86bbf7 103               self.media_liste();
U 104             } else {
f61a32 105               //console.log("Media-Inhalt auswaehlen oder abspielen");
7c22a2 106               self.removeClassMulti('selected');
U 107               t.classList.add('selected');
86bbf7 108             }
U 109           });
110           self.addEvtListener('#zurueck-btn', 'click', function (event) {
111             if(self.mediaPfad === '/') {
112               self.ortPfad = '/';              
113             } else {
114               var pos = self.mediaPfad.lastIndexOf('/');
3271f1 115               var parent;
U 116               if(pos > 1) {
117                 parent = self.mediaPfad.substring(0, pos);
118               } else {
119                 parent = '/';
120               }
f61a32 121               //console.log("Parent: " + parent);
86bbf7 122               self.mediaPfad = parent;
U 123             }
124             self.media_liste();
125           });        
126         });
127       });
128     }
129   };
cfa858 130
a43e1a 131   this.ablageort_liste = function() {
f45e20 132     self.http_get('../api/store/Ablageort/liste/', function (responseText) {
a43e1a 133       self.vorlage_laden_und_fuellen("data/tpl/ablageort_liste.tpl", JSON.parse(responseText), function (html) {
U 134         document.querySelector(".zentraler-inhalt").innerHTML = html;
135         self.addEvtListener('.entity-eintrag', 'click', function (event) {
136           var t = event.target;
90f5d4 137           self.http_get('../api/store/Ablageort/' + t.textContent, function(responseText){
86bbf7 138             var ablageort = JSON.parse(responseText);
90f5d4 139             self.ablageort_form(ablageort);
U 140           });
a43e1a 141         });
faab2d 142         self.addEvtListener('#neu-btn', 'click', function (event) {
U 143           eval("self.ablageort_form" + "(this)");
144         });        
cf6509 145       });
U 146     });
147   };
148
149   this.prefs_liste = function() {
f45e20 150     self.http_get('../api/store/Einstellung/liste/', function (responseText) {
cf6509 151       self.vorlage_laden_und_fuellen("data/tpl/einstellung_liste.tpl", JSON.parse(responseText), function (html) {
U 152         document.querySelector(".zentraler-inhalt").innerHTML = html;
153         self.addEvtListener('.entity-eintrag', 'click', function (event) {
154           var t = event.target;
155           self.http_get('../api/store/Einstellung/' + t.textContent, function(responseText){
156             var einstellung = JSON.parse(responseText);
157             self.prefs_form(einstellung);
158           });
159         });
160         self.addEvtListener('#neu-btn', 'click', function (event) {
161           eval("self.prefs_form" + "(this)");
162         });        
163       });
164     });
165   };
166
3d4bca 167   this.abspieler_liste = function() {
f45e20 168     self.http_get('../api/store/Abspieler/liste/', function (responseText) {
3d4bca 169       self.vorlage_laden_und_fuellen("data/tpl/abspieler_liste.tpl", JSON.parse(responseText), function (html) {
U 170         document.querySelector(".zentraler-inhalt").innerHTML = html;
171         self.addEvtListener('.entity-eintrag', 'click', function (event) {
172           var t = event.target;
173           self.http_get('../api/store/Abspieler/' + t.textContent, function(responseText){
174             var abspieler = JSON.parse(responseText);
175             self.abspieler_form(abspieler);
176           });
177         });
178         self.addEvtListener('#neu-btn', 'click', function (event) {
179           eval("self.abspieler_form" + "(this)");
180         });        
181       });
182     });
183   };
184
185   this.abspieler_form = function(pl) {
186     self.vorlage_laden_und_fuellen("data/tpl/form_abspieler.tpl", pl, function (html) {
187       document.querySelector(".zentraler-inhalt").innerHTML = html;
188       self.addEvtListener('#ok-btn', 'click', function () {
189         var plname = document.querySelector('#abspieler-name').value;
190         plname = plname.replace(' ', '').replace(/[\W]+/g, '');
191         var abspieler = new Abspieler(
192           plname,
193           document.querySelector('#abspieler-url').value
194         );
195         var daten = JSON.stringify(abspieler);        
dfb7d3 196         //if(typeof pl === "undefined" || pl.key !== plname) {
U 197         if(typeof pl.name === "undefined" || pl.name.length < 1) {
3d4bca 198           // neu
dfb7d3 199           self.http_put('../api/store/Abspieler/' + plname, daten, function (responseText) {
3d4bca 200             // hier die Antwort verarbeiten
dfb7d3 201             self.abspieler_auswahl_fuellen();
U 202             self.abspieler_liste();
3d4bca 203           });
U 204         } else {
205           // aendern
dfb7d3 206           self.http_put('../api/store/Abspieler/' + pl.name, daten, function (responseText) {
3d4bca 207             // hier die Antwort verarbeiten
dfb7d3 208             self.abspieler_auswahl_fuellen();
U 209             self.abspieler_liste();
3d4bca 210           });
U 211         }
212       });
213       self.addEvtListener('#cancel-btn', 'click', function () {
214         //document.querySelector(".zentraler-inhalt").innerHTML = '';
215         self.abspieler_liste();
216       });
217       self.addEvtListener('#loeschen-btn', 'click', function() {
218         var plname = document.querySelector('#abspieler-name').value;
219         var dlgdata = {"del-elem": plname};
220         self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.tpl', dlgdata, function() {
221           self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen);
222           self.addEvtListener('#ja-btn', 'click', function() {
223             self.http_delete('../api/store/Abspieler/' + plname, '', function (responseText) {
224               // hier die Antwort verarbeiten
225               self.dialog_schliessen();
226               //document.querySelector(".zentraler-inhalt").innerHTML = '';
dfb7d3 227               self.abspieler_auswahl_fuellen();
3d4bca 228               self.abspieler_liste();
U 229             });
230           });
231         });
232       });
233     });
234   };
cf6509 235
U 236   this.prefs_form = function(k) {
237     self.vorlage_laden_und_fuellen("data/tpl/form_einstellung.tpl", k, function (html) {
238       document.querySelector(".zentraler-inhalt").innerHTML = html;
239       self.addEvtListener('#ok-btn', 'click', function () {
240         var pkey = document.querySelector('#einstellung-key').value;
241         pkey = pkey.replace(' ', '').replace(/[\W]+/g, '');
242         var pref = new Einstellung(
243           pkey,
244           document.querySelector('#einstellung-value').value
245         );
246         var daten = JSON.stringify(pref);        
dfb7d3 247         //if(typeof k === "undefined" || k.key !== pkey) {
U 248         if(typeof k.key === "undefined" ||  k.key.length < 1) {
cf6509 249           // neu
dfb7d3 250           self.http_put('../api/store/Einstellung/' + pkey, daten, function (responseText) {
cf6509 251             // hier die Antwort verarbeiten
dfb7d3 252             self.prefs_liste();
cf6509 253           });
U 254         } else {
255           // aendern
dfb7d3 256           self.http_put('../api/store/Einstellung/' + k.key, daten, function (responseText) {
cf6509 257             // hier die Antwort verarbeiten
dfb7d3 258             self.prefs_liste();
cf6509 259           });
U 260         }
261       });
262       self.addEvtListener('#cancel-btn', 'click', function () {
263         //document.querySelector(".zentraler-inhalt").innerHTML = '';
264         self.prefs_liste();
265       });
266       self.addEvtListener('#loeschen-btn', 'click', function() {
267         var pkey = document.querySelector('#einstellung-key').value;
268         var dlgdata = {"del-elem": pkey};
269         self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.tpl', dlgdata, function() {
270           self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen);
271           self.addEvtListener('#ja-btn', 'click', function() {
272             self.http_delete('../api/store/Einstellung/' + pkey, '', function (responseText) {
273               // hier die Antwort verarbeiten
274               self.dialog_schliessen();
275               //document.querySelector(".zentraler-inhalt").innerHTML = '';
276               self.prefs_liste();
277             });
278           });
279         });
a43e1a 280       });
U 281     });
282   };
cfa858 283
90f5d4 284   /* 
U 285    * Ablageort-Formular anzeigen
286    * 
287    * {"name":"Katalog 2","ort":"/home/ulrich/Videos","url":"/media/kat2"}: 
288    * 
289    * @param {type} ablageort  der Ablageort, der bearbeitet werden soll, leer fuer neuen Ort
290    * @returns {undefined} kein Rueckgabewert
291    */
292   this.ablageort_form = function(ort) {
293     self.vorlage_laden_und_fuellen("data/tpl/form_ablageort.tpl", ort, function (html) {
b379f5 294       document.querySelector(".zentraler-inhalt").innerHTML = html;
f074f6 295       self.addEvtListener('#ok-btn', 'click', function () {
2597cd 296         var aName = document.querySelector('#ablageort-name').value;
U 297         aName = aName.replace(' ', '').replace(/[\W]+/g, '');
b379f5 298         var a = new Ablageort(
2597cd 299           aName,
b379f5 300           document.querySelector('#ablageort-ort').value,
U 301           document.querySelector('#ablageort-url').value
302         );
90f5d4 303         var daten = JSON.stringify(a);        
dfb7d3 304         //if(typeof ort === "undefined" || ort.name !== aName) {
U 305         if(typeof ort.name === "undefined"  || ort.name.length < 1) {
2597cd 306           // neu
dfb7d3 307           self.http_put('../api/store/Ablageort/' + aName, daten, function (responseText) {
90f5d4 308             // hier die Antwort verarbeiten
dfb7d3 309             self.ablageort_liste();
90f5d4 310           });
U 311         } else {
2597cd 312           // aendern
dfb7d3 313           self.http_put('../api/store/Ablageort/' + ort.name, daten, function (responseText) {
90f5d4 314             // hier die Antwort verarbeiten
dfb7d3 315             self.ablageort_liste();
90f5d4 316           });
U 317         }
b379f5 318       });
f074f6 319       self.addEvtListener('#cancel-btn', 'click', function () {
b29119 320         //document.querySelector(".zentraler-inhalt").innerHTML = '';
faab2d 321         self.ablageort_liste();
5b7356 322       });
U 323       self.addEvtListener('#loeschen-btn', 'click', function() {
324         var aoname = document.querySelector('#ablageort-name').value;
325         var dlgdata = {"del-elem": aoname};
326         self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.tpl', dlgdata, function() {
327           self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen);
328           self.addEvtListener('#ja-btn', 'click', function() {
90f5d4 329             self.http_delete('../api/store/Ablageort/' + aoname, '', function (responseText) {
U 330               // hier die Antwort verarbeiten
2597cd 331               self.dialog_schliessen();
b29119 332               //document.querySelector(".zentraler-inhalt").innerHTML = '';
faab2d 333               self.ablageort_liste();
90f5d4 334             });
5b7356 335           });
U 336         });
b379f5 337       });
U 338     });
339   };
340
7c22a2 341   this.addEvtListener = function(selector, eventName, func) {
U 342     document.querySelectorAll(selector).forEach(elem => { elem.addEventListener(eventName, func); });
343   };
344   
345   this.removeClassMulti = function(selector) {
346     document.querySelectorAll('.' + selector).forEach(elem => { elem.classList.remove(selector); });
347   };
348
f45e20 349   /* --------------------- asynchroner HTTP Client ----------------- */
faab2d 350   
f074f6 351   this.http_get = function (u, cb) {
b379f5 352     self.http_call('GET', u, null, cb);
U 353   };
f074f6 354
U 355   this.http_post = function (u, data, cb) {
b379f5 356     self.http_call('POST', u, data, cb);
U 357   };
358
90f5d4 359   this.http_put = function (u, data, cb) {
U 360     self.http_call('PUT', u, data, cb);
361   };
362   
5b7356 363   this.http_delete = function (u, data, cb) {
2597cd 364     console.log("delete " + u);
5b7356 365     self.http_call('DELETE', u, data, cb);
U 366   };
367   
f074f6 368   this.http_call = function (method, u, data, scallback) {
b379f5 369     var xhr = new XMLHttpRequest();
U 370     var url = u;
f074f6 371     xhr.onreadystatechange = function () {
b379f5 372       if (this.readyState === 4 && this.status === 200) {
U 373         scallback(this.responseText);
374       }
375     };
376     xhr.open(method, url);
f074f6 377     if (method === 'GET') {
b379f5 378       xhr.send();
2597cd 379     } else if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
b379f5 380       xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
U 381       xhr.send(data);
382     }
383   };
8239d1 384   
f45e20 385   /* ------------------------ aus App-Vorlage -------------------  */
cfa858 386
f074f6 387   this.menue_umschalten = function () {
cfa858 388     var ham = document.querySelector(".hamburger");
U 389     ham.classList.toggle("is-active"); // hamburger-icon umschalten
390     self.appMenu.toggle(); // menue oeffnen/schliessen
391   };
392
f074f6 393   this.info_dialog_zeigen = function () {
cfa858 394     self.dialog_laden_und_zeigen('data/tpl/dlg-info.tpl', '');
U 395     self.menue_umschalten();
396   };
397
f074f6 398   this.seitenleiste_umschalten = function () {
cfa858 399     var ostDiv = document.querySelector('.ost');
f074f6 400     if (ostDiv.classList.contains('ost-open')) {
cfa858 401       ostDiv.classList.remove('ost-open');
f074f6 402       ostDiv.style.flexBasis = '0em';
cfa858 403     } else {
f074f6 404       ostDiv.classList.add('ost-open');
U 405       ostDiv.style.flexBasis = '6em';
cfa858 406     }
U 407     self.menue_umschalten();
408   };
409
f074f6 410   this.fusszeile_umschalten = function () {
cfa858 411     var suedDiv = document.querySelector('.sued');
f074f6 412     if (suedDiv.classList.contains('sued-open')) {
cfa858 413       suedDiv.classList.remove('sued-open');
f074f6 414       suedDiv.style.height = '0';
cfa858 415     } else {
U 416       suedDiv.classList.add('sued-open');
f074f6 417       suedDiv.style.height = '1.5em';
cfa858 418     }
U 419     self.menue_umschalten();
420   };
421
f074f6 422   this.menu_message = function (msg) {
cfa858 423     self.meldung_mit_timeout(msg, 1500);
U 424     var suedDiv = document.querySelector('.sued');
f074f6 425     if (suedDiv.classList.contains('sued-open')) {
cfa858 426     } else {
U 427       suedDiv.classList.add('sued-open');
f074f6 428       suedDiv.style.height = '1.5em';
cfa858 429     }
U 430     self.menue_umschalten();
431   };
432
f074f6 433   this.message_1 = function () {
cfa858 434     self.menu_message('Eine Mitteilung.');
U 435   };
436
f074f6 437   this.message_2 = function () {
cfa858 438     self.menu_message('Was wir schon immer sagen wollten.');
U 439   };
440
f074f6 441   this.message_3 = function (text) {
cfa858 442     self.menu_message(text);
U 443   };
444
f074f6 445   this.meldung_mit_timeout = function (meldung, timeout) {
cfa858 446     var s = document.querySelector('.sued');
a43e1a 447     s.classList.add('sued-open');
U 448     s.style.height = '1.5em';
cfa858 449     s.textContent = meldung;
f074f6 450     setTimeout(function () {
cfa858 451       s.textContent = 'Bereit.';
f074f6 452       setTimeout(function () {
cfa858 453         var suedDiv = document.querySelector('.sued');
f074f6 454         if (suedDiv.classList.contains('sued-open')) {
U 455           suedDiv.classList.remove('sued-open');
456           suedDiv.style.height = '0';
cfa858 457         }
U 458       }, 500);
459     }, timeout);
460   };
8239d1 461   
f45e20 462   /* --------------------- Dialog-Funktionen ------------------------ */
cfa858 463
U 464   /*
f074f6 465    Einen Dialog aus Vorlagen erzeugen
U 466    
467    vurl - URL zur Dialogvorlage
468    msgTpl - URL mit einer Vorlage eines Mitteilungstextes (optional)
469    */
5b7356 470   this.dialog_laden_und_zeigen = function (vurl, msgTpl, cb) {
U 471     var vorlage = self.cache[vurl];
472     if(vorlage === undefined) {
473       self.http_get(vurl, function(antwort) {
474         self.cache[vurl] = antwort;
475         self.dialog_zeigen(vurl, msgTpl, cb);
f074f6 476       });
cfa858 477     } else {
5b7356 478       self.dialog_zeigen(vurl, msgTpl, cb);
cfa858 479     }
U 480   };
481
5b7356 482   this.dialog_zeigen = function (vurl, inhalt, cb) {
U 483     var dlg = document.querySelector(".dialog");
2597cd 484     self.html_erzeugen(vurl, inhalt, function (html) {
U 485       dlg.style.height = '7em';
486       dlg.innerHTML = html;
487       document.querySelector('.close-btn').addEventListener('click', self.dialog_schliessen);
488       if(typeof(cb) !== 'function') {
489         // ..
490       } else {
491         cb();
492       }
493     });
5b7356 494   };
2597cd 495   
f45e20 496   this.dialog_schliessen = function () {
cfa858 497     document.querySelector('.close-btn').removeEventListener('click', self.dialog_schliessen);
U 498     var dlg = document.querySelector('.dialog');
499     dlg.style.height = '0';
500     dlg.innerHTML = '';
501   };
502
f45e20 503   /* ---------------------   Vorlagen   ---------------------- */
cfa858 504
U 505   /*
f074f6 506    Das HTML erzeugen, das entsteht, wenn eine Vorlage mit Inhalt
U 507    gefüllt wird
508    
509    Das Füllen erfolgt asynchron, d.h. der Programmlauf geht nach dem
510    Aufruf weiter ohne auf das Laden und Füllen der Vorlage zu warten.
511    Das fertige HTML wird der Callback-Funktion übergeben
512    sobald die Vorlage geladen und gefüllt ist, unabhängig davon, wo der
513    Programmlauf zu diesem Zeitpunkt mittlerweile ist.
514    
515    vurl - URL zur Vorlagendatei
516    inhalt - die JSON-Struktur, deren Inhalt in die
517    Vorlage gefüllt werden soll
518    cb - Callback-Funktion, die gerufen wird, wenn die Vorlage gefüllt ist.
519    Dieser Callback-Funktion wird das fertige HTML übergeben
520    */
521   this.html_erzeugen = function (vurl, inhalt, cb) {
cfa858 522     var vorlage = self.cache[vurl];
f074f6 523     if (vorlage === undefined) {
cfa858 524       self.vorlage_laden_und_fuellen(vurl, inhalt, cb);
U 525     } else {
526       self.vorlage_fuellen(vurl, inhalt, cb);
527     }
528   };
529
f074f6 530   this.vorlage_fuellen = function (vurl, inhalt, cb) {
cfa858 531     cb(Mustache.render(self.cache[vurl], inhalt));
U 532   };
533
534   /*
f074f6 535    Eine Vorlage vom Server in den lokalen Speicher laden
U 536    vurl - der URL unter dem die Vorlage zu finden ist
537    inhalt - die JSON-Struktur, deren Inhalt in die
538    Vorlage gefüllt werden soll
539    cb - callback: Diese Funktion wird gerufen, wenn die Vorlage mit dem
540    Inhalt gefüllt ist
541    */
542   this.vorlage_laden_und_fuellen = function (vurl, inhalt, cb) {
cfa858 543     var xmlhttp = new XMLHttpRequest();
f074f6 544     xmlhttp.onreadystatechange = function () {
cfa858 545       if (this.readyState == 4 && this.status == 200) {
U 546         self.cache[vurl] = this.responseText;
547         self.vorlage_fuellen(vurl, inhalt, cb);
548       }
549     };
550     xmlhttp.open("GET", vurl, true);
551     xmlhttp.send();
552   };
553
554
555 }
556
f45e20 557 /* ----------- Objekte ---------------- */
U 558
559 function Ablageort(n, o, u) {
560   this.name = n;
561   this.ort = o;
562   this.url = u;
563 }
564
565 function Einstellung(k, v) {
566   this.key = k;
567   this.value = v;
568 }
569
570 function Abspieler(n, u) {
571   this.name = n;
572   this.url = u;
d6b78c 573 }