Files
xTeVe/ts/popup.ts
T
nathan 014a3b04d2
continuous-integration/drone/push Build is passing
Phase 5b and Phase 6: TypeScript restructure, jsdom tests, regex filters and per-playlist buffer in the UI
TypeScript:
- menu_ts.ts split into menu.ts, content.ts, popup.ts and xmltv.ts; the
  other files drop their _ts suffix. Bundle order fixed in ts/tsconfig.json.
- All 94 string event handlers (setAttribute("onclick", "javascript: ..."))
  replaced with addEventListener closures. changeButtonAction, which
  rewrote an onclick attribute from select values, is gone.
- Settings rows are generated from one SETTINGS_FIELDS table instead of
  ~20 copy-pasted blocks; rendered HTML is byte-identical to before.
  saveSettings now serialises password inputs, so a changed Plex token is
  actually sent (the server treats the mask as unchanged).
- createLayout rebuilds the menu list only when the set of visible items
  changes, so focus in the menu survives a refresh.
- announce()/alertUser(): alerts are mirrored into an aria-live region.
- Filter popup offers a third type, Regular Expression (regex-filter), and
  the filter table labels it. Playlist popups get a Buffer select
  (default / none / xTeVe / FFmpeg / VLC) saved as the playlist's
  "buffer" parameter; the tuner field stays editable when the
  playlist's own buffer is active.

