abtmtr-v4/views/scripts/windows.js

323 lines
9.6 KiB
JavaScript
Raw Normal View History

2023-11-23 18:26:44 +00:00
function isTouchDevice() {
return (
"ontouchstart" in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0
);
}
2023-11-23 08:53:28 +00:00
class WindowObject {
windowObject;
windowManager;
windowManagerLabel;
windowContent;
#orig_mousePosX;
#orig_mousePosY;
#orig_selfPosX;
#orig_selfPosY;
#isDragging;
2023-11-23 18:05:19 +00:00
constructor(parent, content, srcdoc, w, h) {
2023-11-23 08:53:28 +00:00
this.parentElement = parent;
2023-11-23 18:05:19 +00:00
this.windowObject = WindowObject.createWindow(this, content, srcdoc, w, h);
2023-11-23 08:53:28 +00:00
this.parentElement.appendChild(this.windowObject);
WindowObject.raiseWindow(this.windowObject);
2023-11-23 18:26:44 +00:00
if (isTouchDevice()) this.maximizeWindow();
2023-11-23 08:53:28 +00:00
this.windowManager = this.windowObject.querySelector(".window-manager");
this.windowManagerLabel = this.windowObject.querySelector(
".window-manager-label"
);
this.windowContent = this.windowObject.querySelector(".window-content");
this.windowManager.addEventListener("mousedown", (e) =>
this.event__dragMouseDown(e)
);
this.windowManager.addEventListener("mousemove", (e) =>
this.event__dragMouseMove(e)
);
this.windowManager.addEventListener("mouseup", (e) =>
this.event__dragMouseUp(e)
);
this.windowManager.addEventListener("mouseout", (e) =>
this.event__dragMouseMove(e)
);
2023-11-23 18:26:44 +00:00
this.windowManager.addEventListener("touchstart", (e) =>
this.event__dragMouseDown(e, true)
);
this.windowManager.addEventListener("touchmove", (e) =>
this.event__dragMouseMove(e, true)
);
this.windowManager.addEventListener("touchend", (e) =>
this.event__dragMouseUp(e, true)
);
this.windowObject.addEventListener("keydown", (e) =>
this.event__responseKeyDown(e)
);
2023-11-23 08:53:28 +00:00
this.windowObject.addEventListener("mousedown", (e) =>
WindowObject.raiseWindow(this.windowObject)
);
this.windowContent.contentWindow.addEventListener("mousedown", (e) =>
WindowObject.raiseWindow(this.windowObject)
);
window.addEventListener("beforeunload", () => this.destroy());
2023-11-23 08:53:28 +00:00
this.windowContent.addEventListener("load", () => {
this.title = this.windowContent.contentWindow.document.title;
2023-11-23 18:26:44 +00:00
if (!srcdoc) {
const nb = this.windowManager.querySelector(".window-new-button");
nb.addEventListener("click", () => {
window.open(this.content);
});
nb.addEventListener("touchstart", (e) => e.stopPropagation());
nb.addEventListener("touchend", (e) => e.stopPropagation());
}
2023-11-23 08:53:28 +00:00
});
}
get title() {
return this.windowManagerLabel.textContent;
}
get content() {
2023-11-23 17:56:39 +00:00
return this.windowContent.src;
2023-11-23 08:53:28 +00:00
}
set title(content) {
this.windowManagerLabel.textContent = content;
}
set content(src) {
2023-11-23 17:56:39 +00:00
this.windowContent.src = src;
2023-11-23 08:53:28 +00:00
}
minimizeWindow() {
if (this.windowObject.classList.contains("minimized")) {
this.windowObject.classList.remove("minimized");
WindowObject.raiseWindow(this.windowObject);
} else {
this.windowObject.classList.add("minimized");
this.windowObject.style.zIndex = 50;
}
}
maximizeWindow() {
this.windowObject.classList.toggle("maximized");
WindowObject.raiseWindow(this.windowObject);
}
destroy() {
if (this.windowContent.contentWindow != null) {
const unloadEvent = new Event("beforeunload");
this.windowContent.contentWindow.dispatchEvent(unloadEvent);
}
2023-11-23 08:53:28 +00:00
this.windowObject.classList.add("closed");
setTimeout(() => {
this.windowObject.remove();
var someWindow = this.parentElement.querySelector(
`.window-object:last-child`
);
if (someWindow != null) WindowObject.raiseWindow(someWindow);
}, 250);
}
2023-11-23 18:26:44 +00:00
event__dragMouseDown(e, touch) {
2023-11-23 08:53:28 +00:00
e.preventDefault();
2023-11-23 18:26:44 +00:00
this.#orig_mousePosX = touch ? e.touches[0].clientX : e.clientX;
this.#orig_mousePosY = touch ? e.touches[0].clientY : e.clientY;
2023-11-23 08:53:28 +00:00
this.#orig_selfPosX = this.windowObject.offsetLeft;
this.#orig_selfPosY = this.windowObject.offsetTop;
this.windowContent.style.userSelect = "none";
this.windowContent.style.pointerEvents = "none";
this.windowManager.style.cursor = "move";
this.#isDragging = true;
if (this.windowObject.style.zIndex != 100)
WindowObject.raiseWindow(this.windowObject);
}
2023-11-23 18:26:44 +00:00
event__dragMouseUp(e, touch) {
2023-11-23 08:53:28 +00:00
e.preventDefault();
this.#orig_mousePosX = 0;
this.#orig_mousePosY = 0;
this.windowContent.style.userSelect = "auto";
this.windowContent.style.pointerEvents = "auto";
this.windowManager.style.cursor = "default";
this.#isDragging = false;
}
2023-11-23 18:26:44 +00:00
event__dragMouseMove(e, touch) {
2023-11-23 08:53:28 +00:00
e.preventDefault();
if (this.#isDragging) {
2023-11-23 18:26:44 +00:00
var cX = touch ? e.touches[0].clientX : e.clientX;
var cY = touch ? e.touches[0].clientY : e.clientY;
2023-11-23 08:53:28 +00:00
this.windowObject.style.left =
2023-11-23 18:26:44 +00:00
this.#orig_selfPosX - (this.#orig_mousePosX - cX) + "px";
2023-11-23 08:53:28 +00:00
this.windowObject.style.top =
2023-11-23 18:26:44 +00:00
this.#orig_selfPosY - (this.#orig_mousePosY - cY) + "px";
2023-11-23 08:53:28 +00:00
}
}
event__responseKeyDown(e) {
e.preventDefault();
switch (e.code) {
case "Backspace":
this.destroy();
break;
case "Space":
this.maximizeWindow();
break;
case "ArrowUp":
if (e.shiftKey)
this.windowObject.style.height =
this.windowObject.offsetHeight - 10 + "px";
else
this.windowObject.style.top = this.windowObject.offsetTop - 10 + "px";
break;
case "ArrowDown":
if (e.shiftKey)
this.windowObject.style.height =
this.windowObject.offsetHeight + 10 + "px";
else
this.windowObject.style.top = this.windowObject.offsetTop + 10 + "px";
break;
case "ArrowLeft":
if (e.shiftKey)
this.windowObject.style.width =
this.windowObject.offsetWidth - 10 + "px";
else
this.windowObject.style.left =
this.windowObject.offsetLeft - 10 + "px";
break;
case "ArrowRight":
if (e.shiftKey)
this.windowObject.style.width =
this.windowObject.offsetWidth + 10 + "px";
else
this.windowObject.style.left =
this.windowObject.offsetLeft + 10 + "px";
break;
}
}
2023-11-23 08:53:28 +00:00
static raiseWindow(windowObj) {
windowObj.parentElement.querySelectorAll(".window-object").forEach((x) => {
if (x.style.zIndex > 50) x.style.zIndex -= 1;
x.classList.add("unfocused");
});
windowObj.style.zIndex = 100;
windowObj.classList.remove("unfocused");
windowObj.focus();
}
2023-11-23 18:05:19 +00:00
static createWindow(windowRef, content, srcdoc, w, h) {
2023-11-23 08:53:28 +00:00
const windowObject = document.createElement("div");
windowObject.classList.add("window-object");
windowObject.style.width = `calc(${w}px + 2.75em)`;
windowObject.style.height = `calc(${h}px + 4.5em)`;
windowObject.style.left = `calc(50vw - ${w / 2}px)`;
windowObject.style.top = `calc(50vh - ${h / 2}px)`;
windowObject.tabIndex = "0";
2023-11-23 08:53:28 +00:00
{
const windowManager = document.createElement("div");
windowManager.classList.add("window-manager");
{
const windowManagerStart = document.createElement("div");
windowManagerStart.classList.add("window-manager-start");
{
const windowManagerLabel = document.createElement("span");
windowManagerLabel.textContent = "";
windowManagerLabel.classList.add("window-manager-label");
windowManagerStart.appendChild(windowManagerLabel);
}
windowManager.appendChild(windowManagerStart);
}
{
const windowManagerEnd = document.createElement("div");
windowManagerEnd.classList.add("window-manager-end");
if (!srcdoc) {
2023-11-23 08:53:28 +00:00
const windowNewButton = document.createElement("button");
windowNewButton.innerHTML = "open_in_new";
windowNewButton.classList.add("window-new-button");
windowManagerEnd.appendChild(windowNewButton);
}
{
const windowMaximizeButton = document.createElement("button");
windowMaximizeButton.innerHTML = "maximize";
windowMaximizeButton.classList.add("window-maximize-button");
windowMaximizeButton.ariaHidden = true; // esoteric operation to screen-reader users
windowMaximizeButton.addEventListener("click", () =>
windowRef.maximizeWindow()
);
2023-11-23 18:26:44 +00:00
windowMaximizeButton.addEventListener("touchstart", (e) =>
e.stopPropagation()
);
windowMaximizeButton.addEventListener("touchend", (e) =>
e.stopPropagation()
);
2023-11-23 08:53:28 +00:00
windowManagerEnd.appendChild(windowMaximizeButton);
}
{
const windowDestroyButton = document.createElement("button");
windowDestroyButton.innerHTML = "close";
windowDestroyButton.classList.add("window-destroy-button");
windowDestroyButton.ariaHidden = true;
windowDestroyButton.addEventListener("click", () =>
windowRef.destroy()
);
2023-11-23 18:26:44 +00:00
windowDestroyButton.addEventListener("touchstart", (e) =>
e.stopPropagation()
);
windowDestroyButton.addEventListener("touchend", (e) =>
e.stopPropagation()
);
2023-11-23 08:53:28 +00:00
windowManagerEnd.appendChild(windowDestroyButton);
}
windowManager.appendChild(windowManagerEnd);
}
windowObject.appendChild(windowManager);
}
{
const windowContent = document.createElement("iframe");
windowContent.classList.add("window-content");
{
if (srcdoc) windowContent.srcdoc = content;
else windowContent.src = content;
2023-11-23 08:53:28 +00:00
}
windowObject.appendChild(windowContent);
}
return windowObject;
}
}