function Mediazentrale() { var self = this; var appMenu; var cache; // mustache templates var ortPfad; var mediaPfad; //var katUrl; //var selTitel; var katName; var playingIndex; var audioCtx; var playState; // 'pause' oder 'play' oder 'stop' var audioElem; 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.txt", ".west", "6em"); 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.addEvtListener('#mi-live', 'click', self.livestream_liste); self.addEvtListener('#mi-devices', 'click', self.geraet_liste); self.addEvtListener('#mi-switch', 'click', self.geraet_schalt_liste); self.fusszeile_umschalten(); self.seitenleiste_umschalten(); self.dialog_unten_zeigen(); }; /* ---------------- Entitaets-Listen ----------------- */ this.livestream_selection = function() { document.querySelector('.breadcrumb-behaelter').textContent = ''; document.querySelector('.bereich-name').textContent = 'Livestream-Auswahl'; self.http_get('api/store/Livestream/liste/', function(responseText) { self.html_erzeugen("data/tpl/livestream_liste.txt", JSON.parse(responseText), function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; self.addEvtListener('.entity-eintrag', 'click', function (event) { var t = event.target; self.removeClassMulti('selected'); t.classList.add('selected'); }); }); }); }; // auf der obersten Ebene werden die Kataloge angezeigt, // darunter der Inhalt des aktuellen Pfades this.media_liste = function() { self.reset_top_buttons(); //console.log("ortPfad: " + self.ortPfad + ", mediaPfad: " + self.mediaPfad); document.querySelector('.bereich-name').textContent = ''; if(self.ortPfad === '/') { var bb = document.querySelector('.breadcrumb-behaelter'); bb.textContent = "Kataloge"; // Kataloge listen self.http_get('api/store/Ablageort/liste/', function (responseText) { //document.querySelector('#top-up-btn').removeEventListener('click', self.media_liste_herauf); self.html_erzeugen("data/tpl/katalog_root_liste.txt", JSON.parse(responseText), function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; self.addEvtListener('.entity-eintrag', 'click', function (event) { var t = event.target; self.katName = t.textContent; if(self.katName !== "Livestreams") { self.http_get('api/store/Ablageort/' + t.textContent, function(responseText) { var ablageort = JSON.parse(responseText); self.ortPfad = ablageort.url; self.media_liste(); }); } else { self.livestream_selection(); } }); }); }); } else { var bb = document.querySelector('.breadcrumb-behaelter'); var brPfad = self.katName + self.mediaPfad; var breadcrumbs = brPfad.split('/'); var brLinks = ""; var brLinkPfad = ""; for(var index = 0; index < breadcrumbs.length; index++) { // breadcrumbs[index] if(index === 0) { brLinkPfad = ''; } else { brLinkPfad = brLinkPfad + '/' + breadcrumbs[index]; } brLinks = brLinks + "" + breadcrumbs[index] + ""; //console.log(' breadcrumbs[' + index + ']: ' + breadcrumbs[index]); } bb.innerHTML = brLinks; self.addEvtListener('.breadcrumb-link', 'click', function(event) { //console.log(event.target.attributes.brlink.nodeValue); var neuerPfad = event.target.attributes.brlink.nodeValue; self.mediaPfad = neuerPfad; self.media_liste(); }); //var url = '/tango' + self.ortPfad + self.mediaPfad; var url = '.' + self.ortPfad + self.mediaPfad; if(!url.endsWith('/')) { url = url + '/'; } self.http_get(url, function(responseText) { self.html_erzeugen("data/tpl/katalog_inhalt_liste.txt", JSON.parse(responseText), function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; self.addEvtListener('.entity-eintrag', 'click', function (event) { var t = event.target; var tx = t.textContent; if(t.classList.contains("entity-typ-folder")) { if(self.mediaPfad.endsWith('/')) { self.mediaPfad = self.mediaPfad + tx; } else { self.mediaPfad = self.mediaPfad + '/' + tx; } self.media_liste(); } else { if(t.classList.contains('selected')) { t.classList.add('added-to-playlist'); self.titelDazu(); } else { self.removeClassMulti('selected'); t.classList.add('selected'); } //self.selTitel = new Titel(t.textContent, self.ortPfad); } }); self.addEvtListener('#top-up-btn', 'click', function(event) { if(self.mediaPfad === '/') { self.ortPfad = '/'; } else { var pos = self.mediaPfad.lastIndexOf('/'); var parent; if(pos > 1) { parent = self.mediaPfad.substring(0, pos); } else { parent = '/'; } self.mediaPfad = parent; } self.media_liste(); }); }); }); } }; this.ein_aus_btn = function() { self.addEvtListener('#ein-aus-btn', 'click', function (event) { var geraetName = event.target.attributes.gname.nodeValue; var nameElem = event.target.parentNode.querySelector('.schalt-geraet-name'); if(nameElem.classList.contains('schalt-geraet-true')) { // ausschalten self.http_get('api/gstrg/geraet/' + geraetName + "/aus", function(responseText) { // console.log(responseText); self.geraet_schalt_liste(); }); } else { // einschalten self.http_get('api/gstrg/geraet/' + geraetName + "/ein", function(responseText) { // console.log(responseText); self.geraet_schalt_liste(); }); } }); }; this.geraet_schalt_liste = function() { /*self.entitaet_liste('Geräte schalten','../api/store/Geraet/listealles/', "data/tpl/geraet_schalt_liste.txt", '../api/store/Geraet/', "self.form_geraet_status", function(responseText) {*/ self.entitaet_liste('Geräte schalten','api/store/Geraet/listealles/', "data/tpl/geraet_schalt_liste.txt", 'api/store/Geraet/', "", function(responseText) { //var geraet = JSON.parse(responseText); //self.geraet_status_form(geraet); }, self.ein_aus_btn); }; this.geraet_liste = function() { self.entitaet_liste('Geräte','api/store/Geraet/liste/', "data/tpl/geraet_liste.txt", 'api/store/Geraet/', "self.geraet_form", function(responseText) { var geraet = JSON.parse(responseText); self.geraet_form(geraet); }); }; this.ablageort_liste = function() { self.entitaet_liste('Kataloge','api/store/Ablageort/liste/', "data/tpl/ablageort_liste.txt", 'api/store/Ablageort/', "self.ablageort_form", function(responseText) { var ablageort = JSON.parse(responseText); self.ablageort_form(ablageort); }); }; this.prefs_liste = function() { self.entitaet_liste('Einstellungen','api/store/Einstellung/liste/', "data/tpl/einstellung_liste.txt", 'api/store/Einstellung/', "self.prefs_form", function(responseText) { var einstellung = JSON.parse(responseText); self.prefs_form(einstellung); }); }; this.abspieler_liste = function() { self.entitaet_liste('Abspieler','api/store/Abspieler/liste/', "data/tpl/abspieler_liste.txt", 'api/store/Abspieler/', "self.abspieler_form", function(responseText) { var abspieler = JSON.parse(responseText); self.abspieler_form(abspieler); }); }; this.livestream_liste = function() { self.entitaet_liste('Livestreams','api/store/Livestream/liste/', "data/tpl/livestream_liste.txt", 'api/store/Livestream/', "self.livestream_form", function(responseText) { var livestream = JSON.parse(responseText); self.livestream_form(livestream); }); }; this.abspielliste_liste = function() { self.entitaet_liste('Abspielliste','api/store/Abspielliste/liste/', "data/tpl/abspielliste_liste.txt", 'api/store/Abspielliste/', "self.abspielliste_form", function(responseText) { //console.log("responseTest: '" + responseText + "'"); var abspielliste = JSON.parse(responseText); self.abspielliste_form(abspielliste); }); }; /* -------------------- Entitaets-Formulare ------------------ */ this.abspielliste_form = function(al) { self.entitaet_form('Abspielliste', al, al.name, "data/tpl/form_abspielliste.txt", 'api/store/Abspielliste/', '#abspielliste-name', 'name', function(event) { if(event !== undefined) { event.preventDefault(); } self.abspielliste_auswahl_fuellen(); self.abspielliste_liste(); }); }; this.abspieler_form = function(pl) { self.entitaet_form('Abspieler', pl, pl.key, "data/tpl/form_abspieler.txt", 'api/store/Abspieler/', '#abspieler-name', 'name', function() { self.abspieler_auswahl_fuellen(); self.abspieler_liste(); }); }; this.livestream_form = function(ls) { self.entitaet_form('Livestream', ls, ls.name, "data/tpl/form_livestream.txt", 'api/store/Livestream/', '#livestream-name', 'name', function() { self.livestream_liste(); }); }; this.geraet_form = function(ge) { self.entitaet_form('Gerät', ge, ge.name, "data/tpl/form_geraet.txt", 'api/store/Geraet/', '#geraet-name', 'name', function() { self.geraet_liste(); }); }; this.geraet_status_form = function(ge) { self.entitaet_form('Gerät', ge, ge.name, "data/tpl/form_geraet_status.txt", 'api/store/Geraet/', '#geraet-name', 'name', function() { self.geraet_schalt_liste(); }); }; this.prefs_form = function(k) { self.entitaet_form('Einstellung', k, k.key, "data/tpl/form_einstellung.txt", 'api/store/Einstellung/', '#einstellung-key', 'key', function() { 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.entitaet_form('Katalog', ort, ort.name, "data/tpl/form_ablageort.txt", 'api/store/Ablageort/', '#ablageort-name', 'name', function() { self.ablageort_liste(); }); }; /* ------------------------------- UI-Dynamik ----------------------- */ self.reset_top_buttons = function() { self.html_erzeugen("data/tpl/top_btns.txt", '', function (html) { document.querySelector(".top-btns").innerHTML = html; }); }; this.abspieler_auswahl_fuellen = function() { self.http_get('api/store/Abspieler/liste/', function (responseText) { self.html_erzeugen("data/tpl/abs_sel.txt", JSON.parse(responseText), function (html) { document.querySelector(".abs-sel").innerHTML = html; }); }); }; this.abspielliste_auswahl_fuellen = function() { self.http_get('api/store/Abspielliste/', function (responseText) { self.html_erzeugen("data/tpl/pl_sel.txt", JSON.parse(responseText), function (html) { document.querySelector(".pl-sel").innerHTML = html; self.addEvtListener('#playlist', 'change', function() { self.titel_liste(); }); }); }); }; /* Unterer Einblendbereich */ this.dialog_unten_zeigen = function() { self.html_erzeugen("data/tpl/ctrl.txt", "", function (html) { var dlg = document.querySelector(".dialog-unten"); //dlg.style.height = '10em'; dlg.innerHTML = html; self.abspieler_auswahl_fuellen(); self.abspielliste_auswahl_fuellen(); self.addEvtListener('#dazu-btn', 'click', self.titelDazu); self.addEvtListener('#play-btn', 'click', self.play); self.addEvtListener('#stop-btn', 'click', function() { self.kommando('stop'); }); self.addEvtListener('#pause-btn', 'click', function() { self.kommando('pause'); }); self.addEvtListener('#weiter-btn', 'click', self.weiter); self.addEvtListener('#hier-btn', 'click', self.hier_spielen); /* */ self.addEvtListener('#weg-btn', 'click', self.titelWeg); self.addEvtListener('#leeren-btn', 'click', self.alleTitelEntfernen); self.addEvtListener('#media-btn', 'click', self.media_liste); self.addEvtListener('#plst-btn', 'click', self.titel_liste); self.addEvtListener('#live-btn', 'click', self.livestream_selection); self.addEvtListener('#switch-btn', 'click', self.geraet_schalt_liste); self.addEvtListener('#voldn-btn', 'click', function() { self.kommando('voldn'); }); self.addEvtListener('#volup-btn', 'click', function() { self.kommando('volup'); }); self.media_liste(); }); }; /* Titel einer Abspielliste */ this.titel_liste = function() { self.reset_top_buttons(); var plname = document.querySelector('#playlist').value; document.querySelector('.bereich-name').textContent = 'Abspielliste ' + plname; var bb = document.querySelector('.breadcrumb-behaelter'); bb.textContent = ""; self.http_get('api/alist/' + plname, function (responseText) { self.html_erzeugen("data/tpl/titel_liste.txt", JSON.parse(responseText), function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; self.addEvtListener('.entity-eintrag', 'click', function (event) { var t = event.target; self.removeClassMulti('selected'); t.classList.add('selected'); }); self.addEvtListener('.entity-eintrag', 'dragstart', function (e) { //console.log("drag started"); e.dataTransfer.setData('text/plain', e.target.textContent); setTimeout(() => { e.target.classList.add('hide'); e.target.classList.add('drag-elem'); }, 0); }); self.addEvtListener('.entity-eintrag', 'dragenter', function (e) { e.preventDefault(); //console.log("drag enter"); e.target.classList.add('drag-over'); }); self.addEvtListener('.entity-eintrag', 'dragover', function (e) { e.preventDefault(); //console.log("drag over"); e.target.classList.add('drag-over'); }); self.addEvtListener('.entity-eintrag', 'dragleave', function (e) { //console.log("drag leave"); e.target.classList.remove('drag-over'); }); self.addEvtListener('.entity-eintrag', 'drop', function (e) { e.preventDefault(); //console.log("drop"); //console.log("index: " + self.getIndexBySelector('drag-over')); const pos = self.getIndexBySelector('drag-elem'); const zielPos = self.getIndexBySelector('drag-over'); const titeltext = e.dataTransfer.getData('text/plain'); const draggable = document.querySelector(".drag-elem"); draggable.classList.remove("drag-elem"); e.target.classList.remove('drag-over'); var plname = document.querySelector('#playlist').value; self.http_put('api/alist/' + plname + "/" + pos + "/" + zielPos, '', function(responseText) { //self.meldung_mit_timeout(responseText, 1500); }); ulElem = draggable.parentElement; ulElem.removeChild(draggable); e.target.insertAdjacentElement('beforebegin', draggable); draggable.classList.remove('hide'); }); }); }); }; /* ------------- Media-Steuerung ------------------------- */ this.play = function() { var bereichName = document.querySelector('.bereich-name').textContent; if(bereichName === '') { var titel = self.titelErmitteln(document.querySelector(".selected")); var playername = document.querySelector('#abspieler').value; console.log('plname: ' + playername + ' url: ' + titel.katalogUrl + titel.pfad + titel.name); self.http_post('api/strg/' + playername + '/play/titel', JSON.stringify(titel), function(responseText) { self.meldung_mit_timeout(responseText, 1500); }); } else if(bereichName === 'Livestream-Auswahl') { var streamName = document.querySelector(".selected").textContent; var playername = document.querySelector('#abspieler').value; var stream = new Livestream(streamName, '-'); self.http_post('api/strg/' + playername + '/play/stream', JSON.stringify(stream), function(responseText) { self.meldung_mit_timeout(responseText, 1500); }); } else { var abs = document.querySelector('#abspieler').value; var lst = document.querySelector('#playlist').value; console.log( "play playlist.value: " + document.querySelector('#playlist').value + ", abspieler.value: " + document.querySelector('#abspieler').value); self.http_get('api/strg/' + abs + '/play/liste/' + lst, function(responseText) { self.meldung_mit_timeout(responseText, 1500); }); } }; this.weiter = function() { var bereichName = document.querySelector('.bereich-name').textContent; if(bereichName === '') { var titel = self.titelErmitteln(document.querySelector(".selected")); var playername = document.querySelector('#abspieler').value; console.log('plname: ' + playername + ' url: ' + titel.katalogUrl + titel.pfad + titel.name); self.http_post('api/strg/' + playername + '/weiter/titel', JSON.stringify(titel), function(responseText) { self.meldung_mit_timeout(responseText, 1500); }); } }; this.kommando = function(kommando) { console.log(kommando); if(self.playingIndex > -1) { //const audioElements = document.querySelectorAll('.entity-eintrag'); //const audioElements = document.querySelectorAll("audio"); //const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); //const track = self.audioCtx.createMediaElementSource(audioElements[self.playingIndex]); //track.connect(self.audioCtx.destination); if(kommando === 'stop') { self.audioElem.pause(); self.audioElem.currentTime = 0; self.audioElem.removeEventListener("ended", self.nextTrack); self.playingIndex = -1; self.playState = 'stop'; } else if(kommando === 'pause') { if(self.playState === 'pause') { self.playState = 'play'; self.audioElem.play(); } else if(self.playState === 'play') { self.playState = 'pause'; self.audioElem.pause(); } } else if(kommando === 'play') { if(self.playingIndex < 0) { self.nextTrack(); } else { self.audioElem.play(); } self.playState = 'play'; } } else { var abs = document.querySelector('#abspieler').value; self.http_get('api/strg/' + abs + '/' + kommando, function(responseText) { if(kommando !== 'volup' && kommando !== 'voldn') { self.meldung_mit_timeout(responseText, 1500); } }); } }; this.hier_spielen = function() { var url; // den Host noch vom Server abrufen und den nachfolgenden Code ersetzen var host = 'http://' + window.location.host + '/tango'; console.log('host: ' + host); var bereichName = document.querySelector('.bereich-name').textContent; if(bereichName === '') { var titel = self.titelErmitteln(document.querySelector(".selected")); //var playername = document.querySelector('#abspieler').value; console.log(' url: ' + titel.katalogUrl + titel.pfad + titel.name); //self.http_post('../api/strg/' + playername + '/titel', JSON.stringify(titel), function(responseText) { // self.meldung_mit_timeout(responseText, 1500); //}); url = host + titel.katalogUrl + titel.pfad + titel.name; window.open(url); } else if(bereichName === 'Livestream-Auswahl') { var streamName = document.querySelector(".selected").textContent; // hier den Stream-URL abrufen //GET /mz/api/store/[typname]/[name] self.http_get('api/store/Livestream/' + streamName, function(responseText) { var stream = JSON.parse(responseText); url = stream.url; window.open(url); }); } else { var lst = document.querySelector('#playlist').value; console.log( "play playlist.value: " + document.querySelector('#playlist').value + ", abspieler.value: " + document.querySelector('#abspieler').value); // hier noch URL fuer Stream der Abspielliste abrufen // Es muss auch noch die Funktion auf dem Server gabut werden, die // eine Abspielliste als Stream liefert //url = 'Stream fuer Abspielliste ' + lst + ' noch nicht gebaut.'; //self.hier_spielen_liste(); self.playingIndex = -1; self.nextTrack(); } //console.log('url: ' + url); //window.open(url); }; this.hier_spielen_liste = function() { const elements = document.querySelectorAll('.entity-eintrag'); //var i = 0; //var ersterTitel; //elements.forEach(function (element) { // const attr = element.attributes; // var titel = host + attr.getNamedItem('data-kat').value + // attr.getNamedItem('data-pfad').value + attr.getNamedItem('data-datei').value; // console.log(titel); // + element.data-pfad + element.data-datei); // if(i++ === 0) { // ersterTitel = titel; // } //}); // Web Audio API Player ab hier //const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); //const AudioContext = window.AudioContext || window.webkitAudioContext; //const audioContext = new AudioContext(); // get the audio elements self.playingIndex = -1; //const audioElements = document.querySelectorAll("audio"); // pass it into the audio context //const track = audioCtx.createMediaElementSource(audioElements[self.playingIndex]); //track.connect(audioCtx.destination); //audioElements[self.playingIndex].addEventListener( // "ended", // () => { // // }, // false //); //audioElements[self.playingIndex].play(); self.nextTrack(); }; this.nextTrack = function() { // ... // mySound = new Audio('sound.mp3'); // mySound.play() // const audioElements = document.querySelectorAll("audio"); const audioElements = document.querySelectorAll('.entity-eintrag'); if(self.playingIndex > -1) { self.audioElem.removeEventListener("ended", self.nextTrack); //audioElements[self.playingIndex].removeEventListener("ended", self.nextTrack); //const element = audioElements[self.playingIndex]; //const attr = element.attributes; //var titel = host + attr.getNamedItem('data-kat').value + // attr.getNamedItem('data-pfad').value + attr.getNamedItem('data-datei').value; //const titelElem = new Audio(titel); } // self.playingIndex++; if(self.playingIndex < audioElements.length) { //const element = audioElements[self.playingIndex]; //const attr = element.attributes; //var titel = host + attr.getNamedItem('data-kat').value + // attr.getNamedItem('data-pfad').value + attr.getNamedItem('data-datei').value; const titel = self.getTitelFromAudioElement(audioElements, self.playingIndex); console.log("titel: " + titel); //const titelElem = new Audio(titel); self.audioElem = new Audio(titel); self.audioElem.addEventListener("ended", self.nextTrack); self.audioCtx = new (window.AudioContext || window.webkitAudioContext)(); const track = self.audioCtx.createMediaElementSource(self.audioElem); track.connect(self.audioCtx.destination); self.audioElem.play(); self.playState = 'play'; //const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); } }; this.getTitelFromAudioElement = function(audioElements, index) { //const audioElements = document.querySelectorAll('.entity-eintrag'); const host = 'http://' + window.location.host + '/tango'; const element = audioElements[index]; const attr = element.attributes; const titel = host + attr.getNamedItem('data-kat').value + attr.getNamedItem('data-pfad').value + attr.getNamedItem('data-datei').value; return titel; }; this.gehe_zu_dialog_zeigen = function () { self.dialog_laden_und_zeigen('data/tpl/gehe-zu.txt', '', function(){ const form = document.querySelector('form'); form.addEventListener('submit', function(event) { // hier gehe zu realisieren event.preventDefault(); const data = new FormData(event.target); const value = Object.fromEntries(data.entries()); var daten = JSON.stringify(value); console.log('gehe zu mit ' + daten); var sekunden = (value['std'] * 3600) + (value['min'] * 60) + (value['sek'] * 1); if(value['richtung'] === 'zurueck') { sekunden *= -1; } console.log('sekunden: ' + sekunden); self.dialog_schliessen(); // HTTP GET /mz/api/strg/abspieler/seek/[sekunden] self.kommando('seek/' + sekunden); }); self.addEvtListener('#cancel-btn', 'click', function(event) { self.dialog_schliessen(); }); self.menue_umschalten(); }); }; /* ------------- Verwaltungsfunktionen Abspielliste -------------------- */ self.alleTitelEntfernen = function() { var plname = document.querySelector('#playlist').value; self.http_delete('api/alist/' + plname + '/alle', '', function(responseText) { // DELETE http://localhost:9090/mz/api/alist/liste1/0 //self.meldung_mit_timeout(responseText, 1500); self.titel_liste(); }); }; /* * { * "katalogUrl":"/media", * "pfad":"/Musik/B/Bay-City-Rollers/Original-Album-Classics/3/", * "name":"3-37-Love-Is.mp3", * "interpret":"Bay City Rollers", * "titelAnzName":"Love Is", * "album":"Original Album Classics" * } * @returns {undefined} */ this.titelDazu = function() { var titel = self.titelErmitteln(document.querySelector(".selected")); //var titelName = elem.textContent; /* var titelName = elem.attributes.dateiName.nodeValue; 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.titelWeg = function() { //var elem = document.querySelector(".selected"); //var parentElem = elem.parentNode; //console.log("elem: " + elem.nodeName + ", parent: " + parentElem.nodeName + ", len: " + parentElem.childNodes.length); //var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente //console.log("liElems.anz: " + liElems.length); //var gefunden = false; //for(var i = 0; i < liElems.length && !gefunden; i++) { //console.log(liElems.item(i).textContent); //if(liElems.item(i).classList.contains("selected")) { //gefunden = true; //var index = i; //console.log(elem.textContent + ' hat Index ' + i); //} //} const index = self.getIndexBySelector("selected"); // /mz/api/alist/[pl-name]/[nr] var plname = document.querySelector('#playlist').value; self.http_delete('api/alist/' + plname + '/' + index,'', function(responseText) { // DELETE http://localhost:9090/mz/api/alist/liste1/0 //self.meldung_mit_timeout(responseText, 1500); self.titel_liste(); }); }; this.getIndexBySelector = function(selector) { var qSel = '.' + selector; var elem = document.querySelector(qSel); var parentElem = elem.parentNode; //console.log("elem: " + elem.nodeName + ", parent: " + parentElem.nodeName + ", len: " + parentElem.childNodes.length); var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente //console.log("liElems.anz: " + liElems.length); var gefunden = false; var index = -1; for(var i = 0; i < liElems.length && !gefunden; i++) { //console.log(liElems.item(i).textContent); if(liElems.item(i).classList.contains(selector)) { gefunden = true; index = i; //console.log(elem.textContent + ' hat Index ' + i); } } return index; }; /* ------------- Helfer fuer Entitaets-Formulare ----------------------- */ /* * url: '../api/store/Ablageort/liste/' * tpl: "data/tpl/ablageort_liste.txt" * storeUrl: '../api/store/Ablageort/' * formFunc: "self.ablageort_form" * cb: etwas wie * function(responseText){ * var ablageort = JSON.parse(responseText); * self.ablageort_form(ablageort); * }); */ this.entitaet_liste = function(bname, listUrl, tpl, storeUrl, formFunc, cb, customListCode) { self.reset_top_buttons(); document.querySelector('.bereich-name').textContent = bname; var bb = document.querySelector('.breadcrumb-behaelter'); bb.textContent = ""; self.http_get(listUrl, function (responseText) { self.html_erzeugen(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(storeUrl + t.textContent, cb); }); //self.addEvtListener('#neu-btn', 'click', function (event) { self.addEvtListener('#top-neu-btn', 'click', function(event) { eval(formFunc + "(this)"); }); if(typeof(customListCode) !== 'function') { // .. } else { customListCode(); } }); }); }; /* * dat: gefuelltes Datenobjekt bei Aenderung * key: der alte schluesselbegriff bei Aenderung (z.B. al.name) * tpl: "data/tpl/form_abspielliste.txt" * url: '../api/store/Abspielliste/' * selector: '#abspielliste-name' * cbOk: etwas wie * function() { * self.abspielliste_auswahl_fuellen(); * self.abspielliste_liste(); * }); * delSelector: '#abspielliste-name' * cbDel: etwas wie * function() { * self.abspielliste_auswahl_fuellen(); * self.abspielliste_liste(); * }); */ this.entitaet_form = function(bname, dat, key, tpl, url, selector, keyname, cb) { document.querySelector('.bereich-name').textContent = bname; self.html_erzeugen(tpl, dat, function (html) { document.querySelector(".zentraler-inhalt").innerHTML = html; const form = document.querySelector('form'); form.addEventListener('submit', function(event) { self.handle_submit(event, key, url, selector, keyname, cb); }); self.addEvtListener('#cancel-btn', 'click', cb); self.addEvtListener('#loeschen-btn', 'click', function(event) { event.preventDefault(); self.handle_del_btn(selector, url, cb); }); }); }; /* * existingKey: wenn die Entitaet existiert und geandert werden soll * leer, wenn neue Entitaet */ this.handle_submit = function(event, existingKey, putUrl, keySelector, keyname, cb) { event.preventDefault(); const data = new FormData(event.target); const value = Object.fromEntries(data.entries()); var formkey = document.querySelector(keySelector).value; formkey = formkey.replace(' ', ''); formkey = formkey.replace(/[\W]+/g, ''); value[keyname] = formkey; var daten = JSON.stringify(value); if(typeof existingKey === "undefined" || existingKey.length < 1) { // neu self.http_put(putUrl + formkey, daten, function (responseText) { if(typeof(cb) !== 'function') { // .. } else { cb(); } }); } else { // aendern self.http_put(putUrl + existingKey, daten, function (responseText) { 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.txt', 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) { self.dialog_schliessen(); if(typeof(cb) !== 'function') { // .. } else { cb(); } }); }); }); }; /* ------------------ sonstige Helfer ----------------------- */ 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); }); }; self.titelErmitteln = function(elem) { var titelName = elem.attributes.dateiName.nodeValue; 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); } return titel; }; /* --------------------- 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, callurl, data, scallback) { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) { scallback(this.responseText); } }; xhr.open(method, callurl); 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.txt', ''); 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 Livestream(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; } function Geraet(n, e, a, s, st) { this.name = n; this.einUrl = e; this.ausUrl = a; this.statusUrl = s; this.status = st; }