function Mediazentrale() { var self = this; var appMenu; var cache; // mustache templates var ortPfad; var mediaPfad; var katUrl; var selTitel; this.init = function () { self.mediaPfad = '/'; self.ortPfad = '/'; self.cache = new Array(); self.appMenu = new AppMenu(); self.appMenu.init( "data/menu/", "hauptmenue.json", "data/tpl/app-menu.tpl", ".west", "8em"); document.querySelector('.hamburger').addEventListener('click', function (e) { self.menue_umschalten(); }); self.addEvtListener('#mi-katalog', 'click', self.media_liste); self.addEvtListener('#mi-orte', 'click', self.ablageort_liste); self.addEvtListener('#mi-prefs', 'click', self.prefs_liste); self.addEvtListener('#mi-player', 'click', self.abspieler_liste); self.addEvtListener('#mi-listen', 'click', self.abspielliste_liste); self.addEvtListener('#mi-list', 'click', self.titel_liste); self.fusszeile_umschalten(); self.seitenleiste_umschalten(); self.dialog_unten_zeigen(); }; /* * Der StorageHandler verarbeitet Entitaeten mit z.B. * HTTP PUT Ablageort/[Name] * und erwartet dabei eine JSON-Struktur, die der Entitaet entspricht. * Beim Ablageort z.B. * private String name; * private String ort; * private String url; * * Im HTML-Formular muessen die input-Elemente mit name="..." * so genannt werden wie die Felder der Entitaet. Fuer Ablageort also * * 1) { parent = self.mediaPfad.substring(0, pos); } else { parent = '/'; } self.mediaPfad = parent; } self.media_liste(); }); }); }); } }; this.addSelectedTitel = function() { var elem = document.querySelector(".selected"); var titelName = elem.textContent; var album = elem.attributes.album.nodeValue; var interpret = elem.attributes.interpret.nodeValue; var anzName = elem.attributes.titelAnzName.nodeValue; var titel; if(self.mediaPfad.endsWith('/')) { titel = new Titel(titelName, self.mediaPfad, self.ortPfad, interpret, anzName, album); } else { titel = new Titel(titelName, self.mediaPfad + '/', self.ortPfad, interpret, anzName, album); } var plname = document.querySelector('#playlist').value; self.http_put('../api/alist/' + plname, JSON.stringify(titel), function(responseText) { self.meldung_mit_timeout(responseText, 1500); }); }; this.ablageort_liste = function() { self.reset_top_buttons(); self.http_get('../api/store/Ablageort/liste/', function (responseText) { self.vorlage_laden_und_fuellen("data/tpl/ablageort_liste.tpl", JSON.parse(responseText), function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; self.addEvtListener('.entity-eintrag', 'click', function (event) { var t = event.target; self.http_get('../api/store/Ablageort/' + t.textContent, function(responseText){ var ablageort = JSON.parse(responseText); self.ablageort_form(ablageort); }); }); //self.addEvtListener('#neu-btn', 'click', function (event) { self.addEvtListener('#top-neu-btn', 'click', function(event) { eval("self.ablageort_form" + "(this)"); }); }); }); }; this.prefs_liste = function() { self.reset_top_buttons(); self.http_get('../api/store/Einstellung/liste/', function (responseText) { self.vorlage_laden_und_fuellen("data/tpl/einstellung_liste.tpl", JSON.parse(responseText), function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; self.addEvtListener('.entity-eintrag', 'click', function (event) { var t = event.target; self.http_get('../api/store/Einstellung/' + t.textContent, function(responseText){ var einstellung = JSON.parse(responseText); self.prefs_form(einstellung); }); }); self.addEvtListener('#top-neu-btn', 'click', function(event) { eval("self.prefs_form" + "(this)"); }); }); }); }; this.abspieler_liste = function() { self.http_get('../api/store/Abspieler/liste/', function (responseText) { self.vorlage_laden_und_fuellen("data/tpl/abspieler_liste.tpl", JSON.parse(responseText), function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; self.addEvtListener('.entity-eintrag', 'click', function (event) { var t = event.target; self.http_get('../api/store/Abspieler/' + t.textContent, function(responseText){ var abspieler = JSON.parse(responseText); self.abspieler_form(abspieler); }); }); //self.addEvtListener('#neu-btn', 'click', function(event) { self.addEvtListener('#top-neu-btn', 'click', function(event) { eval("self.abspieler_form" + "(this)"); }); }); }); }; this.abspielliste_liste = function() { self.http_get('../api/store/Abspielliste/liste/', function (responseText) { self.vorlage_laden_und_fuellen("data/tpl/abspielliste_liste.tpl", JSON.parse(responseText), function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; self.addEvtListener('.entity-eintrag', 'click', function (event) { var t = event.target; self.http_get('../api/store/Abspielliste/' + t.textContent, function(responseText){ var abspielliste = JSON.parse(responseText); self.abspielliste_form(abspielliste); }); }); self.addEvtListener('#top-neu-btn', 'click', function(event) { eval("self.abspielliste_form" + "(this)"); }); }); }); }; /* -------------------- Entitaets-Formulare ------------------ */ this.abspielliste_form = function(al) { self.vorlage_laden_und_fuellen("data/tpl/form_abspielliste.tpl", al, function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; const form = document.querySelector('form'); form.addEventListener('submit', function(event) { self.handle_submit(event, al.name, '../api/store/Abspielliste/', '#abspielliste-name', function() { self.abspielliste_liste(); }); }); /* self.addEvtListener('#ok-btn', 'click', function () { var alname = document.querySelector('#abspielliste-name').value; alname = alname.replace(' ', '').replace(/[\W]+/g, ''); var abspielliste = new Abspielliste( alname ); var daten = JSON.stringify(abspielliste); //if(typeof pl === "undefined" || pl.key !== plname) { if(typeof al.name === "undefined" || al.name.length < 1) { // neu self.http_put('../api/store/Abspielliste/' + alname, daten, function (responseText) { // hier die Antwort verarbeiten self.abspielliste_auswahl_fuellen(); self.abspielliste_liste(); }); } else { // aendern self.http_put('../api/store/Abspielliste/' + al.name, daten, function (responseText) { // hier die Antwort verarbeiten self.abspielliste_auswahl_fuellen(); self.abspielliste_liste(); }); } }); */ self.addEvtListener('#cancel-btn', 'click', function () { //document.querySelector(".zentraler-inhalt").innerHTML = ''; self.abspielliste_liste(); }); self.addEvtListener('#loeschen-btn', 'click', function(event) { event.preventDefault(); self.handle_del_btn('#abspielliste-name', '../api/store/Abspielliste/', function() { self.abspielliste_auswahl_fuellen(); self.abspielliste_liste(); }); }); /* self.addEvtListener('#loeschen-btn', 'click', function() { var alname = document.querySelector('#abspielliste-name').value; var dlgdata = {"del-elem": alname}; self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.tpl', dlgdata, function() { self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen); self.addEvtListener('#ja-btn', 'click', function() { self.http_delete('../api/store/Abspielliste/' + alname, '', function (responseText) { // hier die Antwort verarbeiten self.dialog_schliessen(); //document.querySelector(".zentraler-inhalt").innerHTML = ''; self.abspielliste_auswahl_fuellen(); self.abspielliste_liste(); }); }); }); }); */ }); }; this.abspieler_form = function(pl) { self.vorlage_laden_und_fuellen("data/tpl/form_abspieler.tpl", pl, function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; const form = document.querySelector('form'); form.addEventListener('submit', function(event) { self.handle_submit(event, pl.key, '../api/store/Abspieler/', '#abspieler-name', function() { self.abspieler_liste(); }); }); /* self.addEvtListener('#ok-btn', 'click', function () { var plname = document.querySelector('#abspieler-name').value; plname = plname.replace(' ', '').replace(/[\W]+/g, ''); var abspieler = new Abspieler( plname, document.querySelector('#abspieler-url').value ); var daten = JSON.stringify(abspieler); //if(typeof pl === "undefined" || pl.key !== plname) { if(typeof pl.name === "undefined" || pl.name.length < 1) { // neu self.http_put('../api/store/Abspieler/' + plname, daten, function (responseText) { // hier die Antwort verarbeiten self.abspieler_auswahl_fuellen(); self.abspieler_liste(); }); } else { // aendern self.http_put('../api/store/Abspieler/' + pl.name, daten, function (responseText) { // hier die Antwort verarbeiten self.abspieler_auswahl_fuellen(); self.abspieler_liste(); }); } }); */ self.addEvtListener('#cancel-btn', 'click', function () { //document.querySelector(".zentraler-inhalt").innerHTML = ''; self.abspieler_liste(); }); self.addEvtListener('#loeschen-btn', 'click', function(event) { event.preventDefault(); self.handle_del_btn('#abspieler-name', '../api/store/Abspieler/', function() { self.abspieler_auswahl_fuellen(); self.abspieler_liste(); }); }); /* self.addEvtListener('#loeschen-btn', 'click', function() { var plname = document.querySelector('#abspieler-name').value; var dlgdata = {"del-elem": plname}; self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.tpl', dlgdata, function() { self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen); self.addEvtListener('#ja-btn', 'click', function() { self.http_delete('../api/store/Abspieler/' + plname, '', function (responseText) { // hier die Antwort verarbeiten self.dialog_schliessen(); //document.querySelector(".zentraler-inhalt").innerHTML = ''; self.abspieler_auswahl_fuellen(); self.abspieler_liste(); }); }); }); }); */ }); }; this.prefs_form = function(k) { self.vorlage_laden_und_fuellen("data/tpl/form_einstellung.tpl", k, function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; const form = document.querySelector('form'); form.addEventListener('submit', function(event) { self.handle_submit(event, k.key, '../api/store/Einstellung/', '#einstellung-key', function() { self.prefs_liste(); }); }); /* self.addEvtListener('#ok-btn', 'click', function () { var pkey = document.querySelector('#einstellung-key').value; pkey = pkey.replace(' ', '').replace(/[\W]+/g, ''); var pref = new Einstellung( pkey, document.querySelector('#einstellung-value').value ); var daten = JSON.stringify(pref); //if(typeof k === "undefined" || k.key !== pkey) { if(typeof k.key === "undefined" || k.key.length < 1) { // neu self.http_put('../api/store/Einstellung/' + pkey, daten, function (responseText) { // hier die Antwort verarbeiten self.prefs_liste(); }); } else { // aendern self.http_put('../api/store/Einstellung/' + k.key, daten, function (responseText) { // hier die Antwort verarbeiten self.prefs_liste(); }); } }); */ self.addEvtListener('#cancel-btn', 'click', function (event) { //document.querySelector(".zentraler-inhalt").innerHTML = ''; event.preventDefault(); self.prefs_liste(); }); self.addEvtListener('#loeschen-btn', 'click', function(event) { event.preventDefault(); self.handle_del_btn('#einstellung-key', '../api/store/Einstellung/', function() { self.prefs_liste(); }); }); /* self.addEvtListener('#loeschen-btn', 'click', function() { var pkey = document.querySelector('#einstellung-key').value; var dlgdata = {"del-elem": pkey}; self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.tpl', dlgdata, function() { self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen); self.addEvtListener('#ja-btn', 'click', function() { self.http_delete('../api/store/Einstellung/' + pkey, '', function (responseText) { // hier die Antwort verarbeiten self.dialog_schliessen(); //document.querySelector(".zentraler-inhalt").innerHTML = ''; self.prefs_liste(); }); }); }); }); */ }); }; /* * Ablageort-Formular anzeigen * * {"name":"Katalog 2","ort":"/home/ulrich/Videos","url":"/media/kat2"}: * * @param {type} ablageort der Ablageort, der bearbeitet werden soll, leer fuer neuen Ort * @returns {undefined} kein Rueckgabewert */ this.ablageort_form = function(ort) { self.vorlage_laden_und_fuellen("data/tpl/form_ablageort.tpl", ort, function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; const form = document.querySelector('form'); form.addEventListener('submit', function(event) { self.handle_submit(event, ort.name, '../api/store/Ablageort/', '#ablageort-name', function() { self.ablageort_liste(); }); }); /* self.addEvtListener('#ok-btn', 'click', function () { var aName = document.querySelector('#ablageort-name').value; aName = aName.replace(' ', '').replace(/[\W]+/g, ''); var a = new Ablageort( aName, document.querySelector('#ablageort-ort').value, document.querySelector('#ablageort-url').value ); var daten = JSON.stringify(a); //if(typeof ort === "undefined" || ort.name !== aName) { if(typeof ort.name === "undefined" || ort.name.length < 1) { // neu self.http_put('../api/store/Ablageort/' + aName, daten, function (responseText) { // hier die Antwort verarbeiten self.ablageort_liste(); }); } else { // aendern self.http_put('../api/store/Ablageort/' + ort.name, daten, function (responseText) { // hier die Antwort verarbeiten self.ablageort_liste(); }); } }); */ self.addEvtListener('#cancel-btn', 'click', function () { //document.querySelector(".zentraler-inhalt").innerHTML = ''; self.ablageort_liste(); }); self.addEvtListener('#loeschen-btn', 'click', function(event) { event.preventDefault(); self.handle_del_btn('#ablageort-name', '../api/store/Ablageort/', function() { self.ablageort_liste(); }); }); /* self.addEvtListener('#loeschen-btn', 'click', function() { var aoname = document.querySelector('#ablageort-name').value; var dlgdata = {"del-elem": aoname}; self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.tpl', dlgdata, function() { self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen); self.addEvtListener('#ja-btn', 'click', function() { self.http_delete('../api/store/Ablageort/' + aoname, '', function (responseText) { // hier die Antwort verarbeiten self.dialog_schliessen(); //document.querySelector(".zentraler-inhalt").innerHTML = ''; self.ablageort_liste(); }); }); }); }); */ }); }; /* ------------------------------- Helfer ----------------------- */ /* * existingKey: wenn die Entitaet existiert und geandert werden soll * leer, wenn neue Entitaet */ this.handle_submit = function(event, existingKey, putUrl, keySelector, cb) { event.preventDefault(); const data = new FormData(event.target); const value = Object.fromEntries(data.entries()); console.log({ value }); console.log(JSON.stringify(value)); var daten = JSON.stringify(value); var formkey = document.querySelector(keySelector).value; formkey = formkey.replace(' ', '').replace(/[\W]+/g, ''); if(typeof existingKey === "undefined" || existingKey.length < 1) { // neu self.http_put(putUrl + formkey, daten, function (responseText) { // hier die Antwort verarbeiten //self.prefs_liste(); if(typeof(cb) !== 'function') { // .. } else { cb(); } }); } else { // aendern self.http_put(putUrl + existingKey, daten, function (responseText) { // hier die Antwort verarbeiten // self.prefs_liste(); if(typeof(cb) !== 'function') { // .. } else { cb(); } }); } }; this.handle_del_btn = function(selectorKey, delUrl, cb) { var pkey = document.querySelector(selectorKey).value; var dlgdata = {"del-elem": pkey}; self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.tpl', dlgdata, function() { self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen); self.addEvtListener('#ja-btn', 'click', function(event) { console.log("loeschen geklickt."); self.http_delete(delUrl + pkey, '', function (responseText) { // hier die Antwort verarbeiten self.dialog_schliessen(); //document.querySelector(".zentraler-inhalt").innerHTML = ''; //self.prefs_liste(); if(typeof(cb) !== 'function') { // .. } else { cb(); } }); }); }); }; this.addEvtListener = function(selector, eventName, func) { document.querySelectorAll(selector).forEach(elem => { elem.addEventListener(eventName, func); }); }; this.removeClassMulti = function(selector) { document.querySelectorAll('.' + selector).forEach(elem => { elem.classList.remove(selector); }); }; /* --------------------- asynchroner HTTP Client ----------------- */ this.http_get = function (u, cb) { self.http_call('GET', u, null, cb); }; this.http_post = function (u, data, cb) { self.http_call('POST', u, data, cb); }; this.http_put = function (u, data, cb) { self.http_call('PUT', u, data, cb); }; this.http_delete = function (u, data, cb) { console.log("delete " + u); self.http_call('DELETE', u, data, cb); }; this.http_call = function (method, u, data, scallback) { var xhr = new XMLHttpRequest(); var url = u; xhr.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) { scallback(this.responseText); } }; xhr.open(method, url); if (method === 'GET') { xhr.send(); } else if (method === 'POST' || method === 'PUT' || method === 'DELETE') { xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.send(data); } }; /* ------------------------ aus App-Vorlage ------------------- */ this.menue_umschalten = function () { var ham = document.querySelector(".hamburger"); ham.classList.toggle("is-active"); // hamburger-icon umschalten self.appMenu.toggle(); // menue oeffnen/schliessen }; this.info_dialog_zeigen = function () { self.dialog_laden_und_zeigen('data/tpl/dlg-info.tpl', ''); self.menue_umschalten(); }; this.seitenleiste_umschalten = function () { var ostDiv = document.querySelector('.ost'); if (ostDiv.classList.contains('ost-open')) { ostDiv.classList.remove('ost-open'); ostDiv.style.flexBasis = '0em'; } else { ostDiv.classList.add('ost-open'); ostDiv.style.flexBasis = '6em'; } self.menue_umschalten(); }; this.fusszeile_umschalten = function () { var suedDiv = document.querySelector('.sued'); if (suedDiv.classList.contains('sued-open')) { suedDiv.classList.remove('sued-open'); suedDiv.style.height = '0'; } else { suedDiv.classList.add('sued-open'); suedDiv.style.height = '1.5em'; } self.menue_umschalten(); }; this.menu_message = function (msg) { self.meldung_mit_timeout(msg, 1500); var suedDiv = document.querySelector('.sued'); if (suedDiv.classList.contains('sued-open')) { } else { suedDiv.classList.add('sued-open'); suedDiv.style.height = '1.5em'; } self.menue_umschalten(); }; this.message_1 = function () { self.menu_message('Eine Mitteilung.'); }; this.message_2 = function () { self.menu_message('Was wir schon immer sagen wollten.'); }; this.message_3 = function (text) { self.menu_message(text); }; this.meldung_mit_timeout = function (meldung, timeout) { var s = document.querySelector('.sued'); s.classList.add('sued-open'); s.style.height = '1.5em'; s.textContent = meldung; setTimeout(function () { s.textContent = 'Bereit.'; setTimeout(function () { var suedDiv = document.querySelector('.sued'); if (suedDiv.classList.contains('sued-open')) { suedDiv.classList.remove('sued-open'); suedDiv.style.height = '0'; } }, 500); }, timeout); }; /* --------------------- Dialog-Funktionen ------------------------ */ /* Einen Dialog aus Vorlagen erzeugen vurl - URL zur Dialogvorlage msgTpl - URL mit einer Vorlage eines Mitteilungstextes (optional) */ this.dialog_laden_und_zeigen = function (vurl, msgTpl, cb) { var vorlage = self.cache[vurl]; if(vorlage === undefined) { self.http_get(vurl, function(antwort) { self.cache[vurl] = antwort; self.dialog_zeigen(vurl, msgTpl, cb); }); } else { self.dialog_zeigen(vurl, msgTpl, cb); } }; this.dialog_zeigen = function (vurl, inhalt, cb) { var dlg = document.querySelector(".dialog"); self.html_erzeugen(vurl, inhalt, function (html) { dlg.style.height = '7em'; dlg.innerHTML = html; document.querySelector('.close-btn').addEventListener('click', self.dialog_schliessen); if(typeof(cb) !== 'function') { // .. } else { cb(); } }); }; this.dialog_schliessen = function () { document.querySelector('.close-btn').removeEventListener('click', self.dialog_schliessen); var dlg = document.querySelector('.dialog'); dlg.style.height = '0'; dlg.innerHTML = ''; }; /* --------------------- Vorlagen ---------------------- */ /* Das HTML erzeugen, das entsteht, wenn eine Vorlage mit Inhalt gefüllt wird Das Füllen erfolgt asynchron, d.h. der Programmlauf geht nach dem Aufruf weiter ohne auf das Laden und Füllen der Vorlage zu warten. Das fertige HTML wird der Callback-Funktion übergeben sobald die Vorlage geladen und gefüllt ist, unabhängig davon, wo der Programmlauf zu diesem Zeitpunkt mittlerweile ist. vurl - URL zur Vorlagendatei inhalt - die JSON-Struktur, deren Inhalt in die Vorlage gefüllt werden soll cb - Callback-Funktion, die gerufen wird, wenn die Vorlage gefüllt ist. Dieser Callback-Funktion wird das fertige HTML übergeben */ this.html_erzeugen = function (vurl, inhalt, cb) { var vorlage = self.cache[vurl]; if (vorlage === undefined) { self.vorlage_laden_und_fuellen(vurl, inhalt, cb); } else { self.vorlage_fuellen(vurl, inhalt, cb); } }; this.vorlage_fuellen = function (vurl, inhalt, cb) { cb(Mustache.render(self.cache[vurl], inhalt)); }; /* Eine Vorlage vom Server in den lokalen Speicher laden vurl - der URL unter dem die Vorlage zu finden ist inhalt - die JSON-Struktur, deren Inhalt in die Vorlage gefüllt werden soll cb - callback: Diese Funktion wird gerufen, wenn die Vorlage mit dem Inhalt gefüllt ist */ this.vorlage_laden_und_fuellen = function (vurl, inhalt, cb) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { self.cache[vurl] = this.responseText; self.vorlage_fuellen(vurl, inhalt, cb); } }; xmlhttp.open("GET", vurl, true); xmlhttp.send(); }; } /* ----------- Objekte ---------------- */ function Ablageort(n, o, u) { this.name = n; this.ort = o; this.url = u; } function Einstellung(k, v) { this.key = k; this.value = v; } function Abspieler(n, u) { this.name = n; this.url = u; } function Abspielliste(n) { this.name = n; } function Titel(n, p, u, i, t, a) { this.katalogUrl = u; this.pfad = p; this.name = n; this.interpret = i; this.titelAnzName = t; this.album = a; }