mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
pikvm/pikvm#1316: web: keep stream window maximized
This commit is contained in:
parent
53980c0e68
commit
818ff6321e
@ -982,14 +982,16 @@
|
||||
<div class="window" id="stream-ocr-window">
|
||||
<div class="hidden" id="stream-ocr-selection"></div>
|
||||
</div>
|
||||
<div class="window window-resizable" id="stream-window">
|
||||
<div class="window window-resizable" id="stream-window" data-show-maximized>
|
||||
<div class="window-header" id="stream-window-header">
|
||||
<div class="window-grab">MJPEG</div>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
<button class="window-button-maximize">☐</button>
|
||||
<button class="window-button-original">•</button>
|
||||
<button class="window-button-enter-full-tab">▲</button>
|
||||
<button class="window-button-full-screen">⤢</button>
|
||||
<div class="window-buttons">
|
||||
<button class="window-button-full-screen">⤢</button>
|
||||
<button class="window-button-enter-full-tab">▲</button>
|
||||
<button class="window-button-original">•</button>
|
||||
<button class="window-button-maximize">☐</button>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="stream-info"></div>
|
||||
<button class="window-button-exit-full-tab">▼</button>
|
||||
@ -1032,10 +1034,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="window" id="keyboard-window">
|
||||
<div class="window" id="keyboard-window" data-show-centered>
|
||||
<div class="window-header" id="keyboard-window-header">
|
||||
<div class="window-grab">Virtual Keyboard</div>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
<div class="window-buttons">
|
||||
<button class="window-button-original">•</button>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="keypad" id="keyboard-desktop" align="center">
|
||||
<div class="keypad-block">
|
||||
@ -2111,10 +2116,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="window" id="switch-window" style="width: min-content">
|
||||
<div class="window" id="switch-window" data-show-centered style="width: min-content">
|
||||
<div class="window-header">
|
||||
<div class="window-grab">Switch settings</div>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
<div class="window-buttons">
|
||||
<button class="window-button-original">•</button>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-box">
|
||||
<input checked type="radio" name="switch-tab-button" id="switch-tab-edid-button">
|
||||
@ -2258,10 +2266,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="window" id="about-window">
|
||||
<div class="window" id="about-window" data-show-centered>
|
||||
<div class="window-header">
|
||||
<div class="window-grab">About</div>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
<div class="window-buttons">
|
||||
<button class="window-button-original">•</button>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="about">
|
||||
<table>
|
||||
@ -2961,15 +2972,18 @@
|
||||
<p class="text credits"><a target="_blank" href="https://pikvm.org">PiKVM Project</a> | <a target="_blank" href="https://docs.pikvm.org">Documentation</a> | <a target="_blank" href="https://pikvm.org/support">Support</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="window window-resizable" id="webterm-window" style="width: 720px; height: 480px">
|
||||
<div class="window window-resizable" id="webterm-window" data-show-centered style="display: flex; min-width: 720px; min-height: 480px">
|
||||
<div class="window-header">
|
||||
<div class="window-grab">Terminal</div>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
<button class="window-button-maximize">☐</button>
|
||||
<!-- Терминал глючит из-за зажимаемой клавиши ESC для выхода-->
|
||||
<!-- button(class="window-button-full-screen") ⤢-->
|
||||
<div class="window-buttons">
|
||||
<button class="window-button-original">•</button>
|
||||
<button class="window-button-maximize">☐</button>
|
||||
<button class="window-button-close"><b>×</b></button>
|
||||
<!-- Терминал глючит из-за зажимаемой клавиши ESC для выхода-->
|
||||
<!-- button(class="window-button-full-screen") ⤢-->
|
||||
</div>
|
||||
</div>
|
||||
<iframe id="webterm-iframe" src="" style="width: 100%; height: 100%"></iframe>
|
||||
<iframe id="webterm-iframe" src="" style="width: 100%; flex: 1"></iframe>
|
||||
</div>
|
||||
<ul class="navbar-bg-tips">
|
||||
<li class="left">
|
||||
|
||||
@ -10,10 +10,12 @@ mixin about_tab(name, title, checked=false)
|
||||
span.code-comment No data
|
||||
|
||||
|
||||
.window#about-window
|
||||
.window#about-window(data-show-centered)
|
||||
.window-header
|
||||
.window-grab About
|
||||
button.window-button-close #[b ×]
|
||||
.window-buttons
|
||||
button.window-button-original •
|
||||
button.window-button-close #[b ×]
|
||||
|
||||
#about
|
||||
table
|
||||
|
||||
@ -30,10 +30,12 @@ mixin lamp(cls)
|
||||
img(class=`inline-lamp-small ${cls} led-gray` src=`${svg_dir}/led-square.svg`)
|
||||
|
||||
|
||||
.window#keyboard-window
|
||||
.window#keyboard-window(data-show-centered)
|
||||
.window-header#keyboard-window-header
|
||||
.window-grab Virtual Keyboard
|
||||
button.window-button-close #[b ×]
|
||||
.window-buttons
|
||||
button.window-button-original •
|
||||
button.window-button-close #[b ×]
|
||||
|
||||
.keypad#keyboard-desktop(align="center")
|
||||
.keypad-block
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
.window#stream-ocr-window
|
||||
.hidden#stream-ocr-selection
|
||||
|
||||
.window.window-resizable#stream-window
|
||||
.window.window-resizable#stream-window(data-show-maximized)
|
||||
.window-header#stream-window-header
|
||||
.window-grab MJPEG
|
||||
button.window-button-close #[b ×]
|
||||
button.window-button-maximize ☐
|
||||
button.window-button-original •
|
||||
button.window-button-enter-full-tab ▲
|
||||
button.window-button-full-screen ⤢
|
||||
.window-buttons
|
||||
button.window-button-full-screen ⤢
|
||||
button.window-button-enter-full-tab ▲
|
||||
button.window-button-original •
|
||||
button.window-button-maximize ☐
|
||||
button.window-button-close #[b ×]
|
||||
|
||||
#stream-info
|
||||
|
||||
|
||||
@ -15,10 +15,12 @@ mixin color_slider_tr(name, title)
|
||||
td #[button(id=`switch-color-${name}-default-button` class="small" title="Reset default") ↻]
|
||||
|
||||
|
||||
.window#switch-window(style="width: min-content")
|
||||
.window#switch-window(data-show-centered style="width: min-content")
|
||||
.window-header
|
||||
.window-grab Switch settings
|
||||
button.window-button-close #[b ×]
|
||||
.window-buttons
|
||||
button.window-button-original •
|
||||
button.window-button-close #[b ×]
|
||||
|
||||
.tabs-box
|
||||
+switch_tab("edid", "EDIDs collection", true)
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
.window.window-resizable#webterm-window(style="width: 720px; height: 480px")
|
||||
.window.window-resizable#webterm-window(data-show-centered style="display: flex; min-width: 720px; min-height: 480px")
|
||||
.window-header
|
||||
.window-grab Terminal
|
||||
button.window-button-close #[b ×]
|
||||
button.window-button-maximize ☐
|
||||
// Терминал глючит из-за зажимаемой клавиши ESC для выхода
|
||||
// button(class="window-button-full-screen") ⤢
|
||||
.window-buttons
|
||||
button.window-button-original •
|
||||
button.window-button-maximize ☐
|
||||
button.window-button-close #[b ×]
|
||||
// Терминал глючит из-за зажимаемой клавиши ESC для выхода
|
||||
// button(class="window-button-full-screen") ⤢
|
||||
|
||||
iframe#webterm-iframe(src="" style="width: 100%; height: 100%")
|
||||
iframe#webterm-iframe(src="" style="width: 100%; flex: 1")
|
||||
|
||||
@ -34,6 +34,11 @@ div#stream-window {
|
||||
width: 100% !important;
|
||||
-webkit-transform: translateX(-50%) !important;
|
||||
transform: translateX(-50%) !important;
|
||||
|
||||
/* Ignore stream's resize_hook() */
|
||||
aspect-ratio: unset !important;
|
||||
max-width: unset !important;
|
||||
max-height: unset !important;
|
||||
}
|
||||
|
||||
div#stream-window::after {
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
--cs-window-header-grabbed-bg: #436a8a;
|
||||
--cs-window-header-grabbed-fg: white;
|
||||
--cs-window-closer-default-fg: #6c7481;
|
||||
--cs-window-button-special-fg: #009b48;
|
||||
|
||||
--cs-code-default-bg: #17191d;
|
||||
--cs-code-default-fg: #aaaaaa;
|
||||
|
||||
@ -40,7 +40,7 @@ div.window-resizable {
|
||||
div.window-active {
|
||||
border: var(--border-window-active-2px) !important;
|
||||
}
|
||||
div.window-resizable.window-active::after {
|
||||
div.window-resizable.window-active:not(.window-full-tab)::after {
|
||||
content: "";
|
||||
width: 0;
|
||||
height: 0;
|
||||
@ -61,6 +61,11 @@ div.window:fullscreen {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
padding: 0px !important;
|
||||
|
||||
/* Ignore stream's resize_hook() */
|
||||
aspect-ratio: unset !important;
|
||||
max-width: unset !important;
|
||||
max-height: unset !important;
|
||||
}
|
||||
div.window:fullscreen::after {
|
||||
display: none;
|
||||
@ -75,6 +80,11 @@ div.window:-webkit-full-screen {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
padding: 0px !important;
|
||||
|
||||
/* Ignore stream's resize_hook() */
|
||||
aspect-ratio: unset !important;
|
||||
max-width: unset !important;
|
||||
max-height: unset !important;
|
||||
}
|
||||
div.window:-webkit-full-screen::after {
|
||||
display: none;
|
||||
@ -88,6 +98,11 @@ div.window.window-full-tab {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
padding: 0px !important;
|
||||
|
||||
/* Ignore stream's resize_hook() */
|
||||
aspect-ratio: unset !important;
|
||||
max-width: unset !important;
|
||||
max-height: unset !important;
|
||||
}
|
||||
|
||||
div.window div.window-header {
|
||||
@ -126,36 +141,35 @@ div.window div.window-header-grabbed {
|
||||
border-bottom: var(--border-intensive-thin);
|
||||
}
|
||||
|
||||
div.window div.window-header button.window-button-full-screen,
|
||||
div.window div.window-header button.window-button-enter-full-tab,
|
||||
div.window div.window-header button.window-button-original,
|
||||
div.window div.window-header button.window-button-maximize,
|
||||
div.window div.window-header button.window-button-close {
|
||||
line-height: 1px;
|
||||
border: none;
|
||||
div.window div.window-header div.window-buttons {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
right: 0;
|
||||
font-size: 0px;
|
||||
background-color: var(--cs-window-default-bg);
|
||||
}
|
||||
|
||||
div.window div.window-header div.window-buttons button.window-button-full-screen,
|
||||
div.window div.window-header div.window-buttons button.window-button-enter-full-tab,
|
||||
div.window div.window-header div.window-buttons button.window-button-original,
|
||||
div.window div.window-header div.window-buttons button.window-button-maximize,
|
||||
div.window div.window-header div.window-buttons button.window-button-close {
|
||||
line-height: 1px;
|
||||
border: none;
|
||||
border-radius: 0px;
|
||||
width: 44px;
|
||||
height: 24px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
margin-left: 1px;
|
||||
color: var(--cs-window-closer-default-fg);
|
||||
display: inline-block;
|
||||
}
|
||||
div.window div.window-header button.window-button-full-screen {
|
||||
right: 180px;
|
||||
div.window[data-centered] div.window-header div.window-buttons button.window-button-original {
|
||||
color: var(--cs-window-button-special-fg);
|
||||
}
|
||||
div.window div.window-header button.window-button-enter-full-tab {
|
||||
right: 135px;
|
||||
}
|
||||
div.window div.window-header button.window-button-original {
|
||||
right: 90px;
|
||||
}
|
||||
div.window div.window-header button.window-button-maximize {
|
||||
right: 45px;
|
||||
}
|
||||
div.window div.window-header button.window-button-close {
|
||||
right: 0px;
|
||||
div.window[data-maximized] div.window-header div.window-buttons button.window-button-maximize {
|
||||
color: var(--cs-window-button-special-fg);
|
||||
}
|
||||
|
||||
div.window button.window-button-exit-full-tab {
|
||||
|
||||
@ -43,7 +43,7 @@ export function Streamer() {
|
||||
var __res = {"width": 640, "height": 480};
|
||||
|
||||
var __init__ = function() {
|
||||
__streamer = new MjpegStreamer(__setActive, __setInactive, __setInfo);
|
||||
__streamer = new MjpegStreamer(__setActive, __setInactive, __setInfo, __organizeHook);
|
||||
|
||||
$("stream-led").title = "Stream inactive";
|
||||
|
||||
@ -110,6 +110,7 @@ export function Streamer() {
|
||||
|
||||
$("stream-window").show_hook = () => __applyState(__state);
|
||||
$("stream-window").close_hook = () => __applyState(null);
|
||||
$("stream-window").organize_hook = __organizeHook;
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
@ -294,6 +295,11 @@ export function Streamer() {
|
||||
el_grab.innerText = el_info.innerText = title;
|
||||
};
|
||||
|
||||
var __organizeHook = function() {
|
||||
let geo = self.getGeometry();
|
||||
wm.setAspectRatio($("stream-window"), geo.width, geo.height);
|
||||
};
|
||||
|
||||
var __resetStream = function(mode=null) {
|
||||
if (mode === null) {
|
||||
mode = __streamer.getMode();
|
||||
@ -303,16 +309,16 @@ export function Streamer() {
|
||||
if (mode === "janus") {
|
||||
let allow_audio = !$("stream-video").muted;
|
||||
let allow_mic = $("stream-mic-switch").checked;
|
||||
__streamer = new JanusStreamer(__setActive, __setInactive, __setInfo, orient, allow_audio, allow_mic);
|
||||
__streamer = new JanusStreamer(__setActive, __setInactive, __setInfo, __organizeHook, orient, allow_audio, allow_mic);
|
||||
// Firefox doesn't support RTP orientation:
|
||||
// - https://bugzilla.mozilla.org/show_bug.cgi?id=1316448
|
||||
tools.feature.setEnabled($("stream-orient"), !tools.browser.is_firefox);
|
||||
} else {
|
||||
if (mode === "media") {
|
||||
__streamer = new MediaStreamer(__setActive, __setInactive, __setInfo, orient);
|
||||
__streamer = new MediaStreamer(__setActive, __setInactive, __setInfo, __organizeHook, orient);
|
||||
tools.feature.setEnabled($("stream-orient"), true);
|
||||
} else { // mjpeg
|
||||
__streamer = new MjpegStreamer(__setActive, __setInactive, __setInfo);
|
||||
__streamer = new MjpegStreamer(__setActive, __setInactive, __setInfo, __organizeHook);
|
||||
tools.feature.setEnabled($("stream-orient"), false);
|
||||
}
|
||||
tools.feature.setEnabled($("stream-audio"), false); // Enabling in stream_janus.js
|
||||
|
||||
@ -29,7 +29,7 @@ import {tools, $} from "../tools.js";
|
||||
var _Janus = null;
|
||||
|
||||
|
||||
export function JanusStreamer(__setActive, __setInactive, __setInfo, __orient, __allow_audio, __allow_mic) {
|
||||
export function JanusStreamer(__setActive, __setInactive, __setInfo, __organizeHook, __orient, __allow_audio, __allow_mic) {
|
||||
var self = this;
|
||||
|
||||
/************************************************************************/
|
||||
@ -48,6 +48,8 @@ export function JanusStreamer(__setActive, __setInactive, __setInfo, __orient, _
|
||||
|
||||
var __state = null;
|
||||
var __frames = 0;
|
||||
var __res = {"width": -1, "height": -1};
|
||||
var __resize_listener_installed = false;
|
||||
|
||||
var __ice = null;
|
||||
|
||||
@ -84,11 +86,28 @@ export function JanusStreamer(__setActive, __setInactive, __setInfo, __orient, _
|
||||
__state = state;
|
||||
__stop = false;
|
||||
__ensureJanus(false);
|
||||
if (!__resize_listener_installed) {
|
||||
$("stream-video").addEventListener("resize", __videoResizeHandler);
|
||||
__resize_listener_installed = true;
|
||||
}
|
||||
};
|
||||
|
||||
self.stopStream = function() {
|
||||
__stop = true;
|
||||
__destroyJanus();
|
||||
if (__resize_listener_installed) {
|
||||
$("stream-video").removeEventListener("resize", __videoResizeHandler);
|
||||
__resize_listener_installed = false;
|
||||
}
|
||||
};
|
||||
|
||||
var __videoResizeHandler = function(ev) {
|
||||
let el = ev.target;
|
||||
if (__res.width !== el.videoWidth || __res.height !== el.videoHeight) {
|
||||
__res.width = el.videoWidth;
|
||||
__res.height = el.videoHeight;
|
||||
__organizeHook();
|
||||
}
|
||||
};
|
||||
|
||||
var __ensureJanus = function(internal) {
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
import {tools, $} from "../tools.js";
|
||||
|
||||
|
||||
export function MediaStreamer(__setActive, __setInactive, __setInfo, __orient) {
|
||||
export function MediaStreamer(__setActive, __setInactive, __setInfo, __organizeHook, __orient) {
|
||||
var self = this;
|
||||
|
||||
/************************************************************************/
|
||||
@ -282,6 +282,7 @@ export function MediaStreamer(__setActive, __setInactive, __setInfo, __orient) {
|
||||
if (__canvas.width !== width || __canvas.height !== height) {
|
||||
__canvas.width = width;
|
||||
__canvas.height = height;
|
||||
__organizeHook();
|
||||
}
|
||||
|
||||
if (__orient === 0) {
|
||||
|
||||
@ -27,7 +27,7 @@ import {ROOT_PREFIX} from "../vars.js";
|
||||
import {tools, $} from "../tools.js";
|
||||
|
||||
|
||||
export function MjpegStreamer(__setActive, __setInactive, __setInfo) {
|
||||
export function MjpegStreamer(__setActive, __setInactive, __setInfo, __organizeHook) {
|
||||
var self = this;
|
||||
|
||||
/************************************************************************/
|
||||
@ -62,6 +62,7 @@ export function MjpegStreamer(__setActive, __setInactive, __setInfo) {
|
||||
if (__id.length > 0 && __id in __state.stream.clients_stat) {
|
||||
__setStreamActive();
|
||||
__stopChecking();
|
||||
__organizeHook();
|
||||
} else {
|
||||
__ensureChecking();
|
||||
}
|
||||
|
||||
@ -60,21 +60,59 @@ function __WindowManager() {
|
||||
__windows.push(el_win);
|
||||
|
||||
if (el_win.classList.contains("window-resizable") && window.ResizeObserver) {
|
||||
el_win.__observer_timer = null;
|
||||
new ResizeObserver(function() {
|
||||
// При переполнении рабочей области сократить размер окна по высоте.
|
||||
// По ширине оно настраивается само в CSS.
|
||||
let view = self.getViewGeometry();
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
if ((rect.bottom - rect.top) > (view.bottom - view.top)) {
|
||||
let ratio = (rect.bottom - rect.top) / (view.bottom - view.top);
|
||||
el_win.style.height = view.bottom - view.top + "px";
|
||||
el_win.style.width = Math.round((rect.right - rect.left) / ratio) + "px";
|
||||
}
|
||||
|
||||
if (el_win.hasAttribute("data-centered")) {
|
||||
__centerWindow(el_win);
|
||||
// Таймер нужен чтобы остановить дребезг ресайза: observer вызывает
|
||||
// __organizeWindow(), который сам по себе триггерит observer.
|
||||
if (el_win.__observer_timer === null || el_win.__manual_resizing) {
|
||||
__organizeWindow(el_win, !el_win.__manual_resizing);
|
||||
if (el_win.__observer_timer !== null) {
|
||||
clearTimeout(el_win.__observer_timer);
|
||||
}
|
||||
el_win.__observer_timer = setTimeout(function() {
|
||||
el_win.__observer_timer = null;
|
||||
}, 100);
|
||||
}
|
||||
}).observe(el_win);
|
||||
el_win.addEventListener("pointerrawupdate", function(ev) {
|
||||
// События pointerdown и touchdown не генерируются при ресайзе за уголок,
|
||||
// поэтому отлавливаем pointerrawupdate для тач-событий.
|
||||
let events = ev.getCoalescedEvents();
|
||||
for (ev of events) {
|
||||
if (
|
||||
ev.target === el_win && ev.pointerType === "touch" && ev.buttons
|
||||
&& Math.abs(el_win.clientWidth - ev.offsetX) < 20
|
||||
&& Math.abs(el_win.clientHeight - ev.offsetY) < 20
|
||||
) {
|
||||
__setWindowMca(el_win, false, null, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
el_win.addEventListener("mousedown", function(ev) {
|
||||
if (
|
||||
ev.target === el_win
|
||||
&& Math.abs(el_win.clientWidth - ev.offsetX) < 20
|
||||
&& Math.abs(el_win.clientHeight - ev.offsetY) < 20
|
||||
) {
|
||||
el_win.__manual_resizing = true;
|
||||
}
|
||||
});
|
||||
document.addEventListener("mouseup", function() {
|
||||
if (el_win.__manual_resizing) {
|
||||
__organizeWindow(el_win);
|
||||
}
|
||||
el_win.__manual_resizing = false;
|
||||
});
|
||||
document.addEventListener("mousemove", function(ev) {
|
||||
if (el_win.__manual_resizing) {
|
||||
__setWindowMca(el_win, false, null, true);
|
||||
if (!ev.buttons) {
|
||||
__organizeWindow(el_win);
|
||||
el_win.__manual_resizing = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
@ -90,8 +128,9 @@ function __WindowManager() {
|
||||
if (el) {
|
||||
el.title = "Maximize window";
|
||||
tools.el.setOnClick(el, function() {
|
||||
__maximizeWindow(el_win);
|
||||
__activateLastWindow(el_win);
|
||||
__setWindowMca(el_win, true, false, false);
|
||||
__organizeWindow(el_win);
|
||||
__activateWindow(el_win);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -101,10 +140,11 @@ function __WindowManager() {
|
||||
if (el) {
|
||||
el.title = "Reduce window to its original size and center it";
|
||||
tools.el.setOnClick(el, function() {
|
||||
__setWindowMca(el_win, false, true, false);
|
||||
el_win.style.width = "";
|
||||
el_win.style.height = "";
|
||||
__centerWindow(el_win);
|
||||
__activateLastWindow(el_win);
|
||||
__organizeWindow(el_win);
|
||||
__activateWindow(el_win);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -125,7 +165,7 @@ function __WindowManager() {
|
||||
el.title = "Go to full-screen mode";
|
||||
tools.el.setOnClick(el, function() {
|
||||
__setFullScreenWindow(el_win);
|
||||
__activateLastWindow(el_win);
|
||||
__activateWindow(el_win);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -301,20 +341,46 @@ function __WindowManager() {
|
||||
return promise;
|
||||
};
|
||||
|
||||
var __setWindowMca = function(el_win, maximized, centered, adjusted) {
|
||||
if (maximized !== null) {
|
||||
el_win.toggleAttribute("data-maximized", maximized);
|
||||
if (maximized) {
|
||||
el_win.removeAttribute("data-centered");
|
||||
}
|
||||
}
|
||||
if (centered !== null) {
|
||||
el_win.toggleAttribute("data-centered", centered);
|
||||
if (centered) {
|
||||
el_win.removeAttribute("data-maximized");
|
||||
}
|
||||
}
|
||||
if (adjusted !== null) {
|
||||
el_win.toggleAttribute("data-adjusted", adjusted);
|
||||
if (adjusted) {
|
||||
el_win.removeAttribute("data-maximized");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.showWindow = function(el_win) {
|
||||
let center = false;
|
||||
let showed = false;
|
||||
if (!self.isWindowVisible(el_win)) {
|
||||
center = true;
|
||||
showed = true;
|
||||
}
|
||||
__organizeWindow(el_win, center);
|
||||
|
||||
if (!el_win.hasAttribute("data-adjusted")) {
|
||||
if (el_win.hasAttribute("data-show-maximized") && !el_win.hasAttribute("data-centered")) {
|
||||
__setWindowMca(el_win, true, false, false);
|
||||
} else if (el_win.hasAttribute("data-show-centered") && !el_win.hasAttribute("data-maximized")) {
|
||||
__setWindowMca(el_win, false, true, false);
|
||||
}
|
||||
}
|
||||
__organizeWindow(el_win);
|
||||
|
||||
el_win.style.visibility = "visible";
|
||||
__activateWindow(el_win);
|
||||
if (el_win.show_hook) {
|
||||
if (showed) {
|
||||
el_win.show_hook();
|
||||
}
|
||||
if (showed && el_win.show_hook) {
|
||||
el_win.show_hook();
|
||||
}
|
||||
};
|
||||
|
||||
@ -346,6 +412,18 @@ function __WindowManager() {
|
||||
setTimeout(() => __activateWindow(el_win), 100);
|
||||
};
|
||||
|
||||
self.setAspectRatio = function(el_win, width, height) {
|
||||
// XXX: Values from CSS
|
||||
width += 9 + 9 + 2 + 2;
|
||||
height += 30 + 9 + 2 + 2;
|
||||
el_win.__aspect_ratio_width = width;
|
||||
el_win.__aspect_ratio_height = height;
|
||||
el_win.style.maxWidth = "fit-content";
|
||||
el_win.style.maxHeight = "fit-content";
|
||||
el_win.style.aspectRatio = `${width} / ${height}`;
|
||||
__organizeWindow(el_win, true, false);
|
||||
};
|
||||
|
||||
var __closeWindow = function(el_win) {
|
||||
el_win.focus();
|
||||
el_win.blur();
|
||||
@ -438,23 +516,20 @@ function __WindowManager() {
|
||||
var __organizeWindowsOnBrowserResize = function() {
|
||||
for (let el_win of $$("window")) {
|
||||
if (el_win.style.visibility === "visible") {
|
||||
if (tools.browser.is_mobile && el_win.classList.contains("window-resizable")) {
|
||||
// FIXME: При смене ориентации на мобильном браузере надо сбрасывать
|
||||
// настройки окна стрима, поэтому тут стоит вот этот костыль
|
||||
el_win.style.width = "";
|
||||
el_win.style.height = "";
|
||||
}
|
||||
__organizeWindow(el_win);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var __organizeWindow = function(el_win, center=false) {
|
||||
let view = self.getViewGeometry();
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
var __organizeWindow = function(el_win, auto_shrink=true, organize_hook=true) {
|
||||
if (organize_hook && el_win.organize_hook) {
|
||||
el_win.organize_hook();
|
||||
}
|
||||
|
||||
if (el_win.classList.contains("window-resizable")) {
|
||||
if (auto_shrink && el_win.classList.contains("window-resizable")) {
|
||||
// При переполнении рабочей области сократить размер окна
|
||||
let view = self.getViewGeometry();
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
if ((rect.bottom - rect.top) > (view.bottom - view.top)) {
|
||||
let ratio = (rect.bottom - rect.top) / (view.bottom - view.top);
|
||||
el_win.style.height = view.bottom - view.top + "px";
|
||||
@ -463,32 +538,65 @@ function __WindowManager() {
|
||||
if ((rect.right - rect.left) > (view.right - view.left)) {
|
||||
el_win.style.width = view.right - view.left + "px";
|
||||
}
|
||||
rect = el_win.getBoundingClientRect();
|
||||
}
|
||||
|
||||
if (el_win.hasAttribute("data-centered") || center) {
|
||||
__centerWindow(el_win);
|
||||
if (el_win.hasAttribute("data-maximized")) {
|
||||
__organizeMaximizeWindow(el_win);
|
||||
} else if (el_win.hasAttribute("data-centered")) {
|
||||
__organizeCenterWindow(el_win);
|
||||
} else {
|
||||
if (rect.top <= view.top) {
|
||||
el_win.style.top = view.top + "px";
|
||||
} else if (rect.bottom > view.bottom) {
|
||||
el_win.style.top = view.bottom - rect.height + "px";
|
||||
}
|
||||
|
||||
if (rect.left <= view.left) {
|
||||
el_win.style.left = view.left + "px";
|
||||
} else if (rect.right > view.right) {
|
||||
el_win.style.left = view.right - rect.width + "px";
|
||||
}
|
||||
__organizeFitWindow(el_win);
|
||||
}
|
||||
};
|
||||
|
||||
var __centerWindow = function(el_win) {
|
||||
var __organizeCenterWindow = function(el_win) {
|
||||
let view = self.getViewGeometry();
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
el_win.style.top = Math.max(view.top, Math.round((view.bottom - rect.height) / 2)) + "px";
|
||||
el_win.style.left = Math.round((view.right - rect.width) / 2) + "px";
|
||||
el_win.setAttribute("data-centered", "");
|
||||
};
|
||||
|
||||
var __organizeMaximizeWindow = function(el_win) {
|
||||
let view = self.getViewGeometry();
|
||||
el_win.style.top = view.top + "px";
|
||||
|
||||
let aw = el_win.__aspect_ratio_width;
|
||||
let ah = el_win.__aspect_ratio_height;
|
||||
let gw = view.right - view.left;
|
||||
let gh = view.bottom - view.top;
|
||||
if (aw && ah) {
|
||||
if (aw / gw < ah / gh) {
|
||||
el_win.style.width = "";
|
||||
el_win.style.height = gh + "px";
|
||||
} else {
|
||||
el_win.style.left = "";
|
||||
el_win.style.height = "";
|
||||
el_win.style.width = gw + "px";
|
||||
}
|
||||
}/* else {
|
||||
el_win.style.width = gw + "px";
|
||||
el_win.style.height = gh + "px";
|
||||
}*/
|
||||
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
el_win.style.left = Math.round((view.right - rect.width) / 2) + "px";
|
||||
};
|
||||
|
||||
var __organizeFitWindow = function(el_win) {
|
||||
let view = self.getViewGeometry();
|
||||
let rect = el_win.getBoundingClientRect();
|
||||
|
||||
if (rect.top <= view.top) {
|
||||
el_win.style.top = view.top + "px";
|
||||
} else if (rect.bottom > view.bottom) {
|
||||
el_win.style.top = view.bottom - rect.height + "px";
|
||||
}
|
||||
|
||||
if (rect.left <= view.left) {
|
||||
el_win.style.left = view.left + "px";
|
||||
} else if (rect.right > view.right) {
|
||||
el_win.style.left = view.right - rect.width + "px";
|
||||
}
|
||||
};
|
||||
|
||||
var __activateLastWindow = function(el_except_win=null) {
|
||||
@ -584,7 +692,7 @@ function __WindowManager() {
|
||||
return;
|
||||
}
|
||||
|
||||
el_win.removeAttribute("data-centered");
|
||||
__setWindowMca(el_win, false, false, true);
|
||||
|
||||
ev = (ev || window.ev);
|
||||
ev.preventDefault();
|
||||
@ -612,8 +720,6 @@ function __WindowManager() {
|
||||
}
|
||||
}
|
||||
|
||||
el_win.setAttribute("data-centered", "");
|
||||
|
||||
document.addEventListener("mousemove", doMoving);
|
||||
document.addEventListener("mouseup", stopMoving);
|
||||
|
||||
@ -659,14 +765,5 @@ function __WindowManager() {
|
||||
el_win.focus(el_win); // Почему-то теряется фокус
|
||||
};
|
||||
|
||||
var __maximizeWindow = function(el_win) {
|
||||
let el_navbar = $("navbar");
|
||||
let vertical_offset = (el_navbar ? el_navbar.offsetHeight : 0);
|
||||
el_win.style.left = "0px";
|
||||
el_win.style.top = vertical_offset + "px";
|
||||
el_win.style.width = window.innerWidth + "px";
|
||||
el_win.style.height = window.innerHeight - vertical_offset + "px";
|
||||
};
|
||||
|
||||
__init__();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user