var tid; var ractive; var model; var tiptid; var first; $.postJSON = function (url, data) { return $.ajax({ type: 'POST', url: url, data: JSON.stringify(data), contentType: "application/json", dataType: 'json' }); }; function update() { ractive.set(model); } function navigate(path) { path = path.substr(path.indexOf('#')); var split = path.split("/"); ractive.set("view.page.*", false); ractive.set("view.tab.*", false); if (split.length >= 2) ractive.set("view.page." + split[1], true); if (split.length >= 3) ractive.set("view.tab." + split[2], true); else ractive.set("view.tab.default", true); } function getStatusView(m) { if (m.interfaces.ad.status == "Disabled") { m.interfaces.ad.view = { icon: "ban", style: "", text: "Interface is disabled" }; } else if (m.interfaces.ad.status == "Started") { m.interfaces.ad.view = { icon: "check", style: "ok", text: "Interface is listening" }; } else { m.interfaces.ad.view = { icon: "times", style: "error", text: m.interfaces.ad.error }; } if (m.interfaces.wifi.status == "Disabled") { m.interfaces.wifi.view = { icon: "ban", style: "", text: "Interface is disabled" }; } else if (m.interfaces.wifi.status == "Started") { m.interfaces.wifi.view = { icon: "check", style: "ok", text: "Interface is listening" }; } else { m.interfaces.wifi.view = { icon: "times", style: "error", text: m.interfaces.wifi.error }; } if (m.interfaces.bt.status == "Disabled") { m.interfaces.bt.view = { icon: "ban", style: "", text: "Interface is disabled" }; } else if (m.interfaces.bt.status == "Started") { m.interfaces.bt.view = { icon: "check", style: "ok", text: "Interface is listening" }; } else if (m.interfaces.bt.status == "NotSupported") { m.interfaces.bt.view = { icon: "ban", style: "", text: "Not supported on current OS" }; } else if (m.interfaces.bt.status == "NotAvailable") { m.interfaces.bt.view = { icon: "ban", style: "", text: "Radio is not available" }; } else { m.interfaces.bt.view = { icon: "times", style: "error", text: m.interfaces.bt.error }; } if (m.network.lan.available) { m.network.lan.view = { icon: "check", style: "ok", text: "Detected" }; } else { m.network.lan.view = { icon: "times", style: "error", text: "Not Detected" }; } if (m.network.wan.available) { m.network.wan.view = { icon: "check", style: "ok", text: "Detected" }; } else { m.network.wan.view = { icon: "times", style: "error", text: "Not Detected" }; } if (m.firewall.available) { if (m.firewall.allowed) { m.firewall.view = { icon: "check", style: "ok", text: "Access is allowed" }; } else { m.firewall.view = { icon: "times", style: "error", text: "Access not allowed. Check firewall settings..." }; } } m.input.view = { icon: "check", style: "ok", text: m.input.mode }; return m; } function onConnected() { fetchRemotes(); fetchConfig(); fetchRemotes(); } function fetchStatus() { model.view.restarting = false; $.getJSON("/system/status", function (data) { if (model.view.restarting) { return; } if (!model.view.connected || first) { if (!first) tip("Connected"); model.view.connected = true; model.view.restarting = false; first = false; onConnected(); } model.status = getStatusView(data); update(); }) .fail(function (jqXHR, textStatus, errorThrown) { if (model.view.restarting) { return; } if (model.view.connected) { model.view.connected = false; model.view.log.data = []; tip("Disconnected"); } model.status.interfaces.wifi.view = { icon: "times", style: "", text: "Checking..." }; model.status.interfaces.bt.view = { icon: "times", style: "", text: "Checking..." }; model.status.interfaces.ad.view = { icon: "times", style: "", text: "Checking..." }; model.status.network.lan.view = { icon: "times", style: "", text: "Checking..." }; model.status.network.wan.view = { icon: "times", style: "", text: "Checking..." }; model.status.firewall.view = { icon: "times", style: "", text: "Checking..." }; model.status.input.view = { icon: "times", style: "", text: "Checking..." }; update(); }) .always(function () { if (model.view.restarting) { return; } tid = setTimeout(fetchStatus, 1000); }); var l = model.view.log; var url_postfix = "/" + [l.lines, l.level, l.filter].join("/"); var lineToItem = function(itm) { var split = itm.split(" "); return { date: split[0], time: split[1], tag: model.log_levels[_.trim(split[2], "()")].name, msg: _.slice(split, 3).join(" ") }; }; if (!l.paused) { $.getJSON("/system/log" + url_postfix, function (json) { var newLines = json.data; var newItems = _(newLines).map(lineToItem).value(); var $log = $("#log-data"); // Log element not visible if ($log.size() === 0) return; var log = l.data = _.sortByOrder(newItems, ['data', 'time'], [false, false]); $log.html(templateRender('#tlogline', {log: log})); l.last_url_postfix = url_postfix; }); } } var templateRender = function(template, data) { var ractive = new Ractive({ template: template, data: data }); return ractive.toHTML(); }; function sortRemotes(a,b) { if (a.id == "Relmtech.Basic Input") return -1; if (b.id == "Relmtech.Basic Input") return 1; a = a.name.toLowerCase(); b = b.name.toLowerCase(); if (a < b) return -1; if (a > b) return 1; return 0; } function fetchRemotes() { $.getJSON("/system/remotes", function (data) { data.sort(sortRemotes); model.remotes = data; update(); }); } function fetchConfig() { $.getJSON("/system/config", function (data) { model.config = data; update(); }); } function tip(s) { ractive.set("view.tip", s); var $tips = $(".tips"); $tips.hide(); clearTimeout(tiptid); $tips.slideDown(100, function () { tiptid = setTimeout(function () { $(".tips").slideUp(100); }, 2000); }); } function saveConfig() { model.view.unsaved = {}; $.postJSON("/system/config", model.config); restart(); } function restart() { clearTimeout(tid); model.view.restarting = true; model.view.connected = false; model.view.log.data = []; update(); $.get("/system/restart"); tid = setTimeout(fetchStatus, 3000); } function isRemoteDisabled (id) { return !isRemoteEnabled(id); } function isRemoteEnabled (id) { return $.inArray(id, model.config.loader.disabled) == -1; } function isRemoteUnsaved (id) { return model.view.unsaved[id] == true; } $(document).ready(function () { first = true; log = ""; model = { year: new Date().getFullYear(), view: { restarting: false, connected: true, showhidden: false, tip: "", page: { status: true }, tab: { dashboard: true }, unsaved: {}, dragdrop: undefined, log : { last_url_postfix: undefined, data: [], lines: 30, filter: "", paused: false, level: 6 } }, log_levels: { F: {name: "fatal", value: 1}, C: {name: "critical", value: 2}, E: {name: "error", value: 3}, W: {name: "warning", value: 4}, N: {name: "notice", value: 5}, I: {name: "info", value: 6}, D: {name: "debug", value: 7}, T: {name: "trace", value: 8} }, view_log_levels: [ {name: "Fatal", value: 1}, {name: "Error", value: 3}, {name: "Warning", value: 4}, {name: "Info", value: 6}, {name: "Trace", value: 8} ], isRemoteDisabled: isRemoteDisabled, isRemoteEnabled: isRemoteEnabled, isRemoteUnsaved: isRemoteUnsaved }; ractive = new Ractive({ el: "container", template: "#tmain", data: model }); ractive.on({ navigate: function (e) { navigate(e.node.getAttribute("href")); }, "save-config": function (e) { saveConfig(); }, "cancel-config": function (e) { tip("Reverted changes"); fetchConfig(); }, "remove-path": function (e) { var i = e.node.getAttribute("data-index"); model.config.loader.paths.splice(i, 1); update(); }, "add-path": function (e) { model.config.loader.paths.push(""); update(); }, "restart": function (e) { restart(); }, "reload": function (e) { $.get("/system/reload"); tip("Reloading remotes"); }, "enable-all-remotes": function (e) { model.config.loader.disabled = []; update(); saveConfig(); }, "disable-all-remotes": function (e) { for (var i = 0; i < model.remotes.length; i++) { var remote = model.remotes[i]; if ($.inArray(remote.id, model.config.loader.disabled) == -1) if (!remote.hidden || model.view.showhidden) model.config.loader.disabled.push(remote.id); } update(); saveConfig(); }, "update-check": function (e) { tip("Checking for updates"); $.getJSON("/system/update-force", function (data) { if (data.Available) { tip("Update available"); } else { tip("No updates available"); } fetchConfig(); }); }, "update-clear": function (e) { $.get("/system/update-clear"); fetchConfig(); }, "enable-remote": function (e) { var id = e.node.getAttribute("data-id"); var i = model.config.loader.disabled.indexOf(id); if (i > -1) { model.config.loader.disabled.splice(i, 1); model.view.unsaved[id] = !(model.view.unsaved[id] == true); update(); } else { tip("Already enabled"); } }, "disable-remote": function (e) { var id = e.node.getAttribute("data-id"); var i = model.config.loader.disabled.indexOf(id); if (i == -1) { model.config.loader.disabled.push(id); model.view.unsaved[id] = !(model.view.unsaved[id] == true); update(); } else { tip("Already disabled"); } }, "save-remotes": function (e) { saveConfig(); }, "configure-remote": function (e) { var i = e.node.getAttribute("data-index"); model.view.remote = model.remotes[i]; update(); }, "configure-users": function (e) { navigate("/web/#/settings/users"); }, "add-user": function (e) { model.config.security.users.push({ username: "", password: "" }); update(); }, "remove-user": function (e) { var i = e.node.getAttribute("data-index"); model.config.security.users.splice(i, 1); update(); }, "save-remote-settings": function (e) { tip("Saving settings"); $.postJSON("/system/remote-settings/" + model.view.remote.id, model.view.remote.settings); delete model.view.remote; update(); }, "cancel-remote-settings": function (e) { delete model.view.remote; update(); }, "add-remote-setting": function (e) { model.view.remote.settings.push({ key: "", value: "" }); update(); }, "remove-remote-setting": function (e) { var i = e.node.getAttribute("data-index"); model.view.remote.settings.splice(i, 1); update(); }, "toggle-wan-address": function (e) { $("#wan-address").find("a").toggleClass("hide"); }, "fetch-status": function (e) { fetchStatus(); }, "toggle-pause-log" : function(e) { model.view.log.paused = !model.view.log.paused; update(); }, "file-drag-start": function (e) { var evt = (e.original || {}); if (!evt.dataTransfer) return false; if (evt.preventDefault) evt.preventDefault(); evt.dataTransfer.effectAllowed = "copy"; model.view.dragdrop = { dragging: true, uploading: false, result: false }; update(); return false; }, "file-drag-dismiss": function(e) { model.view.dragdrop = undefined; update(); setTimeout(fetchRemotes, 500); }, "file-drag-cancel": function(e) { if (!model.view.dragdrop) return; if (!model.view.dragdrop.dragging) return; model.view.dragdrop = undefined; update(); }, "file-drag-drop": function (e) { var evt = e.original; var dd = model.view.dragdrop; dd.dragging = false; dd.uploading = true; update(); var dt = evt.dataTransfer || {}; var files = dt.files || []; _.forEach(files, function(file, idx) { var reader = new FileReader(); $(reader).on('loadend', function(e, f) { var blob = this.result; $.ajax({ url: "/system/remote/add?filename=" + file.name, type: 'POST', contentType: 'application/octet-stream', data: blob, dataType: "json", processData: false }) .done(function (data) { dd.uploading = false; dd.result = data; update(); $.get("/system/reload"); }); }); reader.readAsArrayBuffer(file); }); if (evt.preventDefault) evt.preventDefault(); } }); if (window.location.hash) { navigate(window.location.hash); } fetchStatus(); });