const _windowPaddingX = 1 * 2 + 10 * 2; const _windowPaddingY = 1 * 2 + 10 * 2 + 35; let WINDOWS = {}; let MOUSE_MOVE_PROCESSING = {}; let globalIncrement = 1; function escapeHTML(string) { return string.replaceAll("&", "&").replaceAll("<", "<").replaceAll("\"", """); } function incrementZIndex(windowID, focus = false) { WINDOWS[windowID].element.style.zIndex = String(globalIncrement); WINDOWS[windowID].zIndex = globalIncrement; globalIncrement++; if (focus) { WINDOWS[windowID].element.focus(); } } function edgeMoveEvent(x, y, pos, windowID) { let w = WINDOWS[windowID]; if (w.fullscreen) { return; } 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); if (w.posY < 0) { w.height -= w.posY; w.posY = 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); if (w.posX < 0) { w.width -= w.posX; w.posX = 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; } config.width = config.width || 600; config.height = config.height || 400; config.minWidth = config.minWidth || 200; config.minHeight = config.minHeight || 200; let realWidth = Math.max(config.minWidth, Math.min(config.width, innerWidth - _windowPaddingX - 20)); let realHeight = Math.max(config.minHeight, Math.min(config.height, innerHeight - _windowPaddingY - 20)); let posX = config.posX || Math.round((innerWidth / 2) - ((realWidth + _windowPaddingX) / 2)); let posY = config.posY || Math.round((innerHeight / 2) - ((realHeight + _windowPaddingY) / 2)); let wO = document.createElement("div"); wO.classList.add("window-outer"); let w = document.createElement("div"); w.classList.add("window"); w.style.width = `${realWidth}px`; w.style.height = `${realHeight}px`; w.innerHTML = config.content; let wH = document.createElement("div"); wH.classList.add("window-header"); wH.innerHTML = ` ${config.title} `; 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; let cursor = wI.selectionStart; let el = wC.querySelector("[data-type-area]"); if (!el) { return; } if (cursor == text.length) { el.innerHTML = `${escapeHTML(text)} `; } else { el.innerHTML = `${escapeHTML(text.slice(0, cursor))}${escapeHTML(text[cursor])}${escapeHTML(text.slice(cursor + 1))}`; } }, 1); } function setCursor() { setTimeout(() => { wI.setSelectionRange(wI.value.length, wI.value.length); syncInputs(); }, 0); } wI.oninput = (event) => { syncInputs(); w.scrollTop = w.scrollHeight; }; wI.onkeydown = (event) => { if (event.key == "Enter") { commandManager(config.id, wI.value.trim()); w.scrollTop = w.scrollHeight; wI.value = ""; } else { syncInputs(); } }; wI.onfocus = setCursor; wI.onclick = setCursor; wC = document.createElement("label"); wC.htmlFor = `${config.id}__input`; } else { wC = document.createElement("div"); } wC.classList.add("window-container"); wC.tabIndex = 0; wC.style.left = `${posX}px`; wC.style.top = `${posY}px`; 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, edges); document.body.append(wC); if (config.typeable !== false) { wC.append(wI); wI.focus(); } else { wC.focus(); } WINDOWS[config.id] = { element: wC, height: realHeight, width: realWidth, minHeight: config.minHeight, minWidth: config.minWidth, posX: posX, posY: posY, fullscreen: false, zIndex: globalIncrement, vars: {} }; function mouseMoveEvent(x, y) { WINDOWS[config.id].posX = Math.max(0, Math.min(innerWidth - WINDOWS[config.id].width - _windowPaddingX, x - WINDOWS[config.id].vars.mouseOffsetX)); WINDOWS[config.id].posY = Math.max(0, Math.min(innerHeight - WINDOWS[config.id].height - _windowPaddingY, y - WINDOWS[config.id].vars.mouseOffsetY)); wC.style.left = `${WINDOWS[config.id].posX}px`; wC.style.top = `${WINDOWS[config.id].posY}px`; } wC.addEventListener("focus", function () { incrementZIndex(config.id); }); for (const link of wC.querySelectorAll("a")) { link.addEventListener("focus", function () { incrementZIndex(config.id); }); } wH.addEventListener("mousedown", function (e) { if (e.target.dataset.noMove !== undefined) { return; } WINDOWS[config.id].vars.mouseOffsetX = e.clientX - WINDOWS[config.id].posX; WINDOWS[config.id].vars.mouseOffsetY = e.clientY - WINDOWS[config.id].posY; MOUSE_MOVE_PROCESSING[config.id] = { callback: mouseMoveEvent, mouseUp: true }; }); wH.querySelector(".close").addEventListener("click", function () { delete WINDOWS[config.id]; delete windowInformation[config.id]; delete MOUSE_MOVE_PROCESSING[config.id]; wC.remove(); if (typeof config.onDestroy === "function") { config.onDestroy(); } }); wH.querySelector(".fullscreen").addEventListener("click", function () { let window = WINDOWS[config.id]; if (window.fullscreen) { window.posX = Math.max(0, Math.min(innerWidth - window.vars.oldWidth - _windowPaddingX, window.vars.oldPosX)); window.posY = Math.max(0, Math.min(innerHeight - window.vars.oldHeight - _windowPaddingY, window.vars.oldPosY)); window.width = Math.max(window.minWidth, Math.min(window.vars.oldWidth, innerWidth - _windowPaddingX)); window.height = Math.max(window.minHeight, Math.min(window.vars.oldHeight, innerHeight - _windowPaddingY)); window.fullscreen = false; delete window.vars.oldPosX; delete window.vars.oldPosY; delete window.vars.oldWidth; delete window.vars.oldHeight; wC.style.left = `${window.posX}px`; wC.style.top = `${window.posY}px`; wC.style.width = `${window.width + _windowPaddingX - 2}px`; w.style.width = `${window.width}px`; w.style.height = `${window.height}px`; } else { window.vars.oldPosX = window.posX; window.vars.oldPosY = window.posY; window.vars.oldWidth = window.width; window.vars.oldHeight = window.height; window.fullscreen = true; window.posX = 0; window.posY = 0; window.width = innerWidth; window.height = innerHeight; wC.style.left = "0px"; wC.style.top = "0px"; wC.style.width = `${window.width}px`; w.style.width = `${window.width - _windowPaddingX}px`; w.style.height = `${window.height - _windowPaddingY}px`; } }); globalIncrement++; } function windowPreset(template, dontDisableTyping = false) { let el = document.querySelector(`#window-templates > [data-template-id="${template}"]`); if (!el) { return; } if (WINDOWS[template]) { incrementZIndex(template, true); return; } let config = { id: template, title: "~ - tSh", content: "
trinkey@website:~ 
" }; for (const field of el.querySelectorAll("[data-template-field]")) { config[field.dataset.templateField] = field.dataset.isNumber === "" ? +field.innerText : field.innerHTML; } createWindow(config); for (const command of el.querySelectorAll("li")) { WINDOWS[template].element.querySelector("[data-type-area]").innerHTML = command.innerHTML; commandManager(template, command.innerHTML); } if (!dontDisableTyping) { WINDOWS[template].element.querySelector("input").remove(); } } function emptyWindow() { createWindow({ id: `terminal-${Math.random()}`, title: "~ - tSh", content: "
trinkey@website:~ 
" }); } 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)) { let w = WINDOWS[window]; if (w.fullscreen) { w.width = innerWidth - _windowPaddingX + 2; w.height = innerHeight - _windowPaddingY + 2; } else { w.posX = Math.max(0, Math.min(innerWidth - w.width - _windowPaddingX, w.posX)); w.posY = Math.max(0, Math.min(innerHeight - w.height - _windowPaddingY, w.posY)); w.width = Math.max(w.minWidth, Math.min(w.width, innerWidth - _windowPaddingX)); w.height = Math.max(w.minHeight, Math.min(w.height, innerHeight - _windowPaddingY)); } 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`; } };