diff options
author | Devaev Maxim <[email protected]> | 2018-12-15 04:29:40 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2018-12-15 04:29:40 +0300 |
commit | 3c33bd37190772a783369894e209bcfe0858177a (patch) | |
tree | e095f08f37371a3182f6ced0b280c4bcaa06983b /web/js | |
parent | 3445766a50eab16a96d969397a6fe0422f7cfcd2 (diff) |
own auth
Diffstat (limited to 'web/js')
-rw-r--r-- | web/js/bb.js | 33 | ||||
-rw-r--r-- | web/js/index/main.js | 65 | ||||
-rw-r--r-- | web/js/kvm/atx.js | 43 | ||||
-rw-r--r-- | web/js/kvm/hid.js | 198 | ||||
-rw-r--r-- | web/js/kvm/keyboard.js | 190 | ||||
-rw-r--r-- | web/js/kvm/main.js | 16 | ||||
-rw-r--r-- | web/js/kvm/mouse.js | 160 | ||||
-rw-r--r-- | web/js/kvm/msd.js | 193 | ||||
-rw-r--r-- | web/js/kvm/session.js | 143 | ||||
-rw-r--r-- | web/js/kvm/stream.js | 221 | ||||
-rw-r--r-- | web/js/tools.js | 133 | ||||
-rw-r--r-- | web/js/wm.js | 387 |
12 files changed, 0 insertions, 1782 deletions
diff --git a/web/js/bb.js b/web/js/bb.js deleted file mode 100644 index 565a3ab4..00000000 --- a/web/js/bb.js +++ /dev/null @@ -1,33 +0,0 @@ -function checkBrowser() { - if ( - !window.navigator - || window.navigator.userAgent.indexOf("MSIE ") > 0 - || window.navigator.userAgent.indexOf("Trident/") > 0 - || window.navigator.userAgent.indexOf("Edge/") > 0 - ) { - var el_modal = document.createElement("div"); - el_modal.className = "modal"; - el_modal.style.visibility = "visible"; - el_modal.innerHTML = ` - <div class="modal-window"> - <div class="modal-content"> - Hello. You are using an incompatible or legacy browser.<br> - Please use one of the following browsers: - <hr> - <ul> - <li><a target="_blank" href="https://google.com/chrome">Google Chrome</a> <sup><i>recommended</i></sup></li> - <li><a target="_blank" href="https://chromium.org/Home">Chromium</a> <sup><i>recommended</i></sup></li> - <li><a target="_blank" href="https://mozilla.org/firefox">Mozilla Firefox</a></li> - <li><a target="_blank" href="https://apple.com/safari">Apple Safari</a></li> - <li><a target="_blank" href="https://opera.com">Opera</a></li> - <li><a target="_blank" href="https://vivaldi.com">Vivaldi</a></li> - </ul> - </div> - </div> - `; - document.body.appendChild(el_modal); - return false; - } else { - return true; - } -} diff --git a/web/js/index/main.js b/web/js/index/main.js deleted file mode 100644 index 8f5c74a6..00000000 --- a/web/js/index/main.js +++ /dev/null @@ -1,65 +0,0 @@ -function main() { - if (checkBrowser()) { - __setAppText(); - __loadKvmdInfo(); - } -} - -function __setAppText() { - $("app-text").innerHTML = ` - <span class="code-comment"># On Linux using Chromium/Chrome via any terminal:<br> - $</span> \`which chromium 2>/dev/null || which chrome 2>/dev/null\` --app="${window.location.href}"<br> - <br> - <span class="code-comment"># On MacOS using Terminal application:<br> - $</span> /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --app="${window.location.href}"<br> - <br> - <span class="code-comment"># On Windows via cmd.exe:<br> - C:\></span> start chrome --app="${window.location.href}" - `; -} - -function __loadKvmdInfo() { - var http = tools.makeRequest("GET", "/kvmd/info", function() { - if (http.readyState === 4) { - if (http.status === 200) { - var info = JSON.parse(http.responseText).result; - - var apps = Object.values(info.extras).sort(function(a, b) { - if (a["place"] < b["place"]) { - return -1; - } else if (a["place"] > b["place"]) { - return 1; - } else { - return 0; - } - }); - - $("apps-box").innerHTML = "<ul id=\"apps\"></ul>"; - apps.forEach(function(app) { - $("apps").innerHTML += ` - <li> - <div class="app"> - <a href="${app.path}"> - <div> - <img class="svg-gray" src="${app.icon}"> - ${app.name} - </div> - </a> - </div> - </li> - `; - }); - - if (info.meta && info.meta.server && info.meta.server.host) { - $("kvmd-meta-server-host").innerHTML = info.meta.server.host; - document.title = "Pi-KVM Index: " + info.meta.server.host; - } else { - $("kvmd-meta-server-host").innerHTML = ""; - document.title = "Pi-KVM Index"; - } - } else { - setTimeout(__loadKvmdInfo, 1000); - } - } - }); -} diff --git a/web/js/kvm/atx.js b/web/js/kvm/atx.js deleted file mode 100644 index ed5f045e..00000000 --- a/web/js/kvm/atx.js +++ /dev/null @@ -1,43 +0,0 @@ -function Atx() { - var self = this; - - /********************************************************************************/ - - var __init__ = function() { - $("atx-power-led").title = "Power Led"; - $("atx-hdd-led").title = "Disk Activity Led"; - - tools.setOnClick($("atx-power-button"), () => __clickButton("power", "Are you sure to click the power button?")); - tools.setOnClick($("atx-power-button-long"), () => __clickButton("power_long", "Are you sure to perform the long press of the power button?")); - tools.setOnClick($("atx-reset-button"), () => __clickButton("reset", "Are you sure to reboot the server?")); - }; - - /********************************************************************************/ - - self.setState = function(state) { - $("atx-power-led").className = ((state && state.leds.power) ? "led-green" : "led-gray"); - $("atx-hdd-led").className = ((state && state.leds.hdd) ? "led-red" : "led-gray"); - - wm.switchDisabled($("atx-power-button"), (!state || state.busy)); - wm.switchDisabled($("atx-power-button-long"), (!state || state.busy)); - wm.switchDisabled($("atx-reset-button"), (!state || state.busy)); - }; - - var __clickButton = function(button, confirm_msg) { - wm.confirm(confirm_msg).then(function(ok) { - if (ok) { - var http = tools.makeRequest("POST", "/kvmd/atx/click?button=" + button, function() { - if (http.readyState === 4) { - if (http.status === 409) { - wm.error("Performing another ATX operation for other client.<br>Please try again later"); - } else if (http.status !== 200) { - wm.error("Click error:<br>", http.responseText); - } - } - }); - } - }); - }; - - __init__(); -} diff --git a/web/js/kvm/hid.js b/web/js/kvm/hid.js deleted file mode 100644 index 49d659ab..00000000 --- a/web/js/kvm/hid.js +++ /dev/null @@ -1,198 +0,0 @@ -function Hid() { - var self = this; - - /********************************************************************************/ - - var __ws = null; - - var __chars_to_codes = {}; - var __codes_delay = 50; - - var __keyboard = new Keyboard(); - var __mouse = new Mouse(); - - var __init__ = function() { - var __hidden_attr = null; - var __visibility_change_attr = null; - - if (typeof document.hidden !== "undefined") { - __hidden_attr = "hidden"; - __visibility_change_attr = "visibilitychange"; - } else if (typeof document.webkitHidden !== "undefined") { - __hidden_attr = "webkitHidden"; - __visibility_change_attr = "webkitvisibilitychange"; - } else if (typeof document.mozHidden !== "undefined") { - __hidden_attr = "mozHidden"; - __visibility_change_attr = "mozvisibilitychange"; - } - - if (__visibility_change_attr) { - document.addEventListener( - __visibility_change_attr, - function() { - if (document[__hidden_attr]) { - __releaseAll(); - } - }, - false - ); - } - - window.addEventListener("pagehide", __releaseAll); - window.addEventListener("blur", __releaseAll); - - __chars_to_codes = __buildCharsToCodes(); - - tools.setOnClick($("hid-pak-button"), __clickPasteAsKeysButton); - tools.setOnClick($("hid-reset-button"), __clickResetButton); - - Array.prototype.forEach.call(document.querySelectorAll("[data-shortcut]"), function(el_shortcut) { - tools.setOnClick(el_shortcut, () => __emitShortcut(el_shortcut.getAttribute("data-shortcut").split(" "))); - }); - }; - - /********************************************************************************/ - - self.setSocket = function(ws) { - wm.switchDisabled($("hid-pak-text"), !ws); - wm.switchDisabled($("hid-pak-button"), !ws); - wm.switchDisabled($("hid-reset-button"), !ws); - __ws = ws; - __keyboard.setSocket(ws); - __mouse.setSocket(ws); - }; - - var __releaseAll = function() { - __keyboard.releaseAll(); - }; - - var __emitShortcut = function(codes) { - return new Promise(function(resolve) { - tools.debug("HID: emitting keys:", codes); - - var raw_events = []; - [[codes, true], [codes.slice().reverse(), false]].forEach(function(op) { - var [op_codes, state] = op; - op_codes.forEach(function(code) { - raw_events.push({code: code, state: state}); - }); - }); - - var index = 0; - var iterate = () => setTimeout(function() { - __keyboard.fireEvent(raw_events[index].code, raw_events[index].state); - ++index; - if (index < raw_events.length) { - iterate(); - } else { - resolve(null); - } - }, __codes_delay); - iterate(); - }); - }; - - var __buildCharsToCodes = function() { - var chars_to_codes = { - "\n": ["Enter"], - "\t": ["Tab"], - " ": ["Space"], - "`": ["Backquote"], "~": ["ShiftLeft", "Backquote"], - "\\": ["Backslash"], "|": ["ShiftLeft", "Backslash"], - "[": ["BracketLeft"], "{": ["ShiftLeft", "BracketLeft"], - "]": ["BracketLeft"], "}": ["ShiftLeft", "BracketRight"], - ",": ["Comma"], "<": ["ShiftLeft", "Comma"], - ".": ["Period"], ">": ["ShiftLeft", "Period"], - "1": ["Digit1"], "!": ["ShiftLeft", "Digit1"], - "2": ["Digit2"], "@": ["ShiftLeft", "Digit2"], - "3": ["Digit3"], "#": ["ShiftLeft", "Digit3"], - "4": ["Digit4"], "$": ["ShiftLeft", "Digit4"], - "5": ["Digit5"], "%": ["ShiftLeft", "Digit5"], - "6": ["Digit6"], "^": ["ShiftLeft", "Digit6"], - "7": ["Digit7"], "&": ["ShiftLeft", "Digit7"], - "8": ["Digit8"], "*": ["ShiftLeft", "Digit8"], - "9": ["Digit9"], "(": ["ShiftLeft", "Digit9"], - "0": ["Digit0"], ")": ["ShiftLeft", "Digit0"], - "-": ["Minus"], "_": ["ShiftLeft", "Minus"], - "'": ["Quote"], "\"": ["ShiftLeft", "Quote"], - ";": ["Semicolon"], ":": ["ShiftLeft", "Semicolon"], - "/": ["Slash"], "?": ["ShiftLeft", "Slash"], - "=": ["Equal"], "+": ["ShiftLeft", "Equal"], - }; - - for (var ch = "a".charCodeAt(0); ch <= "z".charCodeAt(0); ++ch) { - var low = String.fromCharCode(ch); - var up = low.toUpperCase(); - var code = "Key" + up; - chars_to_codes[low] = [code]; - chars_to_codes[up] = ["ShiftLeft", code]; - } - - return chars_to_codes; - }; - - var __clickPasteAsKeysButton = function() { - var text = $("hid-pak-text").value.replace(/[^\x00-\x7F]/g, ""); // eslint-disable-line no-control-regex - if (text) { - var clipboard_codes = []; - var codes_count = 0; - [...text].forEach(function(ch) { - var codes = __chars_to_codes[ch]; - if (codes) { - codes_count += codes.length; - clipboard_codes.push(codes); - } - }); - var time = __codes_delay * codes_count * 2 / 1000; - - var confirm_msg = ` - You are going to automatically type ${codes_count} characters from the system clipboard. - It will take ${time} seconds.<br> - <br> - Are you sure you want to continue? - `; - - wm.confirm(confirm_msg).then(function(ok) { - if (ok) { - wm.switchDisabled($("hid-pak-text"), true); - wm.switchDisabled($("hid-pak-button"), true); - $("hid-pak-led").className = "led-yellow-rotating-fast"; - $("hid-pak-led").title = "Autotyping..."; - - tools.debug("HID: paste-as-keys:", text); - - var index = 0; - var iterate = function() { - __emitShortcut(clipboard_codes[index]).then(function() { - ++index; - if (index < clipboard_codes.length && __ws) { - iterate(); - } else { - $("hid-pak-text").value = ""; - wm.switchDisabled($("hid-pak-text"), false); - wm.switchDisabled($("hid-pak-button"), false); - $("hid-pak-led").className = "led-gray"; - $("hid-pak-led").title = ""; - } - }); - }; - iterate(); - } else { - $("hid-pak-text").value = ""; - } - }); - } - }; - - var __clickResetButton = function() { - var http = tools.makeRequest("POST", "/kvmd/hid/reset", function() { - if (http.readyState === 4) { - if (http.status !== 200) { - wm.error("HID reset error:<br>", http.responseText); - } - } - }); - }; - - __init__(); -} diff --git a/web/js/kvm/keyboard.js b/web/js/kvm/keyboard.js deleted file mode 100644 index 3c821406..00000000 --- a/web/js/kvm/keyboard.js +++ /dev/null @@ -1,190 +0,0 @@ -function Keyboard() { - var self = this; - - /********************************************************************************/ - - var __ws = null; - - var __keys = [].slice.call(document.querySelectorAll("div#keyboard-desktop div.keyboard-block div.keyboard-row div.key")); - var __modifiers = [].slice.call(document.querySelectorAll("div#keyboard-desktop div.keyboard-block div.keyboard-row div.modifier")); - - var __init__ = function() { - $("hid-keyboard-led").title = "Keyboard free"; - - $("keyboard-window").onkeydown = (event) => __keyboardHandler(event, true); - $("keyboard-window").onkeyup = (event) => __keyboardHandler(event, false); - $("keyboard-window").onfocus = __updateLeds; - $("keyboard-window").onblur = __updateLeds; - - $("stream-window").onkeydown = (event) => __keyboardHandler(event, true); - $("stream-window").onkeyup = (event) => __keyboardHandler(event, false); - $("stream-window").onfocus = __updateLeds; - $("stream-window").onblur = __updateLeds; - - window.addEventListener("focusin", __updateLeds); - window.addEventListener("focusout", __updateLeds); - - Array.prototype.forEach.call($$("key"), function(el_key) { - tools.setOnDown(el_key, () => __clickHandler(el_key, true)); - tools.setOnUp(el_key, () => __clickHandler(el_key, false)); - el_key.onmouseout = function() { - if (__isPressed(el_key)) { - __clickHandler(el_key, false); - } - }; - }); - - Array.prototype.forEach.call($$("modifier"), function(el_key) { - tools.setOnDown(el_key, () => __toggleModifierHandler(el_key)); - }); - - if (tools.browser.is_mac) { - tools.info("Keyboard: enabled Mac-CMD-Hook"); - } - }; - - /********************************************************************************/ - - self.setSocket = function(ws) { - if (ws !== __ws) { - self.releaseAll(); - __ws = ws; - } - __updateLeds(); - }; - - self.releaseAll = function() { - __keys.concat(__modifiers).forEach(function(el_key) { - if (__isActive(el_key)) { - self.fireEvent(el_key.getAttribute("data-key"), false); - } - }); - }; - - self.fireEvent = function(code, state) { - __keyboardHandler({code: code}, state); - }; - - var __updateLeds = function() { - tools.debug("Keyboard: update leds"); - if ( - __ws && ( - $("stream-window").classList.contains("window-active") - || $("keyboard-window").classList.contains("window-active") - ) - ) { - $("hid-keyboard-led").className = "led-green"; - $("hid-keyboard-led").title = "Keyboard captured"; - } else { - $("hid-keyboard-led").className = "led-gray"; - $("hid-keyboard-led").title = "Keyboard free"; - } - }; - - var __keyboardHandler = function(event, state) { - if (event.preventDefault) { - event.preventDefault(); - } - var el_key = document.querySelector(`[data-key='${event.code}']`); - if (el_key && !event.repeat) { - __commonHandler(el_key, state, "pressed"); - if (tools.browser.is_mac) { - // https://bugs.chromium.org/p/chromium/issues/detail?id=28089 - // https://bugzilla.mozilla.org/show_bug.cgi?id=1299553 - if ((event.code === "MetaLeft" || event.code === "MetaRight") && !state) { - __keys.forEach(function(el_key) { - if (__isActive(el_key)) { - self.fireEvent(el_key.getAttribute("data-key"), false); - } - }); - } - } - __unholdModifiers(); - } - }; - - var __clickHandler = function(el_key, state) { - __commonHandler(el_key, state, "pressed"); - __unholdModifiers(); - }; - - var __toggleModifierHandler = function(el_key) { - __commonHandler(el_key, !__isActive(el_key), "holded"); - }; - - var __unholdModifiers = function() { - __modifiers.forEach(function(el_key) { - if (__isHolded(el_key)) { - __deactivate(el_key); - __sendKey(el_key, false); - } - }); - }; - - var __commonHandler = function(el_key, state, cls) { - if (state && !__isActive(el_key)) { - __deactivate(el_key); - __activate(el_key, cls); - __sendKey(el_key, true); - } else { - __deactivate(el_key); - __sendKey(el_key, false); - } - }; - - var __isPressed = function(el_key) { - var is_pressed = false; - Array.prototype.forEach.call(__resolveKeys(el_key), function(el_key) { - is_pressed = (is_pressed || el_key.classList.contains("pressed")); - }); - return is_pressed; - }; - - var __isHolded = function(el_key) { - var is_holded = false; - Array.prototype.forEach.call(__resolveKeys(el_key), function(el_key) { - is_holded = (is_holded || el_key.classList.contains("holded")); - }); - return is_holded; - }; - - var __isActive = function(el_key) { - var is_active = false; - Array.prototype.forEach.call(__resolveKeys(el_key), function(el_key) { - is_active = (is_active || el_key.classList.contains("pressed") || el_key.classList.contains("holded")); - }); - return is_active; - }; - - var __activate = function(el_key, cls) { - Array.prototype.forEach.call(__resolveKeys(el_key), function(el_key) { - el_key.classList.add(cls); - }); - }; - - var __deactivate = function(el_key) { - Array.prototype.forEach.call(__resolveKeys(el_key), function(el_key) { - el_key.classList.remove("pressed"); - el_key.classList.remove("holded"); - }); - }; - - var __resolveKeys = function(el_key) { - var code = el_key.getAttribute("data-key"); - return document.querySelectorAll(`[data-key='${code}']`); - }; - - var __sendKey = function(el_key, state) { - var code = el_key.getAttribute("data-key"); - tools.debug("Keyboard: key", (state ? "pressed:" : "released:"), code); - if (__ws) { - __ws.send(JSON.stringify({ - event_type: "key", - key: code, - state: state, - })); - } - }; - - __init__(); -} diff --git a/web/js/kvm/main.js b/web/js/kvm/main.js deleted file mode 100644 index 5c6d775a..00000000 --- a/web/js/kvm/main.js +++ /dev/null @@ -1,16 +0,0 @@ -var wm; - -function main() { - if (checkBrowser()) { - wm = new WindowManager(); - - tools.setOnClick($("show-about-button"), () => wm.showWindow($("about-window"))); - tools.setOnClick($("show-keyboard-button"), () => wm.showWindow($("keyboard-window"))); - tools.setOnClick($("show-stream-button"), () => wm.showWindow($("stream-window"))); - tools.setOnClick($("open-log-button"), () => window.open("/kvmd/log?seek=3600&follow=1", "_blank")); - - wm.showWindow($("stream-window")); - - new Session(); - } -} diff --git a/web/js/kvm/mouse.js b/web/js/kvm/mouse.js deleted file mode 100644 index 58e46d15..00000000 --- a/web/js/kvm/mouse.js +++ /dev/null @@ -1,160 +0,0 @@ -function Mouse() { - var self = this; - - /********************************************************************************/ - - var __ws = null; - - var __current_pos = {x: 0, y:0}; - var __sent_pos = {x: 0, y:0}; - var __wheel_delta = {x: 0, y: 0}; - - var __stream_hovered = false; - - var __init__ = function() { - $("hid-mouse-led").title = "Mouse free"; - - $("stream-box").onmouseenter = __hoverStream; - $("stream-box").onmouseleave = __leaveStream; - $("stream-box").onmousedown = (event) => __buttonHandler(event, true); - $("stream-box").onmouseup = (event) => __buttonHandler(event, false); - $("stream-box").oncontextmenu = (event) => event.preventDefault(); - $("stream-box").onmousemove = __moveHandler; - $("stream-box").onwheel = __wheelHandler; - $("stream-box").ontouchstart = (event) => __touchMoveHandler(event); - - Array.prototype.forEach.call(document.querySelectorAll("[data-mouse-button]"), function(el_button) { - var button = el_button.getAttribute("data-mouse-button"); - tools.setOnDown(el_button, () => __sendButton(button, true)); - tools.setOnUp(el_button, () => __sendButton(button, false)); - }); - - setInterval(__sendMove, 100); - }; - - /********************************************************************************/ - - self.setSocket = function(ws) { - __ws = ws; - if (ws) { - $("stream-box").classList.add("stream-box-mouse-enabled"); - } else { - $("stream-box").classList.remove("stream-box-mouse-enabled"); - } - __updateLeds(); - }; - - var __hoverStream = function() { - __stream_hovered = true; - __updateLeds(); - }; - - var __leaveStream = function() { - __stream_hovered = false; - __updateLeds(); - }; - - var __updateLeds = function() { - if (__ws && (__stream_hovered || tools.browser.is_ios)) { - // Mouse is always available on iOS via touchscreen - $("hid-mouse-led").className = "led-green"; - $("hid-mouse-led").title = "Mouse tracked"; - } else { - $("hid-mouse-led").className = "led-gray"; - $("hid-mouse-led").title = "Mouse free"; - } - }; - - var __buttonHandler = function(event, state) { - // https://www.w3schools.com/jsref/event_button.asp - event.preventDefault(); - switch (event.button) { - case 0: __sendButton("left", state); break; - case 2: __sendButton("right", state); break; - } - }; - - var __touchMoveHandler = function(event) { - event.preventDefault(); - if (event.touches[0].target && event.touches[0].target.getBoundingClientRect) { - var rect = event.touches[0].target.getBoundingClientRect(); - __current_pos = { - x: Math.round(event.touches[0].clientX - rect.left), - y: Math.round(event.touches[0].clientY - rect.top), - }; - __sendMove(); - } - }; - - var __moveHandler = function(event) { - var rect = event.target.getBoundingClientRect(); - __current_pos = { - x: Math.round(event.clientX - rect.left), - y: Math.round(event.clientY - rect.top), - }; - }; - - - var __sendButton = function(button, state) { - tools.debug("Mouse: button", (state ? "pressed:" : "released:"), button); - __sendMove(); - if (__ws) { - __ws.send(JSON.stringify({ - event_type: "mouse_button", - button: button, - state: state, - })); - } - }; - - var __sendMove = function() { - var pos = __current_pos; - if (pos.x !== __sent_pos.x || pos.y !== __sent_pos.y) { - var el_stream_image = $("stream-image"); - var to = { - x: __translate(pos.x, 0, el_stream_image.clientWidth, -32768, 32767), - y: __translate(pos.y, 0, el_stream_image.clientHeight, -32768, 32767), - }; - - tools.debug("Mouse: moved:", to); - if (__ws) { - __ws.send(JSON.stringify({ - event_type: "mouse_move", - to: to, - })); - } - __sent_pos = pos; - } - }; - - var __translate = function(x, a, b, c, d) { - return Math.round((x - a) / (b - a) * (d - c) + c); - }; - - var __wheelHandler = function(event) { - // https://learn.javascript.ru/mousewheel - if (event.preventDefault) { - event.preventDefault(); - } - - var delta = {x: 0, y: 0}; - - __wheel_delta.y += event.deltaY; - if (Math.abs(__wheel_delta.y) >= 100) { - delta.y = __wheel_delta.y / Math.abs(__wheel_delta.y) * (-5); - __wheel_delta.y = 0; - } - - if (delta.y) { - tools.debug("Mouse: scrolled:", delta); - if (__ws) { - __ws.send(JSON.stringify({ - event_type: "mouse_wheel", - delta: delta, - })); - } - } - }; - - __init__(); -} diff --git a/web/js/kvm/msd.js b/web/js/kvm/msd.js deleted file mode 100644 index c23de99d..00000000 --- a/web/js/kvm/msd.js +++ /dev/null @@ -1,193 +0,0 @@ -function Msd() { - var self = this; - - /********************************************************************************/ - - var __state = null; - var __upload_http = null; - var __image_file = null; - - var __init__ = function() { - $("msd-led").title = "Unknown state"; - - $("msd-select-new-image-file").onchange = __selectNewImageFile; - tools.setOnClick($("msd-select-new-image-button"), () => $("msd-select-new-image-file").click()); - - tools.setOnClick($("msd-upload-new-image-button"), __clickUploadNewImageButton); - tools.setOnClick($("msd-abort-uploading-button"), __clickAbortUploadingButton); - - tools.setOnClick($("msd-switch-to-kvm-button"), () => __clickSwitchButton("kvm")); - tools.setOnClick($("msd-switch-to-server-button"), () => __clickSwitchButton("server")); - - tools.setOnClick($("msd-reset-button"), __clickResetButton); - }; - - /********************************************************************************/ - - self.setState = function(state) { - __state = state; - __applyState(); - }; - - var __clickUploadNewImageButton = function() { - var form_data = new FormData(); - form_data.append("image_name", __image_file.name); - form_data.append("image_data", __image_file); - - __upload_http = new XMLHttpRequest(); - __upload_http.open("POST", "/kvmd/msd/write", true); - __upload_http.upload.timeout = 5000; - __upload_http.onreadystatechange = __uploadStateChange; - __upload_http.upload.onprogress = __uploadProgress; - __upload_http.send(form_data); - }; - - var __clickAbortUploadingButton = function() { - __upload_http.onreadystatechange = null; - __upload_http.upload.onprogress = null; - __upload_http.abort(); - __upload_http = null; - $("msd-progress").setAttribute("data-label", "Aborted"); - $("msd-progress-value").style.width = "0%"; - }; - - var __clickSwitchButton = function(to) { - var http = tools.makeRequest("POST", "/kvmd/msd/connect?to=" + to, function() { - if (http.readyState === 4) { - if (http.status !== 200) { - wm.error("Switch error:<br>", http.responseText); - } - } - __applyState(); - }); - __applyState(); - wm.switchDisabled($(`msd-switch-to-${to}-button`), true); - }; - - var __selectNewImageFile = function() { - var el_input = $("msd-select-new-image-file"); - var image_file = (el_input.files.length ? el_input.files[0] : null); - if (image_file && image_file.size > __state.info.size) { - wm.error("New image is too big for your Mass Storage Device.<br>Maximum:", __formatSize(__state.info.size)); - el_input.value = ""; - image_file = null; - } - __image_file = image_file; - __applyState(); - }; - - var __clickResetButton = function() { - var http = tools.makeRequest("POST", "/kvmd/msd/reset", function() { - if (http.readyState === 4) { - if (http.status !== 200) { - wm.error("MSD reset error:<br>", http.responseText); - } - } - __applyState(); - }); - __applyState(); - }; - - var __applyState = function() { - if (__state) { - if (__state.connected_to === "server") { - $("msd-another-another-user-uploads").style.display = "none"; - $("msd-led").className = "led-green"; - $("msd-status").innerHTML = $("msd-led").title = "Connected to Server"; - } else if (__state.busy) { - if (!__upload_http) { - $("msd-another-another-user-uploads").style.display = "block"; - } - $("msd-led").className = "led-yellow-rotating-fast"; - $("msd-status").innerHTML = $("msd-led").title = "Uploading new image"; - } else { - $("msd-another-another-user-uploads").style.display = "none"; - $("msd-led").className = "led-gray"; - if (__state.in_operate) { - $("msd-status").innerHTML = $("msd-led").title = "Connected to KVM"; - } else { - $("msd-status").innerHTML = $("msd-led").title = "Unavailable"; - } - } - - $("msd-not-in-operate").style.display = (__state.in_operate ? "none" : "block"); - $("msd-current-image-broken").style.display = ( - __state.in_operate && __state.info.image && - !__state.info.image.complete && !__state.busy ? "block" : "none" - ); - - $("msd-current-image-name").innerHTML = (__state.in_operate && __state.info.image ? __state.info.image.name : "None"); - $("msd-current-image-size").innerHTML = (__state.in_operate && __state.info.image ? __formatSize(__state.info.image.size) : "None"); - $("msd-storage-size").innerHTML = (__state.in_operate ? __formatSize(__state.info.size) : "Unavailable"); - - wm.switchDisabled($("msd-switch-to-kvm-button"), (!__state.in_operate || __state.connected_to === "kvm" || __state.busy)); - wm.switchDisabled($("msd-switch-to-server-button"), (!__state.in_operate || __state.connected_to === "server" || __state.busy)); - wm.switchDisabled($("msd-select-new-image-button"), (!__state.in_operate || __state.connected_to !== "kvm" || __state.busy || __upload_http)); - wm.switchDisabled($("msd-upload-new-image-button"), (!__state.in_operate || __state.connected_to !== "kvm" || __state.busy || !__image_file)); - wm.switchDisabled($("msd-abort-uploading-button"), (!__state.in_operate || !__upload_http)); - wm.switchDisabled($("msd-reset-button"), (!__state.in_operate || __upload_http)); - - $("msd-new-image").style.display = (__image_file ? "block" : "none"); - $("msd-progress").setAttribute("data-label", "Waiting for upload ..."); - $("msd-progress-value").style.width = "0%"; - $("msd-new-image-name").innerHTML = (__image_file ? __image_file.name : ""); - $("msd-new-image-size").innerHTML = (__image_file ? __formatSize(__image_file.size) : ""); - - } else { - $("msd-another-another-user-uploads").style.display = "none"; - $("msd-led").className = "led-gray"; - $("msd-status").innerHTML = ""; - $("msd-led").title = ""; - $("msd-not-in-operate").style.display = "none"; - $("msd-current-image-broken").style.display = "none"; - $("msd-current-image-name").innerHTML = ""; - $("msd-current-image-size").innerHTML = ""; - $("msd-storage-size").innerHTML = ""; - - wm.switchDisabled($("msd-switch-to-kvm-button"), true); - wm.switchDisabled($("msd-switch-to-server-button"), true); - wm.switchDisabled($("msd-select-new-image-button"), true); - wm.switchDisabled($("msd-upload-new-image-button"), true); - wm.switchDisabled($("msd-abort-uploading-button"), true); - wm.switchDisabled($("msd-reset-button"), true); - - $("msd-select-new-image-file").value = ""; - $("msd-new-image").style.display = "none"; - $("msd-progress").setAttribute("data-label", ""); - $("msd-progress-value").style.width = "0%"; - $("msd-new-image-name").innerHTML = ""; - $("msd-new-image-size").innerHTML = ""; - } - }; - - var __formatSize = function(size) { - if (size > 0) { - var index = Math.floor( Math.log(size) / Math.log(1024) ); - return (size / Math.pow(1024, index)).toFixed(2) * 1 + " " + ["B", "kB", "MB", "GB", "TB"][index]; - } else { - return 0; - } - }; - - var __uploadStateChange = function() { - if (__upload_http.readyState === 4) { - if (__upload_http.status !== 200) { - wm.error("Can't upload image to the Mass Storage Device:<br>", __upload_http.responseText); - } - $("msd-select-new-image-file").value = ""; - __image_file = null; - __upload_http = null; - __applyState(); - } - }; - - var __uploadProgress = function(event) { - if(event.lengthComputable) { - var percent = Math.round((event.loaded * 100) / event.total); - $("msd-progress").setAttribute("data-label", percent + "%"); - $("msd-progress-value").style.width = percent + "%"; - } - }; - - __init__(); -} diff --git a/web/js/kvm/session.js b/web/js/kvm/session.js deleted file mode 100644 index e3e74160..00000000 --- a/web/js/kvm/session.js +++ /dev/null @@ -1,143 +0,0 @@ -function Session() { - // var self = this; - - /********************************************************************************/ - - var __ws = null; - - var __ping_timer = null; - var __missed_heartbeats = 0; - - var __hid = new Hid(); - var __atx = new Atx(); - var __msd = new Msd(); - var __streamer = new Streamer(); - - var __init__ = function() { - $("link-led").title = "Not connected yet..."; - __startPoller(); - }; - - /********************************************************************************/ - - var __setKvmdInfo = function(state) { - if (state.meta) { - var text = JSON.stringify(state.meta, undefined, 4).replace(/ /g, " ").replace(/\n/g, "<br>"); - $("about-meta").innerHTML = ` - <span class="code-comment">// The Pi-KVM metadata.<br> - // You can get this json using handle <a target="_blank" href="/kvmd/info">/kvmd/info</a>.<br> - // In the standard configuration this data<br> - // is specified in the file /etc/kvmd/meta.yaml.</span><br> - <br> - ${text} - `; - if (state.meta.server && state.meta.server.host) { - $("kvmd-meta-server-host").innerHTML = "Server: " + state.meta.server.host; - document.title = "Pi-KVM Session: " + state.meta.server.host; - } else { - $("kvmd-meta-server-host").innerHTML = ""; - document.title = "Pi-KVM Session"; - } - } - - $("about-version-kvmd").innerHTML = state.version.kvmd; - $("about-version-streamer").innerHTML = `${state.version.streamer} (${state.streamer})`; - }; - - var __startPoller = function() { - $("link-led").className = "led-yellow"; - $("link-led").title = "Connecting..."; - - var http = tools.makeRequest("GET", "/ws_auth", function() { - if (http.readyState === 4) { - if (http.status === 200) { - var proto = (location.protocol === "https:" ? "wss" : "ws"); - __ws = new WebSocket(`${proto}://${location.host}/kvmd/ws`); - __ws.onopen = __wsOpenHandler; - __ws.onmessage = __wsMessageHandler; - __ws.onerror = __wsErrorHandler; - __ws.onclose = __wsCloseHandler; - } else { - __wsCloseHandler(null); - } - } - }); - }; - - var __wsOpenHandler = function(event) { - tools.debug("Session: socket opened:", event); - $("link-led").className = "led-green"; - $("link-led").title = "Connected"; - __hid.setSocket(__ws); - __missed_heartbeats = 0; - __ping_timer = setInterval(__pingServer, 1000); - }; - - var __wsMessageHandler = function(event) { - // tools.debug("Session: received socket data:", event.data); - event = JSON.parse(event.data); - if (event.msg_type === "pong") { - __missed_heartbeats = 0; - } else if (event.msg_type === "event") { - if (event.msg.event === "info_state") { - __setKvmdInfo(event.msg.event_attrs); - } else if (event.msg.event === "atx_state") { - __atx.setState(event.msg.event_attrs); - } else if (event.msg.event === "msd_state") { - __msd.setState(event.msg.event_attrs); - } else if (event.msg.event === "streamer_state") { - __streamer.setState(event.msg.event_attrs); - } - } - }; - - var __wsErrorHandler = function(event) { - tools.error("Session: socket error:", event); - if (__ws) { - __ws.onclose = null; - __ws.close(); - __wsCloseHandler(null); - } - }; - - var __wsCloseHandler = function(event) { - tools.debug("Session: socket closed:", event); - - $("link-led").className = "led-gray"; - - if (__ping_timer) { - clearInterval(__ping_timer); - __ping_timer = null; - } - - __hid.setSocket(null); - __atx.setState(null); - __msd.setState(null); - __streamer.setState(null); - __ws = null; - - setTimeout(function() { - $("link-led").className = "led-yellow"; - setTimeout(__startPoller, 500); - }, 500); - }; - - var __pingServer = function() { - try { - __missed_heartbeats += 1; - if (__missed_heartbeats >= 5) { - throw new Error("Too many missed heartbeats"); - } - __ws.send(JSON.stringify({"event_type": "ping"})); - } catch (err) { - tools.error("Session: ping error:", err.message); - if (__ws) { - __ws.onclose = null; - __ws.close(); - __wsCloseHandler(null); - } - } - }; - - __init__(); -} diff --git a/web/js/kvm/stream.js b/web/js/kvm/stream.js deleted file mode 100644 index 01ded5bc..00000000 --- a/web/js/kvm/stream.js +++ /dev/null @@ -1,221 +0,0 @@ -function Streamer() { - var self = this; - - /********************************************************************************/ - - var __resolution = {width: 640, height: 480}; - var __size_factor = 1; - var __client_key = tools.makeId(); - var __client_id = ""; - var __client_fps = -1; - var __prev = false; - - var __init__ = function() { - $("stream-led").title = "Stream inactive"; - - $("stream-quality-slider").min = 5; - $("stream-quality-slider").max = 100; - $("stream-quality-slider").step = 5; - $("stream-quality-slider").value = 80; - tools.setOnUpSlider($("stream-quality-slider"), 1000, __updateQualityValue, (value) => __sendParam("quality", value)); - - $("stream-desired-fps-slider").min = 0; - $("stream-desired-fps-slider").max = 30; - $("stream-desired-fps-slider").step = 1; - $("stream-desired-fps-slider").value = 0; - tools.setOnUpSlider($("stream-desired-fps-slider"), 1000, __updateDesiredFpsValue, (value) => __sendParam("desired_fps", value)); - - $("stream-size-slider").min = 20; - $("stream-size-slider").max = 200; - $("stream-size-slider").step = 5; - $("stream-size-slider").value = 100; - $("stream-size-slider").oninput = () => __resize(); - $("stream-size-slider").onchange = () => __resize(); - - tools.setOnClick($("stream-screenshot-button"), __clickScreenshotButton); - tools.setOnClick($("stream-reset-button"), __clickResetButton); - }; - - /********************************************************************************/ - - self.setState = function(state) { - if (state && state.state) { - var source = state.state.source; - var stream = state.state.stream; - - if (!__prev) { - $("stream-quality-slider").activated = false; - $("stream-desired-fps-slider").activated = false; - } - - if (!$("stream-quality-slider").activated) { - wm.switchDisabled($("stream-quality-slider"), false); - if ($("stream-quality-slider").value !== source.quality) { - $("stream-quality-slider").value = source.quality; - __updateQualityValue(source.quality); - } - } - - if (!$("stream-desired-fps-slider").activated) { - wm.switchDisabled($("stream-desired-fps-slider"), false); - if ($("stream-desired-fps-slider").value !== source.desired_fps) { - $("stream-desired-fps-slider").value = source.desired_fps; - __updateDesiredFpsValue(source.desired_fps); - } - } - - if (__resolution.width !== source.resolution.width || __resolution.height !== source.resolution.height) { - __resolution = source.resolution; - if ($("stream-auto-resize-checkbox").checked) { - __adjustSizeFactor(); - } else { - __applySizeFactor(); - } - } - - var stream_client = tools.getCookie("stream_client"); - if (!__client_id && stream_client && stream_client.startsWith(__client_key + "/")) { - tools.info("Stream: found acceptable stream_client cookie:", stream_client); - __client_id = stream_client.slice(stream_client.indexOf("/") + 1); - } - - if (stream.clients_stat.hasOwnProperty(__client_id)) { - __client_fps = stream.clients_stat[__client_id].fps; - } else { - __clearState(); - } - - if (!__prev) { - var path = "/streamer/stream?key=" + __client_key; - if (tools.browser.is_chrome || tools.browser.is_blink) { - // uStreamer fix for Blink https://bugs.chromium.org/p/chromium/issues/detail?id=527446 - tools.info("Stream: using advance_headers=1 to fix Blink MJPG bugs"); - path += "&advance_headers=1"; - } else if (tools.browser.is_safari || tools.browser.is_ios) { - // uStreamer fix for WebKit - tools.info("Stream: using dual_final_frames=1 to fix WebKit MJPG bugs"); - path += "&dual_final_frames=1"; - } - $("stream-image").src = path; - $("stream-image").className = "stream-image-active"; - $("stream-box").classList.remove("stream-box-inactive"); - $("stream-led").className = "led-green"; - $("stream-led").title = "Stream is active"; - wm.switchDisabled($("stream-screenshot-button"), false); - wm.switchDisabled($("stream-reset-button"), false); - tools.info("Stream: acquired"); - __prev = true; - } - - __updateStreamHeader(true); - - } else { - __clearState(); - } - }; - - var __clearState = function() { - tools.info("Stream: refreshing ..."); - - $("stream-image").className = "stream-image-inactive"; - $("stream-box").classList.add("stream-box-inactive"); - $("stream-led").className = "led-gray"; - $("stream-led").title = "Stream inactive"; - wm.switchDisabled($("stream-screenshot-button"), true); - wm.switchDisabled($("stream-reset-button"), true); - wm.switchDisabled($("stream-quality-slider"), true); - wm.switchDisabled($("stream-desired-fps-slider"), true); - - __client_key = tools.makeId(); - __client_id = ""; - __client_fps = -1; - __prev = false; - __updateStreamHeader(false); - }; - - var __updateQualityValue = function(value) { - $("stream-quality-value").innerHTML = value + "%"; - }; - - var __updateDesiredFpsValue = function(value) { - $("stream-desired-fps-value").innerHTML = (value === 0 ? "Unlimited" : value); - }; - - var __updateStreamHeader = function(online) { - var el_grab = document.querySelector("#stream-window-header .window-grab"); - var el_info = $("stream-info"); - if (online) { - var fps_suffix = (__client_fps >= 0 ? ` / ${__client_fps} fps` : ""); - el_grab.innerHTML = el_info.innerHTML = `Stream – ${__resolution.width}x${__resolution.height}${fps_suffix}`; - } else { - el_grab.innerHTML = el_info.innerHTML = "Stream – offline"; - } - }; - - var __clickScreenshotButton = function() { - var el_a = document.createElement("a"); - el_a.href = "/streamer/snapshot"; - el_a.target = "_blank"; - document.body.appendChild(el_a); - el_a.click(); - setTimeout(() => document.body.removeChild(el_a), 0); - }; - - var __clickResetButton = function() { - var http = tools.makeRequest("POST", "/kvmd/streamer/reset", function() { - if (http.readyState === 4) { - if (http.status !== 200) { - wm.error("Can't reset stream:<br>", http.responseText); - } - } - }); - }; - - var __sendParam = function(name, value) { - var http = tools.makeRequest("POST", `/kvmd/streamer/set_params?${name}=${value}`, function() { - if (http.readyState === 4) { - if (http.status !== 200) { - wm.error("Can't configure stream:<br>", http.responseText); - } - } - }); - }; - - var __resize = function(center=false) { - var size = $("stream-size-slider").value; - $("stream-size-value").innerHTML = size + "%"; - __size_factor = size / 100; - __applySizeFactor(center); - }; - - var __adjustSizeFactor = function() { - var el_window = $("stream-window"); - var el_slider = $("stream-size-slider"); - var view = wm.getViewGeometry(); - - for (var size = 100; size >= el_slider.min; size -= el_slider.step) { - tools.info("Stream: adjusting size:", size); - $("stream-size-slider").value = size; - __resize(true); - - var rect = el_window.getBoundingClientRect(); - if ( - rect.bottom <= view.bottom - && rect.top >= view.top - && rect.left >= view.left - && rect.right <= view.right - ) { - break; - } - } - }; - - var __applySizeFactor = function(center=false) { - var el_stream_image = $("stream-image"); - el_stream_image.style.width = __resolution.width * __size_factor + "px"; - el_stream_image.style.height = __resolution.height * __size_factor + "px"; - wm.showWindow($("stream-window"), false, center); - }; - - __init__(); -} diff --git a/web/js/tools.js b/web/js/tools.js deleted file mode 100644 index 81970ef8..00000000 --- a/web/js/tools.js +++ /dev/null @@ -1,133 +0,0 @@ -var tools = new function() { - var __debug = (new URL(window.location.href)).searchParams.get("debug"); - - this.makeRequest = function(method, url, callback, timeout=null) { - var http = new XMLHttpRequest(); - http.open(method, url, true); - http.onreadystatechange = callback; - http.timeout = (timeout ? timeout : 5000); - http.send(); - return http; - }; - - this.makeId = function() { - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - var id = ""; - for (var count = 0; count < 16; ++count) { - id += chars.charAt(Math.floor(Math.random() * chars.length)); - } - return id; - }; - - this.getCookie = function(name) { - var matches = document.cookie.match(new RegExp( - "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, "\\$1") + "=([^;]*)" // eslint-disable-line no-useless-escape - )); - return (matches ? decodeURIComponent(matches[1]) : ""); - }; - - this.setOnClick = function(el, callback) { - el.onclick = el.ontouchend = function(event) { - event.preventDefault(); - callback(); - }; - }; - this.setOnDown = function(el, callback) { - el.onmousedown = el.ontouchstart = function(event) { - event.preventDefault(); - callback(); - }; - }; - this.setOnUp = function(el, callback) { - el.onmouseup = el.ontouchend = function(event) { - event.preventDefault(); - callback(); - }; - }; - - this.setOnUpSlider = function(el, delay, display_callback, execute_callback) { - el.execution_timer = null; - el.activated = false; - - var clear_timer = function() { - if (el.execution_timer) { - clearTimeout(el.execution_timer); - el.execution_timer = null; - } - }; - - el.oninput = el.onchange = () => display_callback(el.value); - - el.onmousedown = el.ontouchstart = function() { - clear_timer(); - el.activated = true; - }; - - el.onmouseup = el.ontouchend = function(event) { - event.preventDefault(); - clear_timer(); - el.execution_timer = setTimeout(function() { - execute_callback(el.value); - }, delay); - }; - }; - - this.debug = function(...args) { - if (__debug) { - console.log("LOG/DEBUG", ...args); // eslint-disable-line no-console - } - }; - this.info = (...args) => console.log("LOG/INFO", ...args); // eslint-disable-line no-console - this.error = (...args) => console.error("LOG/ERROR", ...args); // eslint-disable-line no-console - - this.browser = new function() { - // https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser/9851769 - - // Opera 8.0+ - var is_opera = ( - (!!window.opr && !!opr.addons) // eslint-disable-line no-undef - || !!window.opera - || (navigator.userAgent.indexOf(" OPR/") >= 0) - ); - - // Firefox 1.0+ - var is_firefox = (typeof InstallTrigger !== "undefined"); - - // Safari 3.0+ "[object HTMLElementConstructor]" - var is_safari = (/constructor/i.test(window.HTMLElement) || (function (p) { - return p.toString() === "[object SafariRemoteNotification]"; - })(!window["safari"] || (typeof safari !== "undefined" && safari.pushNotification))); // eslint-disable-line no-undef - - // Chrome 1+ - var is_chrome = (!!window.chrome && !!window.chrome.webstore); - - // Blink engine detection - var is_blink = ((is_chrome || is_opera) && !!window.CSS); - - // iOS browsers - // https://stackoverflow.com/questions/9038625/detect-if-device-is-ios - var is_ios = (!!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)); - - // Any browser on Mac - var is_mac = (( - window.navigator.oscpu - || window.navigator.platform - || window.navigator.appVersion - || "Unknown" - ).indexOf("Mac") !== -1); - - return { - "is_opera": is_opera, - "is_firefox": is_firefox, - "is_safari": is_safari, - "is_chrome": is_chrome, - "is_blink": is_blink, - "is_ios": is_ios, - "is_mac": is_mac, - }; - }; - this.info("Browser:", this.browser); -}; - -var $ = (id) => document.getElementById(id); -var $$ = (cls) => document.getElementsByClassName(cls); diff --git a/web/js/wm.js b/web/js/wm.js deleted file mode 100644 index c292ece7..00000000 --- a/web/js/wm.js +++ /dev/null @@ -1,387 +0,0 @@ -function WindowManager() { - var self = this; - - /********************************************************************************/ - - var __top_z_index = 0; - var __windows = []; - var __menu_items = []; - - var __init__ = function() { - Array.prototype.forEach.call(document.querySelectorAll("button"), function(el_button) { - // XXX: Workaround for iOS Safari: - // https://stackoverflow.com/questions/3885018/active-pseudo-class-doesnt-work-in-mobile-safari - el_button.ontouchstart = function() {}; - }); - - Array.prototype.forEach.call($$("menu-item"), function(el_item) { - el_item.parentElement.querySelector(".menu-item-content").setAttribute("tabindex", "-1"); - tools.setOnDown(el_item, () => __toggleMenu(el_item)); - __menu_items.push(el_item); - }); - - Array.prototype.forEach.call($$("window"), function(el_window) { - el_window.setAttribute("tabindex", "-1"); - __makeWindowMovable(el_window); - __windows.push(el_window); - - var el_button = el_window.querySelector(".window-header .window-button-close"); - if (el_button) { - tools.setOnClick(el_button, function() { - el_window.style.visibility = "hidden"; - __activateLastWindow(el_window); - }); - } - }); - - window.onmouseup = __globalMouseButtonHandler; - window.ontouchend = __globalMouseButtonHandler; - - window.addEventListener("focusin", __focusIn); - window.addEventListener("focusout", __focusOut); - - window.addEventListener("resize", () => __organizeWindowsOnResize(false)); - window.addEventListener("orientationchange", () => __organizeWindowsOnResize(true)); - }; - - /********************************************************************************/ - - self.error = (...args) => __modalDialog("Error", args.join(" "), true, false); - self.confirm = (...args) => __modalDialog("Question", args.join(" "), true, true); - - var __modalDialog = function(header, text, ok, cancel) { - var el_modal = document.createElement("div"); - el_modal.className = "modal"; - el_modal.style.visibility = "visible"; - - var el_window = document.createElement("div"); - el_window.className = "modal-window"; - el_window.setAttribute("tabindex", "-1"); - el_modal.appendChild(el_window); - - var el_header = document.createElement("div"); - el_header.className = "modal-header"; - el_header.innerHTML = header; - el_window.appendChild(el_header); - - var el_content = document.createElement("div"); - el_content.className = "modal-content"; - el_content.innerHTML = text; - el_window.appendChild(el_content); - - var promise = null; - if (ok || cancel) { - promise = new Promise(function(resolve) { - var el_buttons = document.createElement("div"); - el_buttons.className = "modal-buttons"; - el_window.appendChild(el_buttons); - - function close(retval) { - el_window.style.visibility = "hidden"; - el_modal.outerHTML = ""; - var index = __windows.indexOf(el_modal); - if (index !== -1) { - __windows.splice(index, 1); - } - __activateLastWindow(el_modal); - resolve(retval); - } - - if (cancel) { - var el_cancel_button = document.createElement("button"); - el_cancel_button.innerHTML = "Cancel"; - tools.setOnClick(el_cancel_button, () => close(false)); - el_buttons.appendChild(el_cancel_button); - } - if (ok) { - var el_ok_button = document.createElement("button"); - el_ok_button.innerHTML = "OK"; - tools.setOnClick(el_ok_button, () => close(true)); - el_buttons.appendChild(el_ok_button); - } - if (ok && cancel) { - el_ok_button.className = "row50"; - el_cancel_button.className = "row50"; - } - - el_window.onkeyup = function(event) { - event.preventDefault(); - if (ok && event.code === "Enter") { - el_ok_button.click(); - } else if (cancel && event.code === "Escape") { - el_cancel_button.click(); - } - }; - }); - } - - __windows.push(el_modal); - document.body.appendChild(el_modal); - __activateWindow(el_modal); - - return promise; - }; - - self.switchDisabled = function(el, disabled) { - if (disabled && document.activeElement === el) { - var el_to_focus = ( - el.closest(".modal-window") - || el.closest(".window") - || el.closest(".menu-item-content") - ); - if (el_to_focus) { - el_to_focus.focus(); - } - } - el.disabled = disabled; - }; - - self.showWindow = function(el_window, activate=true, center=false) { - if (!__isWindowOnPage(el_window) || el_window.hasAttribute("data-centered") || center) { - var view = self.getViewGeometry(); - var rect = el_window.getBoundingClientRect(); - - el_window.style.top = Math.max($("menu").clientHeight, Math.round((view.bottom - rect.height) / 2)) + "px"; - el_window.style.left = Math.round((view.right - rect.width) / 2) + "px"; - el_window.setAttribute("data-centered", ""); - } - - el_window.style.visibility = "visible"; - if (activate) { - __activateWindow(el_window); - } - }; - - self.getViewGeometry = function() { - return { - top: $("menu").clientHeight, - bottom: Math.max(document.documentElement.clientHeight, window.innerHeight || 0), - left: 0, - right: Math.max(document.documentElement.clientWidth, window.innerWidth || 0), - }; - }; - - var __isWindowOnPage = function(el_window) { - var view = self.getViewGeometry(); - var rect = el_window.getBoundingClientRect(); - - return ( - (rect.bottom - el_window.clientHeight / 1.5) <= view.bottom - && rect.top >= view.top - && (rect.left + el_window.clientWidth / 1.5) >= view.left - && (rect.right - el_window.clientWidth / 1.5) <= view.right - ); - }; - - var __toggleMenu = function(el_a) { - var all_hidden = true; - - __menu_items.forEach(function(el_item) { - var el_menu = el_item.parentElement.querySelector(".menu-item-content"); - if (el_item === el_a && window.getComputedStyle(el_menu, null).visibility === "hidden") { - el_item.classList.add("menu-item-selected"); - el_menu.style.visibility = "visible"; - el_menu.focus(); - all_hidden &= false; - } else { - el_item.classList.remove("menu-item-selected"); - el_menu.style.visibility = "hidden"; - } - }); - - if (all_hidden) { - document.onkeyup = null; - __activateLastWindow(); - } else { - document.onkeyup = function(event) { - if (event.code === "Escape") { - event.preventDefault(); - __closeAllMenues(); - __activateLastWindow(); - } - }; - } - }; - - var __closeAllMenues = function() { - document.onkeyup = null; - __menu_items.forEach(function(el_item) { - var el_menu = el_item.parentElement.querySelector(".menu-item-content"); - el_item.classList.remove("menu-item-selected"); - el_menu.style.visibility = "hidden"; - }); - }; - - var __focusIn = function(event) { - var el_parent; - if ((el_parent = event.target.closest(".modal-window")) !== null) { - el_parent.classList.add("window-active"); - } else if ((el_parent = event.target.closest(".window")) !== null) { - el_parent.classList.add("window-active"); - } else if ((el_parent = event.target.closest(".menu-item-content")) !== null) { - el_parent.classList.add("menu-item-content-active"); - } - tools.debug("Focus in:", el_parent); - }; - - var __focusOut = function(event) { - var el_parent; - if ((el_parent = event.target.closest(".modal-window")) !== null) { - el_parent.classList.remove("window-active"); - } else if ((el_parent = event.target.closest(".window")) !== null) { - el_parent.classList.remove("window-active"); - } else if ((el_parent = event.target.closest(".menu-item-content")) !== null) { - el_parent.classList.remove("menu-item-content-active"); - } - tools.debug("Focus out:", el_parent); - }; - - var __globalMouseButtonHandler = function(event) { - if (!event.target.matches(".menu-item")) { - for (var el_item = event.target; el_item && el_item !== document; el_item = el_item.parentNode) { - if (el_item.hasAttribute("data-force-hide-menu")) { - break; - } else if (el_item.hasAttribute("data-dont-hide-menu")) { - return; - } - } - __closeAllMenues(); - __activateLastWindow(); - } - }; - - var __organizeWindowsOnResize = function(orientation) { - var view = self.getViewGeometry(); - - Array.prototype.forEach.call($$("window"), function(el_window) { - if (el_window.style.visibility === "visible" && (orientation || el_window.hasAttribute("data-centered"))) { - var rect = el_window.getBoundingClientRect(); - - el_window.style.top = Math.max($("menu").clientHeight, Math.round((view.bottom - rect.height) / 2)) + "px"; - el_window.style.left = Math.round((view.right - rect.width) / 2) + "px"; - el_window.setAttribute("data-centered", ""); - } - }); - }; - - var __activateLastWindow = function(el_except_window=null) { - var el_last_window = null; - - if (document.activeElement) { - el_last_window = (document.activeElement.closest(".modal-window") || document.activeElement.closest(".window")); - } - - if (!el_last_window || el_last_window === el_except_window) { - var max_z_index = 0; - - __windows.forEach(function(el_window) { - var z_index = parseInt(window.getComputedStyle(el_window, null).zIndex) || 0; - var visibility = window.getComputedStyle(el_window, null).visibility; - - if (max_z_index < z_index && visibility !== "hidden" && el_window !== el_except_window) { - el_last_window = el_window; - max_z_index = z_index; - } - }); - } - - if (el_last_window) { - tools.debug("Activating last window:", el_last_window); - __activateWindow(el_last_window); - } - }; - - var __activateWindow = function(el_window) { - if (window.getComputedStyle(el_window, null).visibility !== "hidden") { - var el_to_focus; - var el_window_contains_focus; - - if (el_window.className === "modal") { - el_to_focus = el_window.querySelector(".modal-window"); - el_window_contains_focus = (document.activeElement && document.activeElement.closest(".modal-window")); - } else { // .window - el_to_focus = el_window; - el_window_contains_focus = (document.activeElement && document.activeElement.closest(".window")); - } - - if (el_window.className !== "modal" && parseInt(el_window.style.zIndex) !== __top_z_index) { - __top_z_index += 1; - el_window.style.zIndex = __top_z_index; - tools.debug("UI: activated window:", el_window); - } - - if (el_window !== el_window_contains_focus) { - el_to_focus.focus(); - tools.debug("UI: focused window:", el_window); - } - } - }; - - var __makeWindowMovable = function(el_window) { - var el_header = el_window.querySelector(".window-header"); - var el_grab = el_window.querySelector(".window-header .window-grab"); - - var prev_pos = {x: 0, y: 0}; - - function startMoving(event) { - __closeAllMenues(); - __activateWindow(el_window); - event = (event || window.event); - event.preventDefault(); - - if (!event.touches || event.touches.length === 1) { - el_header.classList.add("window-header-grabbed"); - - prev_pos = getEventPosition(event); - - document.onmousemove = doMoving; - document.onmouseup = stopMoving; - - document.ontouchmove = doMoving; - document.ontouchend = stopMoving; - } - } - - function doMoving(event) { - el_window.removeAttribute("data-centered"); - - event = (event || window.event); - event.preventDefault(); - - var event_pos = getEventPosition(event); - var x = prev_pos.x - event_pos.x; - var y = prev_pos.y - event_pos.y; - - el_window.style.top = (el_window.offsetTop - y) + "px"; - el_window.style.left = (el_window.offsetLeft - x) + "px"; - - prev_pos = event_pos; - } - - function stopMoving() { - el_header.classList.remove("window-header-grabbed"); - - document.onmousemove = null; - document.onmouseup = null; - - document.ontouchmove = null; - document.ontouchend = null; - } - - function getEventPosition(event) { - if (event.touches) { - return {x: event.touches[0].clientX, y: event.touches[0].clientY}; - } else { - return {x: event.clientX, y: event.clientY}; - } - } - - el_window.setAttribute("data-centered", ""); - el_window.onclick = el_window.ontouchend = () => __activateWindow(el_window); - - el_grab.onmousedown = startMoving; - el_grab.ontouchstart = startMoving; - }; - - __init__(); -} |