diff options
author | Maxim Devaev <[email protected]> | 2021-04-12 15:26:32 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2021-04-12 15:26:32 +0300 |
commit | 3af4a8b852019993ee31becd5651734377da6ec9 (patch) | |
tree | 499b77bfaa0c6f939175ea167d5ccb3956be95f0 /web/share/js | |
parent | 8158941833bd8a50278b61967e00d23522e633d7 (diff) |
Rework of #39 (#40)
* Rework of #39 patch from @arykov (thanks)
* styled resize corner
* fixed squashing of resizaable window on moving
* keep window size and opsition after full screen
* not necessary
* attempt to fix desktop overflow
* improved
* ios fixes
* refactoring
Diffstat (limited to 'web/share/js')
-rw-r--r-- | web/share/js/keypad.js | 10 | ||||
-rw-r--r-- | web/share/js/kvm/mouse.js | 31 | ||||
-rw-r--r-- | web/share/js/kvm/session.js | 2 | ||||
-rw-r--r-- | web/share/js/kvm/stream.js | 64 | ||||
-rw-r--r-- | web/share/js/tools.js | 2 | ||||
-rw-r--r-- | web/share/js/wm.js | 124 |
6 files changed, 157 insertions, 76 deletions
diff --git a/web/share/js/keypad.js b/web/share/js/keypad.js index 554e43cf..23ed0620 100644 --- a/web/share/js/keypad.js +++ b/web/share/js/keypad.js @@ -138,7 +138,7 @@ export function Keypad(keys_parent, key_callback) { var __isPressed = function(el_key) { let is_pressed = false; let el_keys = __resolveKeys(el_key); - for (let el_key of el_keys) { + for (el_key of el_keys) { is_pressed = (is_pressed || el_key.classList.contains("pressed")); } return is_pressed; @@ -147,7 +147,7 @@ export function Keypad(keys_parent, key_callback) { var __isHolded = function(el_key) { let is_holded = false; let el_keys = __resolveKeys(el_key); - for (let el_key of el_keys) { + for (el_key of el_keys) { is_holded = (is_holded || el_key.classList.contains("holded")); } return is_holded; @@ -156,7 +156,7 @@ export function Keypad(keys_parent, key_callback) { var __isActive = function(el_key) { let is_active = false; let el_keys = __resolveKeys(el_key); - for (let el_key of el_keys) { + for (el_key of el_keys) { is_active = (is_active || el_key.classList.contains("pressed") || el_key.classList.contains("holded")); } return is_active; @@ -164,14 +164,14 @@ export function Keypad(keys_parent, key_callback) { var __activate = function(el_key, cls) { let el_keys = __resolveKeys(el_key); - for (let el_key of el_keys) { + for (el_key of el_keys) { el_key.classList.add(cls); } }; var __deactivate = function(el_key) { let el_keys = __resolveKeys(el_key); - for (let el_key of el_keys) { + for (el_key of el_keys) { el_key.classList.remove("pressed"); el_key.classList.remove("holded"); } diff --git a/web/share/js/kvm/mouse.js b/web/share/js/kvm/mouse.js index 3ac7935e..2893a5ae 100644 --- a/web/share/js/kvm/mouse.js +++ b/web/share/js/kvm/mouse.js @@ -40,8 +40,8 @@ export function Mouse(record_callback) { var __keypad = null; - var __current_pos = {x: 0, y:0}; - var __sent_pos = {x: 0, y:0}; + var __current_pos = {x: 0, y: 0}; + var __sent_pos = {x: 0, y: 0}; var __wheel_delta = {x: 0, y: 0}; var __relative_deltas = []; @@ -210,15 +210,16 @@ export function Mouse(record_callback) { if (__absolute) { let pos = __current_pos; if (pos.x !== __sent_pos.x || pos.y !== __sent_pos.y) { - let el_stream_image = $("stream-image"); - let 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); - __sendEvent("mouse_move", {"to": to}); - __sent_pos = pos; + let geometry = $("stream-box").stream_geometry; + if (geometry) { + let to = { + x: __translate(pos.x, geometry.x, geometry.width, -32768, 32767), + y: __translate(pos.y, geometry.y, geometry.height, -32768, 32767), + }; + tools.debug("Mouse: moved:", to); + __sendEvent("mouse_move", {"to": to}); + __sent_pos = pos; + } } } else if (__relative_deltas.length) { tools.debug("Mouse: relative:", __relative_deltas); @@ -228,7 +229,13 @@ export function Mouse(record_callback) { }; var __translate = function(x, a, b, c, d) { - return Math.round((x - a) / (b - a) * (d - c) + c); + let translated = Math.round((x - a) / b * (d - c) + c); + if (translated < c) { + return c; + } else if (translated > d) { + return d; + } + return translated; }; var __streamWheelHandler = function(event) { diff --git a/web/share/js/kvm/session.js b/web/share/js/kvm/session.js index 2e4c4f6d..5aa0a6a0 100644 --- a/web/share/js/kvm/session.js +++ b/web/share/js/kvm/session.js @@ -47,7 +47,7 @@ export function Session() { var __hid = new Hid(); var __atx = new Atx(); var __msd = new Msd(); - var __streamer = new Streamer(); + var __streamer = new Streamer(__hid); var __wol = new WakeOnLan(); var __gpio = new Gpio(); diff --git a/web/share/js/kvm/stream.js b/web/share/js/kvm/stream.js index 83e3c4d4..2db37608 100644 --- a/web/share/js/kvm/stream.js +++ b/web/share/js/kvm/stream.js @@ -34,8 +34,6 @@ export function Streamer() { var __resolution = {width: 640, height: 480}; - var __size_factor = 1; - var __mjpeg_key = tools.makeId(); var __mjpeg_id = ""; var __mjpeg_fps = -1; @@ -53,10 +51,6 @@ export function Streamer() { $("stream-resolution-selector").onchange = (() => __sendParam("resolution", $("stream-resolution-selector").value)); - tools.sliderSetParams($("stream-size-slider"), 20, 200, 5, 100); - $("stream-size-slider").oninput = () => __resize(); - $("stream-size-slider").onchange = () => __resize(); - tools.setOnClick($("stream-screenshot-button"), __clickScreenshotButton); tools.setOnClick($("stream-reset-button"), __clickResetButton); @@ -65,6 +59,7 @@ export function Streamer() { self.setState(__state_for_invisible); } }; + $("stream-window").resize_hook = __resizeHook; }; /************************************************************************/ @@ -88,6 +83,11 @@ export function Streamer() { } if (state && state.streamer) { + if (!window.ResizeObserver) { + // Browsers that don't support this API(on lower versions of iOS for example) + __resizeHook(); + } + if (!$("stream-quality-slider").activated) { wm.setElementEnabled($("stream-quality-slider"), true); if ($("stream-quality-slider").value !== state.streamer.encoder.quality) { @@ -107,13 +107,8 @@ export function Streamer() { } let resolution_str = __makeStringResolution(state.streamer.source.resolution); - if (__makeStringResolution(__resolution) != resolution_str) { + if (__makeStringResolution(__resolution) !== resolution_str) { __resolution = state.streamer.source.resolution; - if ($("stream-auto-resize-switch").checked) { - __adjustSizeFactor(); - } else { - __applySizeFactor(); - } } if (state.features.resolution) { @@ -260,40 +255,17 @@ export function Streamer() { }); }; - var __resize = function() { - let size = $("stream-size-slider").value; - $("stream-size-value").innerHTML = `${size}%`; - __size_factor = size / 100; - __applySizeFactor(); - }; - - var __adjustSizeFactor = function() { - let el_window = $("stream-window"); - let el_slider = $("stream-size-slider"); - let view = wm.getViewGeometry(); - - for (let size = 100; size >= el_slider.min; size -= el_slider.step) { - tools.info("Stream: adjusting size:", size); - $("stream-size-slider").value = size; - __resize(); - - let 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() { - let el = $("stream-image"); - el.style.width = __resolution.width * __size_factor + "px"; - el.style.height = __resolution.height * __size_factor + "px"; - wm.showWindow($("stream-window"), false); + var __resizeHook = function() { + let rect = $("stream-image").getBoundingClientRect(); + let width = $("stream-image").naturalWidth; + let height = $("stream-image").naturalHeight; + let ratio = Math.min(rect.width / width, rect.height / height); + $("stream-box").stream_geometry = { + "x": Math.round((rect.width - ratio * width) / 2), + "y": Math.round((rect.height - ratio * height) / 2), + "width": Math.round(ratio * width), + "height": Math.round(ratio * height), + }; }; var __makeStringResolution = function(resolution) { diff --git a/web/share/js/tools.js b/web/share/js/tools.js index d6965803..521cb1a0 100644 --- a/web/share/js/tools.js +++ b/web/share/js/tools.js @@ -243,5 +243,5 @@ export var tools = new function() { }; export var $ = (id) => document.getElementById(id); -export var $$ = (cls) => document.getElementsByClassName(cls); +export var $$ = (cls) => [].slice.call(document.getElementsByClassName(cls)); export var $$$ = (selector) => document.querySelectorAll(selector); diff --git a/web/share/js/wm.js b/web/share/js/wm.js index f879e3e8..49e79ecb 100644 --- a/web/share/js/wm.js +++ b/web/share/js/wm.js @@ -54,14 +54,37 @@ function __WindowManager() { __menu_buttons.push(el_button); } + if (!window.ResizeObserver) { + tools.error("ResizeObserver not supported"); + } + for (let el_window of $$("window")) { el_window.setAttribute("tabindex", "-1"); __makeWindowMovable(el_window); __windows.push(el_window); - let el_button = el_window.querySelector(".window-header .window-button-close"); - if (el_button) { - tools.setOnClick(el_button, function() { + if (el_window.classList.contains("window-resizable") && window.ResizeObserver) { + new ResizeObserver(function() { + // При переполнении рабочей области сократить размер окна по высоте. + // По ширине оно настраивается само в CSS. + let view = self.getViewGeometry(); + let rect = el_window.getBoundingClientRect(); + if ((rect.bottom - rect.top) > (view.bottom - view.top)) { + el_window.style.height = view.bottom - view.top + "px"; + } + + if (el_window.hasAttribute("data-centered")) { + __centerWindow(el_window); + } + if (el_window.resize_hook) { + el_window.resize_hook(); + } + }).observe(el_window); + } + + let el_close_button = el_window.querySelector(".window-header .window-button-close"); + if (el_close_button) { + tools.setOnClick(el_close_button, function() { let close_window = function() { __closeWindow(el_window); __activateLastWindow(el_window); @@ -78,6 +101,22 @@ function __WindowManager() { } }); } + + let el_maximize_button = el_window.querySelector(".window-header .window-button-maximize"); + if (el_maximize_button) { + tools.setOnClick(el_maximize_button, function() { + __maximizeWindow(el_window); + __activateLastWindow(el_window); + }); + } + + let el_full_screen_button = el_window.querySelector(".window-header .window-button-full-screen"); + if (el_full_screen_button) { + tools.setOnClick(el_full_screen_button, function() { + __fullScreenWindow(el_window); + __activateLastWindow(el_window); + }); + } } window.onmouseup = __globalMouseButtonHandler; @@ -86,8 +125,10 @@ function __WindowManager() { window.addEventListener("focusin", __focusIn); window.addEventListener("focusout", __focusOut); - window.addEventListener("resize", __organizeWindowsOnResize); - window.addEventListener("orientationchange", __organizeWindowsOnResize); + window.addEventListener("resize", __organizeWindowsOnBrowserResize); + window.addEventListener("orientationchange", __organizeWindowsOnBrowserResize); + + document.onfullscreenchange = __onFullScreenChange; }; /************************************************************************/ @@ -205,7 +246,7 @@ function __WindowManager() { if (activate) { __activateWindow(el_window); } - if (Object.prototype.hasOwnProperty.call(el_window, "show_hook")) { + if (el_window.show_hook) { if (showed) { el_window.show_hook(); } @@ -239,7 +280,7 @@ function __WindowManager() { let el_menu = el_button.parentElement.querySelector(".menu"); if (el_button === el_a && window.getComputedStyle(el_menu, null).visibility === "hidden") { let rect = el_menu.getBoundingClientRect(); - let offset = self.getViewGeometry().right - (rect.x + el_menu.clientWidth + 2); // + 2 is ugly hack + let offset = self.getViewGeometry().right - (rect.left + el_menu.clientWidth + 2); // + 2 is ugly hack if (offset < 0) { el_menu.style.right = "0px"; } else { @@ -319,7 +360,7 @@ function __WindowManager() { } }; - var __organizeWindowsOnResize = function() { + var __organizeWindowsOnBrowserResize = function() { for (let el_window of $$("window")) { if (el_window.style.visibility === "visible") { __organizeWindow(el_window); @@ -331,10 +372,19 @@ function __WindowManager() { let view = self.getViewGeometry(); let rect = el_window.getBoundingClientRect(); + if (el_window.classList.contains("window-resizable")) { + // При переполнении рабочей области сократить размер окна + if ((rect.bottom - rect.top) > (view.bottom - view.top)) { + el_window.style.height = view.bottom - view.top + "px"; + } + if ((rect.right - rect.left) > (view.right - view.left)) { + el_window.style.width = view.right - view.left + "px"; + } + rect = el_window.getBoundingClientRect(); + } + if (el_window.hasAttribute("data-centered") || center) { - el_window.style.top = Math.max(view.top, 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", ""); + __centerWindow(el_window); } else { if (rect.top <= view.top) { el_window.style.top = view.top + "px"; @@ -350,6 +400,14 @@ function __WindowManager() { } }; + var __centerWindow = function(el_window) { + let view = self.getViewGeometry(); + let rect = el_window.getBoundingClientRect(); + el_window.style.top = Math.max(view.top, 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) { let el_last_window = null; @@ -415,6 +473,10 @@ function __WindowManager() { let prev_pos = {x: 0, y: 0}; function startMoving(event) { + // При перетаскивании resizable-окна за правый кран экрана оно ужимается. + // Этот костыль фиксит это. + el_window.style.width = el_window.offsetWidth + "px"; + __closeAllMenues(); __activateWindow(el_window); event = (event || window.event); @@ -474,5 +536,45 @@ function __WindowManager() { el_grab.ontouchstart = startMoving; }; + var __onFullScreenChange = function(event) { + let el_window = event.target; + if (!document.fullscreenElement) { + el_window.style.padding = ""; + let rect = el_window.before_full_screen; + if (rect) { + el_window.style.width = rect.width + "px"; + el_window.style.height = rect.height + "px"; + el_window.style.top = rect.top + "px"; + el_window.style.left = rect.left + "px"; + } + } else { + el_window.style.padding = "0px 0px 0px 0px"; + } + }; + + var __fullScreenWindow = function(el_window) { + el_window.before_full_screen = el_window.getBoundingClientRect(); + el_window.requestFullscreen(); + if ("keyboard" in navigator && "lock" in navigator.keyboard) { + navigator.keyboard.lock(); + } else { + let el_lock_alert = el_window.querySelector(".window-lock-alert"); + if (el_lock_alert) { + tools.hiddenSetVisible(el_lock_alert, true); + setTimeout(function() { + tools.hiddenSetVisible(el_lock_alert, false); + }, 7000); + } + } + }; + + var __maximizeWindow = function(el_window) { + let vertical_offset = $("navbar").offsetHeight; + el_window.style.left = "0px"; + el_window.style.top = vertical_offset + "px"; + el_window.style.width = window.innerWidth + "px"; + el_window.style.height = window.innerHeight - vertical_offset + "px"; + }; + __init__(); } |