We should improve windowing somewhat.
Yet you participate in windowing, curious! I am very intelligent.
This commit is contained in:
parent
7f689d5817
commit
e0c355ad82
11 changed files with 480 additions and 111 deletions
|
@ -78,5 +78,10 @@
|
||||||
<script src="/scripts/windows.js"></script>
|
<script src="/scripts/windows.js"></script>
|
||||||
<script src="/scripts/accessibility.js"></script>
|
<script src="/scripts/accessibility.js"></script>
|
||||||
<script src="/scripts/interface.js"></script>
|
<script src="/scripts/interface.js"></script>
|
||||||
|
<script>
|
||||||
|
window.manager = new WindowManager(
|
||||||
|
document.getElementById("WindowHolder")
|
||||||
|
);
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -49,8 +49,7 @@ function averageColors(hex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function initDocument(hx, w, h, t) {
|
function initDocument(hx, w, h, t) {
|
||||||
const newWindow = new WindowObject(
|
const newWindow = window.top.manager.createWindow(
|
||||||
window.parent.document.querySelector("#WindowHolder"),
|
|
||||||
`<html>
|
`<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Result</title>
|
<title>Result</title>
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
<title>Project Windows</title>
|
<title>Project Windows</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="stylesheet" href="/styles/normal.css" />
|
<link rel="stylesheet" href="/styles/normal.css" />
|
||||||
<link rel="stylesheet" href="/styles/style.css" />
|
|
||||||
<link rel="stylesheet" href="/styles/windows.css" />
|
<link rel="stylesheet" href="/styles/windows.css" />
|
||||||
|
<link rel="stylesheet" href="/styles/style.css" />
|
||||||
<style>
|
<style>
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100;200;300;400;500;600;700;800;900&display=swap");
|
@import url("https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@100;200;300;400;500;600;700;800;900&display=swap");
|
||||||
|
|
||||||
|
@ -29,23 +29,18 @@
|
||||||
<p>Various projects I've made.</p>
|
<p>Various projects I've made.</p>
|
||||||
</section>
|
</section>
|
||||||
<$ nav.html $>
|
<$ nav.html $>
|
||||||
<section>
|
<section id="data_get">
|
||||||
<button
|
<h1>Getting projects...</h1>
|
||||||
onclick="
|
|
||||||
new WindowObject(document.getElementById('WindowHolder'), '/projects/hex/')"
|
|
||||||
>
|
|
||||||
Open Hex
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onclick="
|
|
||||||
new WindowObject(document.getElementById('WindowHolder'), '/projects/woz/')"
|
|
||||||
>
|
|
||||||
Open Woz
|
|
||||||
</button>
|
|
||||||
</section>
|
</section>
|
||||||
<div id="WindowHolder"></div>
|
<div id="WindowHolder"></div>
|
||||||
<section id="accessibility" hidden></section>
|
<section id="accessibility" hidden></section>
|
||||||
<script src="/scripts/windows.js"></script>
|
<script src="/scripts/windows.js"></script>
|
||||||
<script src="/scripts/accessibility.js"></script>
|
<script src="/scripts/accessibility.js"></script>
|
||||||
|
<script src="./scripts/data_get_projects.js"></script>
|
||||||
|
<script>
|
||||||
|
window.manager = new WindowManager(
|
||||||
|
document.getElementById("WindowHolder")
|
||||||
|
);
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
20
views/projects/public/projects.json
Normal file
20
views/projects/public/projects.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "HexFlagGen",
|
||||||
|
"date": 1700114400000,
|
||||||
|
"description": [
|
||||||
|
"HexFlagGen is a flag generator inspired by how the <a href=\"https://en.wikipedia.org/wiki/Free_Speech_Flag\" target=\"_blank\">Free Speech Flag</a> was made.",
|
||||||
|
"I dislike DRM and support trans rights."
|
||||||
|
],
|
||||||
|
"url": "/projects/hex/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "WozSteamGen",
|
||||||
|
"date": 1700200800000,
|
||||||
|
"description": [
|
||||||
|
"WozSteamGen is a Scott The Woz thumbnail generator for Steam games.",
|
||||||
|
"It's an API-less adaptation of Steam The Woz, running completely locally."
|
||||||
|
],
|
||||||
|
"url": "/projects/woz/"
|
||||||
|
}
|
||||||
|
]
|
25
views/projects/scripts/data_get_projects.js
Normal file
25
views/projects/scripts/data_get_projects.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const data_get = document.getElementById("data_get");
|
||||||
|
fetch("./public/projects.json")
|
||||||
|
.then((x) => x.json())
|
||||||
|
.then((projects) => {
|
||||||
|
data_get.innerHTML = projects.reduce(
|
||||||
|
(html, project) =>
|
||||||
|
html +
|
||||||
|
`<h1>${project.name}</h1>
|
||||||
|
<p><b>${new Date(project.date).toLocaleDateString()}</b></p>
|
||||||
|
${project.description.reduce(
|
||||||
|
(html, descfragment) => html + `<p>${descfragment}</p>`,
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
<p>
|
||||||
|
<button onclick="window.open('${project.url}')">Open</button> or
|
||||||
|
<button
|
||||||
|
onclick="
|
||||||
|
new WindowObject(manager, '${project.url}')"
|
||||||
|
>
|
||||||
|
Open Window
|
||||||
|
</button>
|
||||||
|
</p>`,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
});
|
|
@ -77,5 +77,10 @@
|
||||||
<script src="/scripts/windows.js"></script>
|
<script src="/scripts/windows.js"></script>
|
||||||
<script src="/scripts/accessibility.js"></script>
|
<script src="/scripts/accessibility.js"></script>
|
||||||
<script src="/scripts/interface.js"></script>
|
<script src="/scripts/interface.js"></script>
|
||||||
|
<script>
|
||||||
|
window.manager = new WindowManager(
|
||||||
|
document.getElementById("WindowHolder")
|
||||||
|
);
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -18,8 +18,8 @@ async function loadImage(url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function initDocument(hx, w, h, t) {
|
function initDocument(hx, w, h, t) {
|
||||||
const newWindow = new WindowObject(
|
console.log(window.parent, window.parent.manager);
|
||||||
window.parent.document.querySelector("#WindowHolder"),
|
const newWindow = window.top.manager.createWindow(
|
||||||
`<html>
|
`<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Result</title>
|
<title>Result</title>
|
||||||
|
@ -35,6 +35,7 @@ function initDocument(hx, w, h, t) {
|
||||||
|
|
||||||
newWindow.windowContent.contentWindow.addEventListener("load", () => {
|
newWindow.windowContent.contentWindow.addEventListener("load", () => {
|
||||||
getScott(newWindow.windowContent.contentDocument.querySelector("#canvas"));
|
getScott(newWindow.windowContent.contentDocument.querySelector("#canvas"));
|
||||||
|
propagateStyles(getComputedStyle(root), newWindow.windowObject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,25 +6,129 @@ function isTouchDevice() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WindowManager {
|
||||||
|
managerObject;
|
||||||
|
|
||||||
|
children;
|
||||||
|
|
||||||
|
minZIndex = 50;
|
||||||
|
maxZIndex = 100;
|
||||||
|
|
||||||
|
constructor(manager) {
|
||||||
|
this.managerObject = manager;
|
||||||
|
this.managerObject.classList.add("window-master");
|
||||||
|
this.managerObject.style.zIndex = this.minZIndex;
|
||||||
|
|
||||||
|
this.children = [];
|
||||||
|
|
||||||
|
window.addEventListener("beforeunload", () => this.destroy());
|
||||||
|
|
||||||
|
this.managerObject.addEventListener("windowcreate", (e) =>
|
||||||
|
this.#event_manageMinimized(e)
|
||||||
|
);
|
||||||
|
this.managerObject.addEventListener("windowminimize", (e) =>
|
||||||
|
this.#event_manageMinimized(e)
|
||||||
|
);
|
||||||
|
this.managerObject.addEventListener("windowdestroy", (e) =>
|
||||||
|
this.#event_manageMinimized(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
createWindow(content, srcdoc, w, h) {
|
||||||
|
return new WindowObject(this, content, srcdoc, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
#event_manageMinimized(e) {
|
||||||
|
this.children
|
||||||
|
.filter((x) => x.minimized)
|
||||||
|
.forEach((curWinObj, i) => {
|
||||||
|
curWinObj.windowObject.style.bottom = `calc(2em * ${i})`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
raiseIndex(windowObj, add, focus = true) {
|
||||||
|
const sortedFocusArray = this.children.toSorted(
|
||||||
|
(x, y) => x.focusOrder - y.focusOrder
|
||||||
|
);
|
||||||
|
this.raiseWindow(
|
||||||
|
sortedFocusArray.at(
|
||||||
|
(sortedFocusArray.indexOf(windowObj) + add) % this.children.length
|
||||||
|
),
|
||||||
|
focus
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addWindow(windowObj) {
|
||||||
|
this.children.push(windowObj);
|
||||||
|
|
||||||
|
this.managerObject.appendChild(windowObj.windowObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeWindow(windowId) {
|
||||||
|
this.children.splice(windowId, 1);
|
||||||
|
if (this.children.length > 0)
|
||||||
|
this.raiseWindow(
|
||||||
|
this.children.toSorted((x, y) => x.focusOrder - y.focusOrder)[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.children.forEach((x) => {
|
||||||
|
console.log(x);
|
||||||
|
x.destroy();
|
||||||
|
});
|
||||||
|
this.managerObject.remove();
|
||||||
|
this.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvent(eventName, data) {
|
||||||
|
const event = new CustomEvent(eventName, data);
|
||||||
|
|
||||||
|
this.managerObject.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
raiseWindow(windowObj, focus = true) {
|
||||||
|
this.children
|
||||||
|
.toSorted((x, y) => x.focusOrder - y.focusOrder)
|
||||||
|
.forEach((curWinObj, i) => {
|
||||||
|
curWinObj.focusOrder = i + 1;
|
||||||
|
curWinObj.windowObject.style.zIndex = this.maxZIndex - (i + 1);
|
||||||
|
curWinObj.windowObject.classList.add("unfocused");
|
||||||
|
});
|
||||||
|
windowObj.focusOrder = 0;
|
||||||
|
windowObj.windowObject.style.zIndex = windowObj.parentManager.maxZIndex;
|
||||||
|
windowObj.windowObject.classList.remove("unfocused");
|
||||||
|
if (focus) windowObj.windowObject.focus();
|
||||||
|
windowObj.dispatchEvent("windowfocus", { detail: windowObj });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class WindowObject {
|
class WindowObject {
|
||||||
|
parentManager;
|
||||||
windowObject;
|
windowObject;
|
||||||
|
|
||||||
windowManager;
|
windowManager;
|
||||||
windowManagerLabel;
|
windowManagerLabel;
|
||||||
windowContent;
|
windowContent;
|
||||||
|
|
||||||
|
focusOrder;
|
||||||
|
|
||||||
#orig_mousePosX;
|
#orig_mousePosX;
|
||||||
#orig_mousePosY;
|
#orig_mousePosY;
|
||||||
#orig_selfPosX;
|
#orig_selfPosX;
|
||||||
#orig_selfPosY;
|
#orig_selfPosY;
|
||||||
#isDragging;
|
#isDragging;
|
||||||
|
#isFrozen;
|
||||||
|
#isRemoved = false;
|
||||||
|
|
||||||
constructor(parent, content, srcdoc, w, h) {
|
constructor(manager, content, srcdoc, w, h) {
|
||||||
this.parentElement = parent;
|
this.parentManager = manager;
|
||||||
this.windowObject = WindowObject.createWindow(this, content, srcdoc, w, h);
|
this.windowObject = WindowObject.createWindow(this, content, srcdoc, w, h);
|
||||||
this.parentElement.appendChild(this.windowObject);
|
this.parentManager.addWindow(this);
|
||||||
|
|
||||||
WindowObject.raiseWindow(this.windowObject);
|
this.dispatchEvent("windowcreate", { detail: this });
|
||||||
|
|
||||||
|
this.parentManager.raiseWindow(this);
|
||||||
|
|
||||||
if (isTouchDevice()) this.maximizeWindow();
|
if (isTouchDevice()) this.maximizeWindow();
|
||||||
|
|
||||||
|
@ -34,47 +138,47 @@ class WindowObject {
|
||||||
);
|
);
|
||||||
this.windowContent = this.windowObject.querySelector(".window-content");
|
this.windowContent = this.windowObject.querySelector(".window-content");
|
||||||
|
|
||||||
this.windowManager.addEventListener("mousedown", (e) =>
|
this.windowManager.addEventListener("mousedown", (e) => {
|
||||||
this.event__dragMouseDown(e)
|
this.event__dragMouseDown(e);
|
||||||
);
|
this.parentManager.raiseWindow(this);
|
||||||
this.windowManager.addEventListener("mousemove", (e) =>
|
});
|
||||||
|
this.windowObject.addEventListener("mousemove", (e) =>
|
||||||
this.event__dragMouseMove(e)
|
this.event__dragMouseMove(e)
|
||||||
);
|
);
|
||||||
this.windowManager.addEventListener("mouseup", (e) =>
|
this.windowObject.addEventListener("mouseout", (e) =>
|
||||||
|
this.event__dragMouseMove(e)
|
||||||
|
);
|
||||||
|
this.windowObject.addEventListener("mouseup", (e) =>
|
||||||
this.event__dragMouseUp(e)
|
this.event__dragMouseUp(e)
|
||||||
);
|
);
|
||||||
this.windowManager.addEventListener("mouseout", (e) =>
|
this.windowManager.addEventListener("touchstart", (e) => {
|
||||||
this.event__dragMouseMove(e)
|
this.event__dragMouseDown(e, true);
|
||||||
);
|
this.parentManager.raiseWindow(this);
|
||||||
this.windowManager.addEventListener("touchstart", (e) =>
|
});
|
||||||
this.event__dragMouseDown(e, true)
|
this.parentManager.managerObject.addEventListener("touchmove", (e) =>
|
||||||
);
|
|
||||||
this.windowManager.addEventListener("touchmove", (e) =>
|
|
||||||
this.event__dragMouseMove(e, true)
|
this.event__dragMouseMove(e, true)
|
||||||
);
|
);
|
||||||
this.windowManager.addEventListener("touchend", (e) =>
|
this.parentManager.managerObject.addEventListener("touchend", (e) =>
|
||||||
this.event__dragMouseUp(e, true)
|
this.event__dragMouseUp(e, true)
|
||||||
);
|
);
|
||||||
this.windowObject.addEventListener("keydown", (e) =>
|
this.windowObject.addEventListener("keydown", (e) =>
|
||||||
this.event__responseKeyDown(e)
|
this.event__responseKeyDown(e)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.windowObject.addEventListener("mousedown", (e) =>
|
this.windowObject.addEventListener("focus", (e) =>
|
||||||
WindowObject.raiseWindow(this.windowObject)
|
this.parentManager.raiseWindow(this)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.windowContent.contentWindow.addEventListener("mousedown", (e) =>
|
this.windowContent.contentWindow.addEventListener("focus", (e) =>
|
||||||
WindowObject.raiseWindow(this.windowObject)
|
this.parentManager.raiseWindow(this, false)
|
||||||
);
|
);
|
||||||
|
|
||||||
window.addEventListener("beforeunload", () => this.destroy());
|
|
||||||
|
|
||||||
this.windowContent.addEventListener("load", () => {
|
this.windowContent.addEventListener("load", () => {
|
||||||
this.title = this.windowContent.contentWindow.document.title;
|
this.title = this.windowContent.contentWindow.document.title;
|
||||||
if (!srcdoc) {
|
if (!srcdoc) {
|
||||||
const nb = this.windowManager.querySelector(".window-new-button");
|
const nb = this.windowManager.querySelector(".window-new-button");
|
||||||
nb.addEventListener("click", () => {
|
nb.addEventListener("click", () => {
|
||||||
window.open(this.content);
|
window.open(this.contentUrl);
|
||||||
});
|
});
|
||||||
nb.addEventListener("touchstart", (e) => e.stopPropagation());
|
nb.addEventListener("touchstart", (e) => e.stopPropagation());
|
||||||
nb.addEventListener("touchend", (e) => e.stopPropagation());
|
nb.addEventListener("touchend", (e) => e.stopPropagation());
|
||||||
|
@ -82,37 +186,212 @@ class WindowObject {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dispatchEvent(eventName, data) {
|
||||||
|
const event = new CustomEvent(eventName, data);
|
||||||
|
|
||||||
|
this.parentManager.managerObject.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
get windowId() {
|
||||||
|
return this.parentManager.children.indexOf(this);
|
||||||
|
}
|
||||||
|
|
||||||
get title() {
|
get title() {
|
||||||
return this.windowManagerLabel.textContent;
|
return this.windowManagerLabel.textContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
get content() {
|
get content() {
|
||||||
|
return this.windowContent.srcdoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
get contentUrl() {
|
||||||
return this.windowContent.src;
|
return this.windowContent.src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get x() {
|
||||||
|
return this.windowObject.offsetLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
get y() {
|
||||||
|
return this.windowObject.offsetTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
get width() {
|
||||||
|
return this.windowObject.offsetWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
get height() {
|
||||||
|
return this.windowObject.offsetHeight;
|
||||||
|
}
|
||||||
|
|
||||||
set title(content) {
|
set title(content) {
|
||||||
this.windowManagerLabel.textContent = content;
|
this.windowManagerLabel.textContent = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
set content(src) {
|
set content(src) {
|
||||||
this.windowContent.src = src;
|
this.windowContent.srcdoc = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
set contentUrl(url) {
|
||||||
|
this.windowContent.src = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
set x(x) {
|
||||||
|
this.windowObject.style.left = x + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
set y(y) {
|
||||||
|
this.windowObject.style.top = y = "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
set width(w) {
|
||||||
|
this.windowObject.style.width = w + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
set height(h) {
|
||||||
|
this.windowObject.style.height = h = "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
freezeWindow() {
|
||||||
|
this.#isFrozen = !this.#isFrozen;
|
||||||
|
|
||||||
|
this.dispatchEvent("windowfreeze", { detail: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
set frozen(state) {
|
||||||
|
if (state != this.frozen)
|
||||||
|
this.dispatchEvent("windowfreeze", { detail: this });
|
||||||
|
|
||||||
|
this.#isFrozen = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
get frozen() {
|
||||||
|
return this.#isFrozen;
|
||||||
|
}
|
||||||
|
|
||||||
|
petrifyWindow() {
|
||||||
|
if (this.windowObject.classList.contains("petrified")) {
|
||||||
|
this.windowObject.classList.remove("petrified");
|
||||||
|
this.windowObject.style.minWidth = null;
|
||||||
|
this.windowObject.style.maxWidth = null;
|
||||||
|
this.windowObject.style.minHeight = null;
|
||||||
|
this.windowObject.style.maxHeight = null;
|
||||||
|
} else {
|
||||||
|
this.windowObject.classList.add("petrified");
|
||||||
|
this.windowObject.style.minWidth = this.w + "px";
|
||||||
|
this.windowObject.style.maxWidth = this.w + "px";
|
||||||
|
this.windowObject.style.minHeight = this.h + "px";
|
||||||
|
this.windowObject.style.maxHeight = this.h + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispatchEvent("windowpetrify", { detail: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
set petrified(state) {
|
||||||
|
if (state != this.petrified)
|
||||||
|
this.dispatchEvent("windowpetrify", { detail: this });
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
this.windowObject.classList.add("petrified");
|
||||||
|
this.windowObject.style.minWidth = this.w + "px";
|
||||||
|
this.windowObject.style.maxWidth = this.w + "px";
|
||||||
|
this.windowObject.style.minHeight = this.h + "px";
|
||||||
|
this.windowObject.style.maxHeight = this.h + "px";
|
||||||
|
} else {
|
||||||
|
this.windowObject.classList.remove("petrified");
|
||||||
|
this.windowObject.style.minWidth = null;
|
||||||
|
this.windowObject.style.maxWidth = null;
|
||||||
|
this.windowObject.style.minHeight = null;
|
||||||
|
this.windowObject.style.maxHeight = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get petrified() {
|
||||||
|
return this.windowObject.classList.contains("petrified");
|
||||||
}
|
}
|
||||||
|
|
||||||
minimizeWindow() {
|
minimizeWindow() {
|
||||||
if (this.windowObject.classList.contains("minimized")) {
|
if (this.windowObject.classList.contains("minimized")) {
|
||||||
this.windowObject.classList.remove("minimized");
|
this.windowObject.classList.remove("minimized");
|
||||||
|
|
||||||
WindowObject.raiseWindow(this.windowObject);
|
this.frozen = false;
|
||||||
|
this.petrified = false;
|
||||||
|
this.windowObject.style.setProperty("--z-index", null);
|
||||||
|
|
||||||
|
this.parentManager.raiseWindow(this);
|
||||||
} else {
|
} else {
|
||||||
this.windowObject.classList.add("minimized");
|
this.windowObject.classList.add("minimized");
|
||||||
this.windowObject.style.zIndex = 50;
|
this.maximized = false;
|
||||||
|
|
||||||
|
this.frozen = true;
|
||||||
|
this.petrified = true;
|
||||||
|
this.windowObject.style.setProperty(
|
||||||
|
"--z-index",
|
||||||
|
this.parentManager.minZIndex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispatchEvent("windowminimize", { detail: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
set minimized(state) {
|
||||||
|
if (state != this.minimized)
|
||||||
|
this.dispatchEvent("windowminimize", { detail: this });
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
this.windowObject.classList.add("minimized");
|
||||||
|
this.maximized = false;
|
||||||
|
|
||||||
|
this.frozen = true;
|
||||||
|
this.petrified = true;
|
||||||
|
this.windowObject.style.setProperty(
|
||||||
|
"--z-index",
|
||||||
|
this.parentManager.minZIndex
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.windowObject.classList.remove("minimized");
|
||||||
|
|
||||||
|
this.frozen = false;
|
||||||
|
this.petrified = false;
|
||||||
|
this.windowObject.style.setProperty("--z-index", null);
|
||||||
|
|
||||||
|
this.parentManager.raiseWindow(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maximizeWindow() {
|
get minimized() {
|
||||||
this.windowObject.classList.toggle("maximized");
|
return this.windowObject.classList.contains("minimized");
|
||||||
|
}
|
||||||
|
|
||||||
WindowObject.raiseWindow(this.windowObject);
|
maximizeWindow() {
|
||||||
|
if (this.windowObject.classList.contains("maximized")) {
|
||||||
|
this.windowObject.classList.remove("maximized");
|
||||||
|
} else {
|
||||||
|
this.windowObject.classList.add("maximized");
|
||||||
|
this.minimized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parentManager.raiseWindow(this);
|
||||||
|
|
||||||
|
this.dispatchEvent("windowmaximize", { detail: this });
|
||||||
|
}
|
||||||
|
|
||||||
|
set maximized(state) {
|
||||||
|
if (state != this.maximized)
|
||||||
|
this.dispatchEvent("windowmaximize", { detail: this });
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
this.windowObject.classList.add("maximized");
|
||||||
|
this.minimized = false;
|
||||||
|
} else {
|
||||||
|
this.windowObject.classList.remove("maximized");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parentManager.raiseWindow(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
get maximized() {
|
||||||
|
return this.windowObject.classList.contains("maximized");
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
@ -121,18 +400,14 @@ class WindowObject {
|
||||||
this.windowContent.contentWindow.dispatchEvent(unloadEvent);
|
this.windowContent.contentWindow.dispatchEvent(unloadEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.windowObject.classList.add("closed");
|
this.windowObject.remove();
|
||||||
setTimeout(() => {
|
|
||||||
this.windowObject.remove();
|
this.parentManager.removeWindow(this.windowId);
|
||||||
var someWindow = this.parentElement.querySelector(
|
this.dispatchEvent("windowdestroy", { detail: this });
|
||||||
`.window-object:last-child`
|
|
||||||
);
|
|
||||||
if (someWindow != null) WindowObject.raiseWindow(someWindow);
|
|
||||||
}, 250);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event__dragMouseDown(e, touch) {
|
event__dragMouseDown(e, touch) {
|
||||||
e.preventDefault();
|
if (this.#isFrozen) return;
|
||||||
|
|
||||||
this.#orig_mousePosX = touch ? e.touches[0].clientX : e.clientX;
|
this.#orig_mousePosX = touch ? e.touches[0].clientX : e.clientX;
|
||||||
this.#orig_mousePosY = touch ? e.touches[0].clientY : e.clientY;
|
this.#orig_mousePosY = touch ? e.touches[0].clientY : e.clientY;
|
||||||
|
@ -142,12 +417,17 @@ class WindowObject {
|
||||||
this.windowContent.style.pointerEvents = "none";
|
this.windowContent.style.pointerEvents = "none";
|
||||||
this.windowManager.style.cursor = "move";
|
this.windowManager.style.cursor = "move";
|
||||||
this.#isDragging = true;
|
this.#isDragging = true;
|
||||||
if (this.windowObject.style.zIndex != 100)
|
if (this.windowObject.style.zIndex != this.parentManager.maxZIndex)
|
||||||
WindowObject.raiseWindow(this.windowObject);
|
this.parentManager.raiseWindow(this);
|
||||||
|
|
||||||
|
this.dispatchEvent("windowdragdown", { detail: this, mouse: e });
|
||||||
}
|
}
|
||||||
|
|
||||||
event__dragMouseUp(e, touch) {
|
event__dragMouseUp(e, touch) {
|
||||||
e.preventDefault();
|
if (this.#isFrozen) return;
|
||||||
|
|
||||||
|
if (this.#isDragging)
|
||||||
|
this.dispatchEvent("windowdragup", { detail: this, mouse: e });
|
||||||
|
|
||||||
this.#orig_mousePosX = 0;
|
this.#orig_mousePosX = 0;
|
||||||
this.#orig_mousePosY = 0;
|
this.#orig_mousePosY = 0;
|
||||||
|
@ -158,7 +438,7 @@ class WindowObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
event__dragMouseMove(e, touch) {
|
event__dragMouseMove(e, touch) {
|
||||||
e.preventDefault();
|
if (this.#isFrozen) return;
|
||||||
|
|
||||||
if (this.#isDragging) {
|
if (this.#isDragging) {
|
||||||
var cX = touch ? e.touches[0].clientX : e.clientX;
|
var cX = touch ? e.touches[0].clientX : e.clientX;
|
||||||
|
@ -167,20 +447,25 @@ class WindowObject {
|
||||||
this.#orig_selfPosX - (this.#orig_mousePosX - cX) + "px";
|
this.#orig_selfPosX - (this.#orig_mousePosX - cX) + "px";
|
||||||
this.windowObject.style.top =
|
this.windowObject.style.top =
|
||||||
this.#orig_selfPosY - (this.#orig_mousePosY - cY) + "px";
|
this.#orig_selfPosY - (this.#orig_mousePosY - cY) + "px";
|
||||||
|
|
||||||
|
this.dispatchEvent("windowdragmove", { detail: this, mouse: e });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event__responseKeyDown(e) {
|
event__responseKeyDown(e) {
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
switch (e.code) {
|
switch (e.code) {
|
||||||
|
case "Backquote":
|
||||||
|
this.parentManager.raiseIndex(this, 1);
|
||||||
|
break;
|
||||||
case "Backspace":
|
case "Backspace":
|
||||||
this.destroy();
|
this.destroy();
|
||||||
break;
|
break;
|
||||||
case "Space":
|
case "Space":
|
||||||
this.maximizeWindow();
|
if (e.shiftKey) this.minimizeWindow();
|
||||||
|
else this.maximizeWindow();
|
||||||
break;
|
break;
|
||||||
case "ArrowUp":
|
case "ArrowUp":
|
||||||
|
if (this.#isFrozen) return;
|
||||||
if (e.shiftKey)
|
if (e.shiftKey)
|
||||||
this.windowObject.style.height =
|
this.windowObject.style.height =
|
||||||
this.windowObject.offsetHeight - 10 + "px";
|
this.windowObject.offsetHeight - 10 + "px";
|
||||||
|
@ -188,6 +473,7 @@ class WindowObject {
|
||||||
this.windowObject.style.top = this.windowObject.offsetTop - 10 + "px";
|
this.windowObject.style.top = this.windowObject.offsetTop - 10 + "px";
|
||||||
break;
|
break;
|
||||||
case "ArrowDown":
|
case "ArrowDown":
|
||||||
|
if (this.#isFrozen) return;
|
||||||
if (e.shiftKey)
|
if (e.shiftKey)
|
||||||
this.windowObject.style.height =
|
this.windowObject.style.height =
|
||||||
this.windowObject.offsetHeight + 10 + "px";
|
this.windowObject.offsetHeight + 10 + "px";
|
||||||
|
@ -195,6 +481,7 @@ class WindowObject {
|
||||||
this.windowObject.style.top = this.windowObject.offsetTop + 10 + "px";
|
this.windowObject.style.top = this.windowObject.offsetTop + 10 + "px";
|
||||||
break;
|
break;
|
||||||
case "ArrowLeft":
|
case "ArrowLeft":
|
||||||
|
if (this.#isFrozen) return;
|
||||||
if (e.shiftKey)
|
if (e.shiftKey)
|
||||||
this.windowObject.style.width =
|
this.windowObject.style.width =
|
||||||
this.windowObject.offsetWidth - 10 + "px";
|
this.windowObject.offsetWidth - 10 + "px";
|
||||||
|
@ -203,6 +490,7 @@ class WindowObject {
|
||||||
this.windowObject.offsetLeft - 10 + "px";
|
this.windowObject.offsetLeft - 10 + "px";
|
||||||
break;
|
break;
|
||||||
case "ArrowRight":
|
case "ArrowRight":
|
||||||
|
if (this.#isFrozen) return;
|
||||||
if (e.shiftKey)
|
if (e.shiftKey)
|
||||||
this.windowObject.style.width =
|
this.windowObject.style.width =
|
||||||
this.windowObject.offsetWidth + 10 + "px";
|
this.windowObject.offsetWidth + 10 + "px";
|
||||||
|
@ -210,19 +498,16 @@ class WindowObject {
|
||||||
this.windowObject.style.left =
|
this.windowObject.style.left =
|
||||||
this.windowObject.offsetLeft + 10 + "px";
|
this.windowObject.offsetLeft + 10 + "px";
|
||||||
break;
|
break;
|
||||||
|
case "KeyR":
|
||||||
|
if (this.#isFrozen) return;
|
||||||
|
this.windowObject.style.width = `600px`;
|
||||||
|
this.windowObject.style.height = `500px`;
|
||||||
|
this.windowObject.style.left = `calc(50vw - ${this.width / 2}px)`;
|
||||||
|
this.windowObject.style.top = `calc(50vh - ${this.height / 2}px)`;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
static createWindow(windowRef, content, srcdoc, w, h) {
|
static createWindow(windowRef, content, srcdoc, w, h) {
|
||||||
const windowObject = document.createElement("div");
|
const windowObject = document.createElement("div");
|
||||||
windowObject.classList.add("window-object");
|
windowObject.classList.add("window-object");
|
||||||
|
@ -263,6 +548,23 @@ class WindowObject {
|
||||||
windowManagerEnd.appendChild(windowNewButton);
|
windowManagerEnd.appendChild(windowNewButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const windowMinimizeButton = document.createElement("button");
|
||||||
|
windowMinimizeButton.innerHTML = "minimize";
|
||||||
|
windowMinimizeButton.classList.add("window-minimize-button");
|
||||||
|
windowMinimizeButton.addEventListener("click", () =>
|
||||||
|
windowRef.minimizeWindow()
|
||||||
|
);
|
||||||
|
windowMinimizeButton.addEventListener("touchstart", (e) =>
|
||||||
|
e.stopPropagation()
|
||||||
|
);
|
||||||
|
windowMinimizeButton.addEventListener("touchend", (e) =>
|
||||||
|
e.stopPropagation()
|
||||||
|
);
|
||||||
|
|
||||||
|
windowManagerEnd.appendChild(windowMinimizeButton);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const windowMaximizeButton = document.createElement("button");
|
const windowMaximizeButton = document.createElement("button");
|
||||||
windowMaximizeButton.innerHTML = "maximize";
|
windowMaximizeButton.innerHTML = "maximize";
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
"Segoe UI Symbol";
|
"Segoe UI Symbol";
|
||||||
--document-width: 40em;
|
--document-width: 40em;
|
||||||
|
|
||||||
--border-style: 0.0625em solid var(--color);
|
--border-style: calc(1em / 16) solid var(--color);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -35,17 +35,23 @@ html.base {
|
||||||
"Segoe UI Symbol" !important;
|
"Segoe UI Symbol" !important;
|
||||||
--document-width: 40em;
|
--document-width: 40em;
|
||||||
|
|
||||||
--border-style: 0.0625em solid var(--color);
|
--border-style: calc(1em / 16) solid var(--color);
|
||||||
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.base body {
|
html.base body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html.base * {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Size and type normalize */
|
/* Size and type normalize */
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-size: var(--base-scale);
|
font-size: var(--base-scale);
|
||||||
|
line-height: 1em;
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
color: var(--color);
|
color: var(--color);
|
||||||
}
|
}
|
||||||
|
@ -185,6 +191,7 @@ input[type="reset"] {
|
||||||
margin-inline: 0;
|
margin-inline: 0;
|
||||||
margin-block: 0.25em;
|
margin-block: 0.25em;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
line-height: 1.25em;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
background-color: var(--accent-color);
|
background-color: var(--accent-color);
|
||||||
color: var(--accent-color-fg);
|
color: var(--accent-color-fg);
|
||||||
|
|
|
@ -9,3 +9,13 @@
|
||||||
#accessibility fieldset {
|
#accessibility fieldset {
|
||||||
margin-block: 0;
|
margin-block: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* * {
|
||||||
|
font-smooth: never;
|
||||||
|
-webkit-font-smoothing: subpixel-antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
} */
|
||||||
|
|
||||||
|
* {
|
||||||
|
transition: background-color 0.25s, color 0.25s, opacity 0.25s;
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0");
|
@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0");
|
||||||
|
|
||||||
@keyframes appear {
|
.window-master {
|
||||||
from {
|
display: inline-block;
|
||||||
scale: 0;
|
position: fixed;
|
||||||
opacity: 0;
|
left: 0;
|
||||||
}
|
top: 0;
|
||||||
to {
|
width: 0;
|
||||||
scale: 1;
|
height: 0;
|
||||||
opacity: 1;
|
overflow: visible;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div.window-object {
|
div.window-object {
|
||||||
|
@ -20,6 +19,7 @@ div.window-object {
|
||||||
height: 500px;
|
height: 500px;
|
||||||
left: calc(50vw - 300px);
|
left: calc(50vw - 300px);
|
||||||
top: calc(50vh - 250px);
|
top: calc(50vh - 250px);
|
||||||
|
bottom: auto;
|
||||||
|
|
||||||
min-width: 10em;
|
min-width: 10em;
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
|
@ -30,7 +30,8 @@ div.window-object {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
/* padding: 0.5em; */
|
/* padding: 0.5em; */
|
||||||
transition: opacity 0.25s, scale 0.25s;
|
/* transition: background-color 0.25s, color 0.25s, opacity 0.25s; */
|
||||||
|
transition: none;
|
||||||
|
|
||||||
scale: 1;
|
scale: 1;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
@ -42,32 +43,10 @@ div.window-object.unfocused {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.window-object.closed {
|
div.window-object.petrified {
|
||||||
scale: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.window-object.minimized {
|
|
||||||
top: auto !important;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0 !important;
|
|
||||||
max-width: 20em !important;
|
|
||||||
width: 20em !important;
|
|
||||||
min-width: 20em !important;
|
|
||||||
max-height: 2.5em !important;
|
|
||||||
height: 2.5em !important;
|
|
||||||
min-height: 2.5em !important;
|
|
||||||
resize: none;
|
resize: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.window-object.minimized > div.window-manager {
|
|
||||||
cursor: default !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.window-object.minimized > iframe.window-content {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.window-object.maximized {
|
div.window-object.maximized {
|
||||||
top: 0 !important;
|
top: 0 !important;
|
||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
|
@ -84,6 +63,27 @@ div.window-object.maximized > div.window-manager {
|
||||||
cursor: default !important;
|
cursor: default !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.window-object.minimized {
|
||||||
|
top: auto !important;
|
||||||
|
left: 0 !important;
|
||||||
|
max-width: 20em !important;
|
||||||
|
width: 20em !important;
|
||||||
|
min-width: 20em !important;
|
||||||
|
max-height: calc(2em + (1em / 16)) !important;
|
||||||
|
height: calc(2em + (1em / 16)) !important;
|
||||||
|
min-height: calc(2em + (1em / 16)) !important;
|
||||||
|
resize: none;
|
||||||
|
z-index: var(--z-index) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.window-object.minimized > div.window-manager {
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.window-object.minimized > iframe.window-content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
div.window-object > div.window-manager {
|
div.window-object > div.window-manager {
|
||||||
display: grid;
|
display: grid;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -131,8 +131,8 @@ div.window-object > div.window-manager > div > button {
|
||||||
margin-inline-start: 0.25em;
|
margin-inline-start: 0.25em;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: var(--border-style);
|
border: var(--border-style);
|
||||||
background-color: var(--accent-color);
|
background-color: transparent;
|
||||||
color: var(--accent-color-fg);
|
color: currentColor;
|
||||||
font-family: "Material Symbols Outlined";
|
font-family: "Material Symbols Outlined";
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
Loading…
Reference in a new issue