Tests: tests/ holds 27 jsdom tests (Node's built-in runner, jsdom pinned)
that load the built bundle with a fixture server payload: menu visibility
rules, mapping table renders names as text, settings panel fields, popup
flows, sorting, bulk select, layout refresh keeps nodes, live region,
regex option, buffer select. npm test runs in the Drone webui-check step.
README-DEV documents the layout and the test workflow.
2026-09-26 13:39:35 +10:00

1172 lines
35 KiB
TypeScript

class PopupWindow {
DocumentID:string = "popup-custom"
InteractionID:string = "interaction"
doc = document.getElementById(this.DocumentID)
createTitle(title:string):any {
var td = document.createElement("TD")
td.className = "left"
td.innerHTML = title + ":"
return td
}
createContent(element):any {
var td = document.createElement("TD")
td.appendChild(element)
return td
}
createInteraction():any {
var div = document.createElement("div")
div.setAttribute("id", "popup-interaction")
div.className = "interaction"
this.doc.appendChild(div)
}
}
class PopupContent extends PopupWindow{
table = document.createElement("TABLE")
createHeadline(headline):void {
this.doc.innerHTML = ""
var element = document.createElement("H3")
element.innerHTML = headline.toUpperCase()
this.doc.appendChild(element)
// Tabelle erstellen
this.table = document.createElement("TABLE")
this.doc.appendChild(this.table)
}
appendRow(title:string, element:any):void {
var tr = document.createElement("TR")
// Bezeichnung
if (title.length != 0) {
tr.appendChild(this.createTitle(title))
}
// Content
tr.appendChild(this.createContent(element))
this.table.appendChild(tr)
}
createInput(type:string, name:string, value:string):any {
var input = document.createElement("INPUT")
if (value == undefined) {
value = ""
}
input.setAttribute("type", type)
input.setAttribute("name", name)
input.setAttribute("value", value)
return input
}
createCheckbox(name:string):any {
var input = document.createElement("INPUT")
input.setAttribute("type", "checkbox")
input.setAttribute("name", name)
return input
}
createSelect(text:string[], values:string[], set:string, dbKey:string):any {
var select = document.createElement("SELECT")
select.setAttribute("name", dbKey)
for (let i = 0; i < text.length; i++) {
var option = document.createElement("OPTION")
option.setAttribute("value", values[i])
option.innerText = text[i]
select.appendChild(option)
}
if(set != "") {
(select as HTMLSelectElement).value = set
}
if (set == undefined) {
(select as HTMLSelectElement).value = values[0]
}
return select
}
selectOption(select:any, value:string):any {
//select.selectedOptions = value
var s:HTMLSelectElement = (select as HTMLSelectElement)
s.options[s.selectedIndex].value = value
return select
}
// isHTML must only be true for static text written in the source; never for data.
description(value:string, isHTML:boolean = false):any {
var tr = document.createElement("TR")
var td = document.createElement("TD")
var span = document.createElement("PRE")
if (isHTML) {
span.innerHTML = value
} else {
span.textContent = value
}
tr.appendChild(td)
tr.appendChild(this.createContent(span))
this.table.appendChild(tr)
}
// Interaktion
addInteraction(element:any) {
var interaction = document.getElementById("popup-interaction")
interaction.appendChild(element)
}
}
// Buffer choices a playlist can make; "default" means the global setting.
const PLAYLIST_BUFFER_OPTIONS = [
{ text: "Default (global setting)", value: "default" },
{ text: "No buffer (pass the URL through)", value: "-" },
{ text: "xTeVe", value: "xteve" },
{ text: "FFmpeg", value: "ffmpeg" },
{ text: "VLC", value: "vlc" }
]
function createBufferSelect(content:PopupContent, data:object):HTMLSelectElement {
var text:string[] = PLAYLIST_BUFFER_OPTIONS.map(function(o) { return o.text })
var values:string[] = PLAYLIST_BUFFER_OPTIONS.map(function(o) { return o.value })
var current:string = data["buffer"]
if (values.indexOf(current) == -1) {
current = "default"
}
return content.createSelect(text, values, current, "buffer")
}
// playlistBufferActive: is a buffer in use for this playlist (its own choice,
// or the global setting when it has none)? Decides whether the tuner count
// can be edited.
function playlistBufferActive(data:object):boolean {
var own:string = data["buffer"]
if (own != undefined && own != "default" && own != "") {
return own != "-"
}
return SERVER["settings"]["buffer"] != "-"
}
function openPopUp(dataType, element?) {
var data:object = new Object();
var id:any
switch (element) {
case undefined:
switch (dataType) {
case "group-title":
if (id == undefined) {
id = -1
}
data = getLocalData("filter", id)
data["type"] = "group-title"
break;
case "custom-filter":
if (id == undefined) {
id = -1
}
data = getLocalData("filter", id)
data["type"] = "custom-filter"
break;
case "regex-filter":
if (id == undefined) {
id = -1
}
data = getLocalData("filter", id)
data["type"] = "regex-filter"
break;
default:
data["id.provider"] = "-"
data["type"] = dataType
id = "-"
break;
}
break
default:
id = element.id
data = getLocalData(dataType, id)
break;
}
var content:PopupContent = new PopupContent()
switch (dataType) {
case "playlist":
content.createHeadline("Playlist type")
// Type
var text:string[] = ["M3U", "HDHomeRun"]
var values:string[] = ["m3u", "hdhr"]
var select = content.createSelect(text, values, "", "type")
select.setAttribute("id", "type")
content.appendRow("Type", select)
const typeSelect:HTMLSelectElement = select
// Interaktion
content.createInteraction()
// Abbrechen
var input = content.createInput("button", "cancel", "Cancel")
input.addEventListener("click", function() { showElement("popup", false) })
content.addInteraction(input)
// Weiter
var input = content.createInput("button", "next", "Next")
input.addEventListener("click", function() { openPopUp(typeSelect.value) })
input.setAttribute("id", 'next')
content.addInteraction(input)
break
case "m3u":
content.createHeadline(dataType)
// Name
var dbKey:string = "name"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Playlist name")
content.appendRow("Name", input)
// Beschreibung
var dbKey:string = "description"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Description")
content.appendRow("Description", input)
// URL
var dbKey:string = "file.source"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "File path or URL of the M3U")
content.appendRow("M3U File", input)
// Buffer (per playlist override of the global setting)
var bufferSelect = createBufferSelect(content, data)
content.appendRow("Buffer", bufferSelect)
// Tuner
if (playlistBufferActive(data)) {
var text:string[] = new Array()
var values:string[] = new Array()
for (var i = 1; i <= 100; i++) {
text.push(i.toString())
values.push(i.toString())
}
var dbKey:string = "tuner"
var select = content.createSelect(text, values, data[dbKey], dbKey)
content.appendRow("Tuner / Streams", select)
} else {
var dbKey:string = "tuner"
if (data[dbKey] == undefined) {
data[dbKey] = 1
}
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("readonly", "true")
input.className = "notAvailable"
content.appendRow("Tuner / Streams", input)
}
content.description("Number of parallel connections that can be established to the provider. <br>Only available with activated buffer.<br>New settings will only be applied after quitting all streams.", true)
// Interaktion
content.createInteraction()
// Löschen
if (data["id.provider"]!= "-") {
var input = content.createInput("button", "delete", "Delete")
input.className = "delete"
input.addEventListener("click", function() { savePopupData("m3u", String(id), true, 0) })
content.addInteraction(input)
} else {
var input = content.createInput("button", "back", "Back")
input.addEventListener("click", function() { openPopUp("playlist") })
content.addInteraction(input)
}
// Abbrechen
var input = content.createInput("button", "cancel", "Cancel")
input.addEventListener("click", function() { showElement("popup", false) })
content.addInteraction(input)
// Aktualisieren
if (data["id.provider"]!= "-") {
var input = content.createInput("button", "update", "Update")
input.addEventListener("click", function() { savePopupData("m3u", String(id), false, 1) })
content.addInteraction(input)
}
// Speichern
var input = content.createInput("button", "save", "Save")
input.addEventListener("click", function() { savePopupData("m3u", String(id), false, 0) })
content.addInteraction(input)
break
case "hdhr":
content.createHeadline(dataType)
// Name
var dbKey:string = "name"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Playlist name")
content.appendRow("Name", input)
// Beschreibung
var dbKey:string = "description"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Description")
content.appendRow("Description", input)
// URL
var dbKey:string = "file.source"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "IP address and port (192.168.1.10:5004)")
content.appendRow("HDHomeRun IP", input)
// Buffer (per playlist override of the global setting)
var bufferSelect = createBufferSelect(content, data)
content.appendRow("Buffer", bufferSelect)
// Tuner
if (playlistBufferActive(data)) {
var text:string[] = new Array()
var values:string[] = new Array()
for (var i = 1; i <= 100; i++) {
text.push(i.toString())
values.push(i.toString())
}
var dbKey:string = "tuner"
var select = content.createSelect(text, values, data[dbKey], dbKey)
content.appendRow("Tuner / Streams", select)
} else {
var dbKey:string = "tuner"
if (data[dbKey] == undefined) {
data[dbKey] = 1
}
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("readonly", "true")
input.className = "notAvailable"
content.appendRow("Tuner / Streams", input)
}
content.description("Number of parallel connections that can be established to the provider. <br>Only available with activated buffer.<br>New settings will only be applied after quitting all streams.", true)
// Interaktion
content.createInteraction()
// Löschen
if (data["id.provider"]!= "-") {
var input = content.createInput("button", "delete", "Delete")
input.addEventListener("click", function() { savePopupData("hdhr", String(id), true, 0) })
input.className = "delete"
content.addInteraction(input)
} else {
var input = content.createInput("button", "back", "Back")
input.addEventListener("click", function() { openPopUp("playlist") })
content.addInteraction(input)
}
// Abbrechen
var input = content.createInput("button", "cancel", "Cancel")
input.addEventListener("click", function() { showElement("popup", false) })
content.addInteraction(input)
// Aktualisieren
if (data["id.provider"]!= "-") {
var input = content.createInput("button", "update", "Update")
input.addEventListener("click", function() { savePopupData("hdhr", String(id), false, 1) })
content.addInteraction(input)
}
// Speichern
var input = content.createInput("button", "save", "Save")
input.addEventListener("click", function() { savePopupData("hdhr", String(id), false, 0) })
content.addInteraction(input)
break
case "filter":
content.createHeadline(dataType)
// Type
var dbKey:string = "type"
var text:string[] = ["M3U: " + "Group Title", "xTeVe: " + "Custom Filter", "xTeVe: " + "Regular Expression"]
var values:string[] = ["group-title", "custom-filter", "regex-filter"]
var select = content.createSelect(text, values, "group-title", dbKey)
select.setAttribute("id", id)
content.appendRow("Type", select)
const filterTypeSelect:HTMLSelectElement = select
// Interaktion
content.createInteraction()
// Abbrechen
var input = content.createInput("button", "cancel", "Cancel")
input.addEventListener("click", function() { showElement("popup", false) })
content.addInteraction(input)
// Weiter
var input = content.createInput("button", "next", "Next")
input.addEventListener("click", function() { openPopUp(filterTypeSelect.value) })
input.setAttribute("id", 'next')
content.addInteraction(input)
break
case "custom-filter":
case "group-title":
case "regex-filter":
switch (dataType) {
case "custom-filter":
content.createHeadline("Custom")
break;
case "group-title":
content.createHeadline("Group")
break;
case "regex-filter":
content.createHeadline("Regular Expression")
break;
}
// Name
var dbKey:string = "name"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Filter name")
content.appendRow("Filter Name", input)
// Beschreibung
var dbKey:string = "description"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Description")
content.appendRow("Description", input)
// Typ
var dbKey:string = "type"
var input = content.createInput("hidden", dbKey, data[dbKey])
content.appendRow("", input)
var filterType = data[dbKey]
switch (filterType) {
case "custom-filter":
// Groß- Kleinschreibung beachten
var dbKey:string = "caseSensitive"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
content.appendRow("Case Sensitive", input)
// Filterregel (Benutzerdefiniert)
var dbKey:string = "filter"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Sport {HD} !{ES,IT}")
content.appendRow("Filter Rule", input)
break;
case "regex-filter":
// Groß- Kleinschreibung beachten
var dbKey:string = "caseSensitive"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
content.appendRow("Case Sensitive", input)
// Regulärer Ausdruck
var dbKey:string = "filter"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "^(BBC|ITV) \\d+$")
content.appendRow("Regular Expression", input)
content.description("Go regular expression, tried against the channel name, then the group title, then the raw M3U attributes. Case-insensitive unless Case Sensitive is checked. Invalid patterns are rejected on save.")
break;
case "group-title":
//alert(dbKey + " " + filterType)
// Filter basierend auf den Gruppen in der M3U
var dbKey:string = "filter"
var groupsM3U = getLocalData("m3uGroups", "")
var text:string[] = groupsM3U["text"]
var values:string[] = groupsM3U["value"]
var select = content.createSelect(text, values, data[dbKey], dbKey)
markChangedOnChange(select)
content.appendRow("Group Title", select)
content.description("Select a M3U group. (Counter)<br>Changing the group title in the M3U invalidates the filter.", true)
// Groß- Kleinschreibung beachten
var dbKey:string = "caseSensitive"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
content.appendRow("Case Sensitive", input)
var dbKey:string = "include"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "FHD,UHD")
content.appendRow("Include", input)
content.description("Channel name must include.<br>(Comma separated) Comma means or", true)
var dbKey:string = "exclude"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "ES,IT")
content.appendRow("Exclude", input)
content.description("Channel name must not contain.<br>(Comma separated) Comma means or", true)
break
default:
break;
}
// Interaktion
content.createInteraction()
// Löschen
var input = content.createInput("button", "delete", "Delete")
input.addEventListener("click", function() { savePopupData("filter", String(id), true, 0) })
input.className = "delete"
content.addInteraction(input)
// Abbrechen
var input = content.createInput("button", "cancel", "Cancel")
input.addEventListener("click", function() { showElement("popup", false) })
content.addInteraction(input)
// Speichern
var input = content.createInput("button", "save", "Save")
input.addEventListener("click", function() { savePopupData("filter", String(id), false, 0) })
content.addInteraction(input)
break
case "xmltv":
content.createHeadline(dataType)
// Name
var dbKey:string = "name"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Guide name")
content.appendRow("Name", input)
// Beschreibung
var dbKey:string = "description"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Description")
content.appendRow("Description", input)
// URL
var dbKey:string = "file.source"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "File path or URL of the XMLTV")
content.appendRow("XMLTV File", input)
// Interaktion
content.createInteraction()
// Löschen
if (data["id.provider"]!= "-") {
var input = content.createInput("button", "delete", "Delete")
input.addEventListener("click", function() { savePopupData("xmltv", String(id), true, 0) })
input.className = "delete"
content.addInteraction(input)
}
// Abbrechen
var input = content.createInput("button", "cancel", "Cancel")
input.addEventListener("click", function() { showElement("popup", false) })
content.addInteraction(input)
// Aktualisieren
if (data["id.provider"]!= "-") {
var input = content.createInput("button", "update", "Update")
input.addEventListener("click", function() { savePopupData("xmltv", String(id), false, 1) })
content.addInteraction(input)
}
// Speichern
var input = content.createInput("button", "save", "Save")
input.addEventListener("click", function() { savePopupData("xmltv", String(id), false, 0) })
content.addInteraction(input)
break
case "users":
content.createHeadline("Users")
// Benutzername
var dbKey:string = "username"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Username")
content.appendRow("Username", input)
// Neues Passwort
var dbKey:string = "password"
var input = content.createInput("password", dbKey, "")
input.setAttribute("placeholder", "Password")
content.appendRow("Password", input)
// Bestätigung
var dbKey:string = "confirm"
var input = content.createInput("password", dbKey, "")
input.setAttribute("placeholder", "Password confirm")
content.appendRow("Confirm", input)
// Berechtigung WEB
var dbKey:string = "authentication.web"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
if (data["defaultUser"] == true) {
input.addEventListener("click", function(event) { event.preventDefault() })
}
content.appendRow("Web Access", input)
// Berechtigung PMS
var dbKey:string = "authentication.pms"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
content.appendRow("PMS Access", input)
// Berechtigung M3U
var dbKey:string = "authentication.m3u"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
content.appendRow("M3U Access", input)
// Berechtigung XML
var dbKey:string = "authentication.xml"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
content.appendRow("XML Access", input)
// Berechtigung API
var dbKey:string = "authentication.api"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
content.appendRow("API Access", input)
// Interaktion
content.createInteraction()
// Löschen
if (data["defaultUser"]!= true && id != "-") {
var input = content.createInput("button", "delete", "Delete")
input.className = "delete"
input.addEventListener("click", function() { savePopupData(dataType, String(id), true, 0) })
content.addInteraction(input)
}
// Abbrechen
var input = content.createInput("button", "cancel", "Cancel")
input.addEventListener("click", function() { showElement("popup", false) })
content.addInteraction(input)
// Speichern
var input = content.createInput("button", "save", "Save")
input.addEventListener("click", function() { savePopupData(dataType, String(id), false, 0) })
content.addInteraction(input)
break
case "mapping":
content.createHeadline("Mapping")
// Aktiv
var dbKey:string = "x-active"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
input.id = "active"
//markChangedOnChange(input)
input.addEventListener("change", function() { toggleChannelStatus(id) })
content.appendRow("Active", input)
// Kanalname
var dbKey:string = "x-name"
var input = content.createInput("text", dbKey, data[dbKey])
markChangedOnChange(input)
if (BULK_EDIT == true) {
input.style.border = "solid 1px red"
input.setAttribute("readonly", "true")
}
content.appendRow("Channel Name", input)
content.description(data["name"])
// Beschreibung
var dbKey:string = "x-description"
var input = content.createInput("text", dbKey, data[dbKey])
input.setAttribute("placeholder", "Used by the Dummy as an XML description")
markChangedOnChange(input)
content.appendRow("Channel Description", input)
// Aktualisierung des Kanalnamens
if (data.hasOwnProperty("_uuid.key")) {
if (data["_uuid.key"] != "") {
var dbKey:string = "x-update-channel-name"
var input = content.createCheckbox(dbKey)
markChangedOnChange(input)
input.checked = data[dbKey]
content.appendRow("Update Channel Name", input)
}
}
// Logo URL (Kanal)
var dbKey:string = "tvg-logo"
var input = content.createInput("text", dbKey, data[dbKey])
markChangedOnChange(input)
input.setAttribute("id", "channel-icon")
content.appendRow("Logo URL", input)
// Aktualisierung des Kanallogos
var dbKey:string = "x-update-channel-icon"
var input = content.createCheckbox(dbKey)
input.checked = data[dbKey]
input.setAttribute("id", "update-icon")
markChangedOnChange(input, function() { changeChannelLogo(id) })
content.appendRow("Update Channel Logo", input)
// Erweitern der EPG Kategorie
var dbKey:string = "x-category"
var text:string[] = ["-", "Kids (Emby only)", "News", "Movie", "Series", "Sports"]
var values:string[] = ["", "Kids", "News", "Movie", "Series", "Sports"]
var select = content.createSelect(text, values, data[dbKey], dbKey)
markChangedOnChange(select)
content.appendRow("EPG Category", select)
// M3U Gruppentitel
var dbKey:string = "x-group-title"
var input = content.createInput("text", dbKey, data[dbKey])
markChangedOnChange(input)
content.appendRow("Group Title (xteve.m3u)", input)
if (data["group-title"] != undefined) {
content.description(data["group-title"])
}
// XMLTV Datei
var dbKey:string = "x-xmltv-file"
var xmlFile = data[dbKey]
var xmltv:XMLTVFile = new XMLTVFile()
var select = xmltv.getFiles(data[dbKey])
select.setAttribute("name", dbKey)
select.setAttribute("id", "popup-xmltv")
markChangedOnChange(select, function(element) { setXmltvChannel(id, element) })
content.appendRow("XMLTV File", select)
var file = data[dbKey]
// XMLTV Mapping
var dbKey:string = "x-mapping"
var xmltv:XMLTVFile = new XMLTVFile()
var select = xmltv.getPrograms(file, data[dbKey])
select.setAttribute("name", dbKey)
select.setAttribute("id", "popup-mapping")
markChangedOnChange(select, function(element) { checkXmltvChannel(id, element, xmlFile) })
sortSelect(select)
content.appendRow("XMLTV Channel", select)
// Interaktion
content.createInteraction()
// Logo hochladen
var input = content.createInput("button", "cancel", "Upload Logo")
input.addEventListener("click", function() { uploadLogo() })
content.addInteraction(input)
// Abbrechen
var input = content.createInput("button", "cancel", "Cancel")
input.addEventListener("click", function() { showElement("popup", false) })
content.addInteraction(input)
// Fertig
var ids:string[] = new Array()
ids = getAllSelectedChannels()
if (ids.length == 0) {
ids.push(id)
}
var input = content.createInput("button", "save", "Done")
input.addEventListener("click", function() { donePopupData(dataType, ids.join(",")) })
content.addInteraction(input)
break
default:
break;
}
showPopUpElement('popup-custom');
}
function savePopupData(dataType:string, id:string, remove:Boolean, option:number) {
if (dataType == "mapping") {
var data = new Object()
console.log("Save mapping data")
cmd = "saveEpgMapping"
data["epgMapping"] = SERVER["xepg"]["epgMapping"]
console.log("SEND TO SERVER");
var server:Server = new Server(cmd)
server.request(data)
delete UNDO["epgMapping"]
return
}
console.log("Save popup data")
var div = document.getElementById("popup-custom")
var inputs = div.getElementsByTagName("TABLE")[0].getElementsByTagName("INPUT");
var selects = div.getElementsByTagName("TABLE")[0].getElementsByTagName("SELECT");
var input = new Object();
var confirmMsg: string
for (let i = 0; i < selects.length; i++) {
var name:string
name = (selects[i] as HTMLSelectElement).name
var value = (selects[i] as HTMLSelectElement).value
switch (name) {
case "tuner":
input[name] = parseInt(value)
break;
default:
input[name] = value
break;
}
}
for (let i = 0; i < inputs.length; i++) {
switch ((inputs[i] as HTMLInputElement).type) {
case "checkbox":
name = (inputs[i] as HTMLInputElement).name
input[name] = (inputs[i] as HTMLInputElement).checked
break
case "text":
case "hidden":
case "password":
name = (inputs[i] as HTMLInputElement).name
switch (name) {
case "tuner":
input[name] = parseInt((inputs[i] as HTMLInputElement).value)
break;
default:
input[name] = (inputs[i] as HTMLInputElement).value
break;
}
break
}
}
var data = new Object()
var cmd:string
if (remove == true) {
input["delete"] = true
}
switch (dataType) {
case "users":
confirmMsg = "Delete this user?"
if (id == "-") {
cmd = "saveNewUser"
data["userData"] = input
} else {
cmd = "saveUserData"
var d = new Object()
d[id] = input
data["userData"] = d
}
break;
case "m3u":
confirmMsg = "Delete this playlist?"
switch (option) {
// Popup: Save
case 0:
cmd = "saveFilesM3U"
break
// Popup: Update
case 1:
cmd = "updateFileM3U"
break
}
data["files"] = new Object
data["files"][dataType] = new Object
data["files"][dataType][id] = input
break
case "hdhr":
confirmMsg = "Delete this HDHomeRun tuner?"
switch (option) {
// Popup: Save
case 0:
cmd = "saveFilesHDHR"
break
// Popup: Update
case 1:
cmd = "updateFileHDHR"
break
}
data["files"] = new Object
data["files"][dataType] = new Object
data["files"][dataType][id] = input
break
case "xmltv":
confirmMsg = "Delete this XMLTV file?"
switch (option) {
// Popup: Save
case 0:
cmd = "saveFilesXMLTV"
break
// Popup: Update
case 1:
cmd = "updateFileXMLTV"
break
}
data["files"] = new Object
data["files"][dataType] = new Object
data["files"][dataType][id] = input
break
case "filter":
confirmMsg = "Delete this filter?"
cmd = "saveFilter"
data["filter"] = new Object
data["filter"][id] = input
break
default:
console.log(dataType, id);
return
break;
}
if (remove == true) {
if (!confirm(confirmMsg)) {
showElement("popup", false)
return
}
}
console.log("SEND TO SERVER");
console.log(data);
var server:Server = new Server(cmd)
server.request(data)
}
function donePopupData(dataType:string, idsStr:string) {
var ids:string[] = idsStr.split(',');
var div = document.getElementById("popup-custom")
var inputs = div.getElementsByClassName("changed")
ids.forEach(id => {
var input = new Object();
input = SERVER["xepg"]["epgMapping"][id]
console.log(input);
for (let i = 0; i < inputs.length; i++) {
var name:string
var value:any
switch (inputs[i].tagName) {
case "INPUT":
switch ((inputs[i] as HTMLInputElement).type) {
case "checkbox":
name = (inputs[i] as HTMLInputElement).name
value = (inputs[i] as HTMLInputElement).checked
input[name] = value
break
case "text":
name = (inputs[i] as HTMLInputElement).name
value = (inputs[i] as HTMLInputElement).value
input[name] = value
break
}
break
case "SELECT":
name = (inputs[i] as HTMLSelectElement).name
value = (inputs[i] as HTMLSelectElement).value
input[name] = value
break
}
switch (name) {
case "tvg-logo":
//(document.getElementById(id).childNodes[2].firstChild as HTMLElement).setAttribute("src", value)
break
case "x-name":
(document.getElementById(id).childNodes[3].firstChild as HTMLElement).textContent = value
break
case "x-category":
(document.getElementById(id).childNodes[3].firstChild as HTMLElement).className = value
break
case "x-group-title":
(document.getElementById(id).childNodes[5].firstChild as HTMLElement).textContent = value
break
case "x-xmltv-file":
if (value != "xTeVe Dummy" && value != "-") {
value = getValueFromProviderFile(value, "xmltv", "name")
}
if (value == "-") {
input["x-active"] = false
}
(document.getElementById(id).childNodes[6].firstChild as HTMLElement).textContent = value
break
case "x-mapping":
if (value == "-") {
input["x-active"] = false
}
(document.getElementById(id).childNodes[7].firstChild as HTMLElement).textContent = value
break
default:
}
createSearchObj()
searchInMapping()
}
if (input["x-active"] == false) {
document.getElementById(id).className = "notActiveEPG"
} else {
document.getElementById(id).className = "activeEPG"
}
console.log(input["tvg-logo"]);
(document.getElementById(id).childNodes[2].firstChild as HTMLElement).setAttribute("src", input["tvg-logo"])
});
showElement("popup", false);
return
}
function showPreview(element:boolean) {
var div = document.getElementById("myStreamsBox")
switch (element) {
case false:
div.className = "notVisible"
return
break;
}
var streams:string[] = ["activeStreams", "inactiveStreams"]
streams.forEach(preview => {
var table = document.getElementById(preview)
table.innerHTML = ""
var obj:string[] = SERVER["data"]["StreamPreviewUI"][preview]
obj.forEach(channel => {
var tr = document.createElement("TR")
var tdKey = document.createElement("TD")
var tdVal = document.createElement("TD")
tdKey.className = "tdKey"
tdVal.className = "tdVal"
switch (preview) {
case "activeStreams":
tdKey.innerText = "Channel: (+)"
break;
case "inactiveStreams":
tdKey.innerText = "Channel: (-)"
break;
}
tdVal.innerText = channel
tr.appendChild(tdKey)
tr.appendChild(tdVal)
table.appendChild(tr)
});
});
showElement("loading", false)
div.className = "visible"
return
}