From 9d6d00165a6bb550ffdc88b38a220e69fa83f89f Mon Sep 17 00:00:00 2001 From: trinkey Date: Thu, 13 Feb 2025 19:04:05 -0500 Subject: [PATCH] window resizing --- css/base.css | 78 +++++++++++++++++++++++++++++ js/index.js | 107 ++++++++++++++++++++++++++++++++------- ts/globals.d.ts | 2 + ts/index.ts | 130 ++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 273 insertions(+), 44 deletions(-) diff --git a/css/base.css b/css/base.css index 5064885..fb4cd77 100644 --- a/css/base.css +++ b/css/base.css @@ -248,6 +248,84 @@ pre { overflow: scroll; } +.edge { + position: absolute; + cursor: wait; + z-index: 2; +} + +.edge.top { + height: 12px; + width: auto; + top: -10px; + left: 0; + right: 0; + cursor: n-resize; +} + +.edge.bottom { + height: 12px; + width: auto; + bottom: -10px; + left: 0; + right: 0; + cursor: s-resize; +} + +.edge.left { + width: 12px; + height: auto; + top: 0; + bottom: 0; + left: -10px; + cursor: w-resize; +} + +.edge.right { + width: 12px; + height: auto; + top: 0; + bottom: 0; + right: -10px; + cursor: e-resize; +} + +.edge.top-left { + height: 25px; + width: 25px; + top: -12px; + left: -12px; + z-index: 3; + cursor: nw-resize; +} + +.edge.top-right { + height: 25px; + width: 25px; + top: -12px; + right: -12px; + z-index: 3; + cursor: ne-resize; +} + +.edge.bottom-left { + height: 25px; + width: 25px; + bottom: -12px; + left: -12px; + z-index: 3; + cursor: sw-resize; +} + +.edge.bottom-right { + height: 25px; + width: 25px; + bottom: -12px; + right: -12px; + z-index: 3; + cursor: se-resize; +} + .buttons-88x31 { display: flex; flex-direction: row; diff --git a/js/index.js b/js/index.js index 5357657..a268a61 100644 --- a/js/index.js +++ b/js/index.js @@ -1,3 +1,5 @@ +const _windowPaddingX = 1 * 2 + 10 * 2; +const _windowPaddingY = 1 * 2 + 10 * 2 + 35; let WINDOWS = {}; let MOUSE_MOVE_PROCESSING = {}; let globalIncrement = 1; @@ -12,13 +14,45 @@ function incrementZIndex(windowID, focus = false) { WINDOWS[windowID].element.focus(); } } +function edgeMoveEvent(x, y, pos, windowID) { + let w = WINDOWS[windowID]; + if (x - w.vars.mouseOffsetX < 0) { + x = w.vars.mouseOffsetX; + } + if (y - w.vars.mouseOffsetY < 0) { + y = w.vars.mouseOffsetY; + } + if (pos == "top" || pos.startsWith("top-")) { + w.height = Math.max(-(y - w.vars.mouseOffsetY - w.vars.startingPosY) + w.vars.startingHeight, w.minHeight); + w.posY = Math.max(w.vars.startingHeight - w.height + w.vars.startingPosY, 0); + } + else if (pos == "bottom" || pos.startsWith("bottom-")) { + w.height = Math.max(y - w.vars.mouseOffsetY - w.vars.startingPosY + w.vars.startingHeight, w.minHeight); + } + if (pos == "left" || pos.endsWith("-left")) { + w.width = Math.max(-(x - w.vars.mouseOffsetX - w.vars.startingPosX) + w.vars.startingWidth, w.minWidth); + w.posX = Math.max(w.vars.startingWidth - w.width + w.vars.startingPosX, 0); + } + else if (pos == "right" || pos.endsWith("-right")) { + w.width = Math.max(x - w.vars.mouseOffsetX - w.vars.startingPosX + w.vars.startingWidth, w.minWidth); + } + if (w.posX + w.width + _windowPaddingX > innerWidth) { + w.width = Math.max(innerWidth - w.posX - _windowPaddingX, w.minWidth); + } + if (w.posY + w.height + _windowPaddingY > innerHeight) { + w.height = Math.max(innerHeight - w.posY - _windowPaddingY, w.minHeight); + } + w.element.style.left = `${w.posX}px`; + w.element.style.top = `${w.posY}px`; + w.element.style.width = `${w.width + _windowPaddingX - 2}px`; + w.element.querySelector(".window").style.width = `${w.width}px`; + w.element.querySelector(".window").style.height = `${w.height}px`; +} function createWindow(config) { if (document.getElementById(config.id)) { incrementZIndex(config.id); return; } - let _windowPaddingX = 1 * 2 + 10 * 2; - let _windowPaddingY = 1 * 2 + 10 * 2 + 35; config.width = config.width || 600; config.height = config.height || 400; config.minWidth = config.minWidth || 200; @@ -48,6 +82,9 @@ function createWindow(config) { let wC; let wI = null; if (config.typeable !== false) { + wI = document.createElement("input"); + wI.classList.add("window-input"); + wI.id = `${config.id}__input`; function syncInputs() { setTimeout(function () { let text = wI.value; @@ -70,9 +107,6 @@ function createWindow(config) { syncInputs(); }, 0); } - wI = document.createElement("input"); - wI.classList.add("window-input"); - wI.id = `${config.id}__input`; wI.oninput = (event) => { syncInputs(); w.scrollTop = w.scrollHeight; @@ -102,8 +136,27 @@ function createWindow(config) { wC.id = config.id; wC.style.zIndex = String(globalIncrement); wC.style.width = `${realWidth + _windowPaddingX - 2}px`; + let edges = document.createDocumentFragment(); + for (const pos of ["top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"]) { + let el = document.createElement("div"); + el.classList.add("edge", pos); + el.addEventListener("mousedown", function (e) { + e.preventDefault(); + WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX; + WINDOWS[config.id].vars.mouseOffsetY = e.clientY - WINDOWS[config.id].posY; + WINDOWS[config.id].vars.startingWidth = WINDOWS[config.id].width; + WINDOWS[config.id].vars.startingHeight = WINDOWS[config.id].height; + WINDOWS[config.id].vars.startingPosX = WINDOWS[config.id].posX; + WINDOWS[config.id].vars.startingPosY = WINDOWS[config.id].posY; + MOUSE_MOVE_PROCESSING[config.id] = { + callback: (x, y) => { edgeMoveEvent(x, y, pos, config.id); }, + mouseUp: true + }; + }); + edges.append(el); + } wO.append(w); - wC.append(wH, wO); + wC.append(wH, wO, edges); document.body.append(wC); if (config.typeable !== false) { wC.append(wI); @@ -116,6 +169,8 @@ function createWindow(config) { element: wC, height: realHeight, width: realWidth, + minHeight: config.minHeight, + minWidth: config.minWidth, posX: posX, posY: posY, fullscreen: false, @@ -188,19 +243,6 @@ function createWindow(config) { }); globalIncrement++; } -window.addEventListener("mousemove", function (e) { - for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) { - MOUSE_MOVE_PROCESSING[key].callback(e.clientX, e.clientY); - } -}); -window.addEventListener("mouseup", function () { - for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) { - if (MOUSE_MOVE_PROCESSING[key].mouseUp) { - delete MOUSE_MOVE_PROCESSING[key]; - } - ; - } -}); function windowPreset(template) { let el = document.querySelector(`#window-templates > [data-template-id="${template}"]`); if (!el) { @@ -227,3 +269,30 @@ function windowPreset(template) { function copyButton() { navigator.clipboard.writeText("\"trinkey's"); } +onmousemove = function (e) { + e.preventDefault(); + for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) { + MOUSE_MOVE_PROCESSING[key].callback(e.clientX, e.clientY); + } +}; +onmouseup = function () { + for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) { + if (MOUSE_MOVE_PROCESSING[key].mouseUp) { + delete MOUSE_MOVE_PROCESSING[key]; + } + ; + } +}; +onresize = function () { + for (const window of Object.keys(WINDOWS)) { + WINDOWS[window].posX = Math.max(0, Math.min(innerWidth - WINDOWS[window].width - _windowPaddingX, WINDOWS[window].posX)); + WINDOWS[window].posY = Math.max(0, Math.min(innerHeight - WINDOWS[window].height - _windowPaddingY, WINDOWS[window].posY)); + WINDOWS[window].width = Math.max(WINDOWS[window].minWidth, Math.min(WINDOWS[window].width, innerWidth - _windowPaddingX)); + WINDOWS[window].height = Math.max(WINDOWS[window].minHeight, Math.min(WINDOWS[window].height, innerHeight - _windowPaddingY)); + WINDOWS[window].element.style.left = `${WINDOWS[window].posX}px`; + WINDOWS[window].element.style.top = `${WINDOWS[window].posY}px`; + WINDOWS[window].element.style.width = `${WINDOWS[window].width + _windowPaddingX - 2}px`; + WINDOWS[window].element.querySelector(".window").style.width = `${WINDOWS[window].width}px`; + WINDOWS[window].element.querySelector(".window").style.height = `${WINDOWS[window].height}px`; + } +}; diff --git a/ts/globals.d.ts b/ts/globals.d.ts index 5c5d8a2..75475d9 100644 --- a/ts/globals.d.ts +++ b/ts/globals.d.ts @@ -20,6 +20,8 @@ type _winConf = { element: HTMLElement, height: number, width: number, + minHeight: number, + minWidth: number, posX: number, posY: number, fullscreen: boolean, diff --git a/ts/index.ts b/ts/index.ts index 3352958..371ee2c 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -1,3 +1,9 @@ +// 1 - border +// 10 - padding +// 35 - header +const _windowPaddingX: number = 1*2 + 10*2; +const _windowPaddingY: number = 1*2 + 10*2 + 35; + let WINDOWS: { [key: string]: _winConf } = {}; let MOUSE_MOVE_PROCESSING: { [key: string]: { @@ -22,18 +28,48 @@ function incrementZIndex(windowID: string, focus: boolean=false): void { } } +function edgeMoveEvent(x: number, y: number, pos: "top" | "bottom" | "left" | "right" | "top-left" | "top-right" | "bottom-left" | "bottom-right" | string, windowID: string): void { + let w: _winConf = WINDOWS[windowID]; + + if (x - w.vars.mouseOffsetX < 0) { x = w.vars.mouseOffsetX; } + if (y - w.vars.mouseOffsetY < 0) { y = w.vars.mouseOffsetY; } + + if (pos == "top" || pos.startsWith("top-")) { + w.height = Math.max(-(y - w.vars.mouseOffsetY - w.vars.startingPosY) + w.vars.startingHeight, w.minHeight); + w.posY = Math.max(w.vars.startingHeight - w.height + w.vars.startingPosY, 0); + } else if (pos == "bottom" || pos.startsWith("bottom-")) { + w.height = Math.max(y - w.vars.mouseOffsetY - w.vars.startingPosY + w.vars.startingHeight, w.minHeight); + } + + if (pos == "left" || pos.endsWith("-left")) { + w.width = Math.max(-(x - w.vars.mouseOffsetX - w.vars.startingPosX) + w.vars.startingWidth, w.minWidth); + w.posX = Math.max(w.vars.startingWidth - w.width + w.vars.startingPosX, 0); + } else if (pos == "right" || pos.endsWith("-right")) { + w.width = Math.max(x - w.vars.mouseOffsetX - w.vars.startingPosX + w.vars.startingWidth, w.minWidth); + } + + if (w.posX + w.width + _windowPaddingX > innerWidth ) { + w.width = Math.max(innerWidth - w.posX - _windowPaddingX, w.minWidth); + } + + if (w.posY + w.height + _windowPaddingY > innerHeight) { + w.height = Math.max(innerHeight - w.posY - _windowPaddingY, w.minHeight); + } + + w.element.style.left = `${w.posX}px`; + w.element.style.top = `${w.posY}px`; + + w.element.style.width = `${w.width + _windowPaddingX - 2}px`; + (w.element.querySelector(".window") as HTMLElement).style.width = `${w.width }px`; + (w.element.querySelector(".window") as HTMLElement).style.height = `${w.height}px`; +} + function createWindow(config: _winInitConf): void { if (document.getElementById(config.id)) { incrementZIndex(config.id); return; } - // 1 - border - // 10 - padding - // 35 - header - let _windowPaddingX: number = 1*2 + 10*2; - let _windowPaddingY: number = 1*2 + 10*2 + 35; - config.width = config.width || 600; config.height = config.height || 400; config.minWidth = config.minWidth || 200; @@ -68,7 +104,12 @@ function createWindow(config: _winInitConf): void { let wC: HTMLDivElement | HTMLLabelElement; let wI: HTMLInputElement = null; + if (config.typeable !== false) { + wI = document.createElement("input"); + wI.classList.add("window-input"); + wI.id = `${config.id}__input`; + function syncInputs(): void { setTimeout(function(): void { let text: string = wI.value; @@ -92,10 +133,6 @@ function createWindow(config: _winInitConf): void { }, 0); } - wI = document.createElement("input"); - wI.classList.add("window-input"); - wI.id = `${config.id}__input`; - wI.oninput = (event: KeyboardEvent): void => { syncInputs(); w.scrollTop = w.scrollHeight; @@ -128,8 +165,30 @@ function createWindow(config: _winInitConf): void { wC.style.zIndex = String(globalIncrement); wC.style.width = `${realWidth + _windowPaddingX - 2}px`; + let edges: DocumentFragment = document.createDocumentFragment(); + for (const pos of ["top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"]) { + let el: HTMLDivElement = document.createElement("div"); + el.classList.add("edge", pos); + el.addEventListener("mousedown", function(e: MouseEvent): void { + e.preventDefault(); + + WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX; + WINDOWS[config.id].vars.mouseOffsetY = e.clientY - WINDOWS[config.id].posY; + WINDOWS[config.id].vars.startingWidth = WINDOWS[config.id].width; + WINDOWS[config.id].vars.startingHeight = WINDOWS[config.id].height; + WINDOWS[config.id].vars.startingPosX = WINDOWS[config.id].posX; + WINDOWS[config.id].vars.startingPosY = WINDOWS[config.id].posY; + MOUSE_MOVE_PROCESSING[config.id] = { + callback: (x: number, y: number): void => { edgeMoveEvent(x, y, pos, config.id); }, + mouseUp: true + }; + }); + + edges.append(el); + } + wO.append(w); - wC.append(wH, wO); + wC.append(wH, wO, edges); document.body.append(wC); if (config.typeable !== false) { @@ -143,6 +202,8 @@ function createWindow(config: _winInitConf): void { element: wC, height: realHeight, width: realWidth, + minHeight: config.minHeight, + minWidth: config.minWidth, posX: posX, posY: posY, fullscreen: false, @@ -225,20 +286,6 @@ function createWindow(config: _winInitConf): void { globalIncrement++; } -window.addEventListener("mousemove", function(e: MouseEvent): void { - for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) { - MOUSE_MOVE_PROCESSING[key].callback(e.clientX, e.clientY); - } -}); - -window.addEventListener("mouseup", function(): void { - for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) { - if (MOUSE_MOVE_PROCESSING[key].mouseUp) { - delete MOUSE_MOVE_PROCESSING[key]; - }; - } -}); - function windowPreset(template: string): void { let el: HTMLElement = document.querySelector(`#window-templates > [data-template-id="${template}"]`); @@ -270,3 +317,36 @@ function windowPreset(template: string): void { function copyButton(): void { navigator.clipboard.writeText("\"trinkey's"); } + +onmousemove = function(e: MouseEvent): void { + e.preventDefault(); + + for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) { + MOUSE_MOVE_PROCESSING[key].callback(e.clientX, e.clientY); + } +} + +onmouseup = function(): void { + for (const key of Object.keys(MOUSE_MOVE_PROCESSING)) { + if (MOUSE_MOVE_PROCESSING[key].mouseUp) { + delete MOUSE_MOVE_PROCESSING[key]; + }; + } +} + +onresize = function(): void { + for (const window of Object.keys(WINDOWS)) { + WINDOWS[window].posX = Math.max(0, Math.min(innerWidth - WINDOWS[window].width - _windowPaddingX, WINDOWS[window].posX)); + WINDOWS[window].posY = Math.max(0, Math.min(innerHeight - WINDOWS[window].height - _windowPaddingY, WINDOWS[window].posY)); + + WINDOWS[window].width = Math.max(WINDOWS[window].minWidth, Math.min(WINDOWS[window].width, innerWidth - _windowPaddingX)); + WINDOWS[window].height = Math.max(WINDOWS[window].minHeight, Math.min(WINDOWS[window].height, innerHeight - _windowPaddingY)); + + WINDOWS[window].element.style.left = `${WINDOWS[window].posX}px`; + WINDOWS[window].element.style.top = `${WINDOWS[window].posY}px`; + + WINDOWS[window].element.style.width = `${WINDOWS[window].width + _windowPaddingX - 2}px`; + (WINDOWS[window].element.querySelector(".window") as HTMLElement).style.width = `${WINDOWS[window].width }px`; + (WINDOWS[window].element.querySelector(".window") as HTMLElement).style.height = `${WINDOWS[window].height}px`; + } +}