moving to custom swap engine
Signed-off-by: ari melody <ari@arimelody.me>
This commit is contained in:
parent
749f9bc8b7
commit
13d802d361
21 changed files with 4361 additions and 225 deletions
|
@ -1,44 +0,0 @@
|
|||
const accessibility = JSON.parse(localStorage.getItem("accessibility")) || {};
|
||||
|
||||
function toggle_accessibility_setting(name) {
|
||||
if (accessibility[name]) {
|
||||
delete accessibility[name];
|
||||
update_accessibility();
|
||||
return true;
|
||||
}
|
||||
accessibility[name] = true;
|
||||
update_accessibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
function set_accessibility_setting(name, value) {
|
||||
accessibility[name] = value;
|
||||
update_accessibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
function clear_accessibility_setting(name) {
|
||||
if (!accessibility[name]) return false;
|
||||
delete accessibility[name];
|
||||
update_accessibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
function update_accessibility() {
|
||||
localStorage.setItem("accessibility", JSON.stringify(accessibility));
|
||||
}
|
||||
|
||||
if (accessibility) {
|
||||
if (accessibility.disable_crt) {
|
||||
document.querySelector('div#overlay').setAttribute("hidden", true);
|
||||
document.body.style.textShadow = "none";
|
||||
document.getElementById('toggle-crt').classList.add("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("toggle-crt").addEventListener("click", () => {
|
||||
toggle_accessibility_setting("disable_crt");
|
||||
document.querySelector('div#overlay').toggleAttribute("hidden");
|
||||
document.getElementById('toggle-crt').className = accessibility.disable_crt ? "disabled" : "";
|
||||
});
|
||||
|
42
public/script/config.js
Normal file
42
public/script/config.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
function toggle_config_setting(config, name) {
|
||||
if (config[name]) {
|
||||
delete config[name];
|
||||
update_config(config);
|
||||
return true;
|
||||
}
|
||||
config[name] = true;
|
||||
update_config(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
function set_config_setting(config, name, value) {
|
||||
config[name] = value;
|
||||
update_config(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
function clear_config_setting(config, name) {
|
||||
if (!config[name]) return false;
|
||||
delete config[name];
|
||||
update_config(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
function update_config(config) {
|
||||
localStorage.setItem("config", JSON.stringify(config));
|
||||
}
|
||||
|
||||
const config = JSON.parse(localStorage.getItem("config")) || {};
|
||||
if (config) {
|
||||
if (config.disable_crt) {
|
||||
document.querySelector('div#overlay').setAttribute("hidden", true);
|
||||
document.body.style.textShadow = "none";
|
||||
document.getElementById('toggle-crt').classList.add("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("toggle-crt").addEventListener("click", () => {
|
||||
toggle_config_setting(config, "disable_crt");
|
||||
document.querySelector('div#overlay').toggleAttribute("hidden");
|
||||
document.getElementById('toggle-crt').className = config.disable_crt ? "disabled" : "";
|
||||
});
|
|
@ -1,14 +1,12 @@
|
|||
const header_links = document.getElementById("header-links");
|
||||
const hamburger = document.getElementById("header-links-toggle");
|
||||
|
||||
function toggle_header_links() {
|
||||
header_links.classList.toggle("open");
|
||||
}
|
||||
|
||||
document.addEventListener("click", event => {
|
||||
if (!header_links.contains(event.target) && !hamburger.contains(event.target) && !header_links.href) {
|
||||
header_links.classList.remove("open");
|
||||
}
|
||||
});
|
||||
|
||||
hamburger.addEventListener("click", event => { toggle_header_links(); });
|
||||
hamburger.addEventListener("click", event => {
|
||||
header_links.classList.toggle("open");
|
||||
});
|
||||
|
|
147
public/script/lib/htmx-preload.js
Normal file
147
public/script/lib/htmx-preload.js
Normal file
|
@ -0,0 +1,147 @@
|
|||
// This adds the "preload" extension to htmx. By default, this will
|
||||
// preload the targets of any tags with `href` or `hx-get` attributes
|
||||
// if they also have a `preload` attribute as well. See documentation
|
||||
// for more details
|
||||
htmx.defineExtension("preload", {
|
||||
|
||||
onEvent: function(name, event) {
|
||||
|
||||
// Only take actions on "htmx:afterProcessNode"
|
||||
if (name !== "htmx:afterProcessNode") {
|
||||
return;
|
||||
}
|
||||
|
||||
// SOME HELPER FUNCTIONS WE'LL NEED ALONG THE WAY
|
||||
|
||||
// attr gets the closest non-empty value from the attribute.
|
||||
var attr = function(node, property) {
|
||||
if (node == undefined) {return undefined;}
|
||||
return node.getAttribute(property) || node.getAttribute("data-" + property) || attr(node.parentElement, property)
|
||||
}
|
||||
|
||||
// load handles the actual HTTP fetch, and uses htmx.ajax in cases where we're
|
||||
// preloading an htmx resource (this sends the same HTTP headers as a regular htmx request)
|
||||
var load = function(node) {
|
||||
|
||||
// Called after a successful AJAX request, to mark the
|
||||
// content as loaded (and prevent additional AJAX calls.)
|
||||
var done = function(html) {
|
||||
if (!node.preloadAlways) {
|
||||
node.preloadState = "DONE"
|
||||
}
|
||||
|
||||
if (attr(node, "preload-images") == "true") {
|
||||
document.createElement("div").innerHTML = html // create and populate a node to load linked resources, too.
|
||||
}
|
||||
}
|
||||
|
||||
return function() {
|
||||
|
||||
// If this value has already been loaded, then do not try again.
|
||||
if (node.preloadState !== "READY") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Special handling for HX-GET - use built-in htmx.ajax function
|
||||
// so that headers match other htmx requests, then set
|
||||
// node.preloadState = TRUE so that requests are not duplicated
|
||||
// in the future
|
||||
var hxGet = node.getAttribute("hx-get") || node.getAttribute("data-hx-get")
|
||||
if (hxGet) {
|
||||
htmx.ajax("GET", hxGet, {
|
||||
source: node,
|
||||
handler:function(elt, info) {
|
||||
done(info.xhr.responseText);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, perform a standard xhr request, then set
|
||||
// node.preloadState = TRUE so that requests are not duplicated
|
||||
// in the future.
|
||||
if (node.getAttribute("href")) {
|
||||
var r = new XMLHttpRequest();
|
||||
r.open("GET", node.getAttribute("href"));
|
||||
r.onload = function() {done(r.responseText);};
|
||||
r.send();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function processes a specific node and sets up event handlers.
|
||||
// We'll search for nodes and use it below.
|
||||
var init = function(node) {
|
||||
|
||||
// If this node DOES NOT include a "GET" transaction, then there's nothing to do here.
|
||||
if (node.getAttribute("href") + node.getAttribute("hx-get") + node.getAttribute("data-hx-get") == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Guarantee that we only initialize each node once.
|
||||
if (node.preloadState !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get event name from config.
|
||||
var on = attr(node, "preload") || "mousedown"
|
||||
const always = on.indexOf("always") !== -1
|
||||
if (always) {
|
||||
on = on.replace('always', '').trim()
|
||||
}
|
||||
|
||||
// FALL THROUGH to here means we need to add an EventListener
|
||||
|
||||
// Apply the listener to the node
|
||||
node.addEventListener(on, function(evt) {
|
||||
if (node.preloadState === "PAUSE") { // Only add one event listener
|
||||
node.preloadState = "READY"; // Required for the `load` function to trigger
|
||||
|
||||
// Special handling for "mouseover" events. Wait 100ms before triggering load.
|
||||
if (on === "mouseover") {
|
||||
window.setTimeout(load(node), 100);
|
||||
} else {
|
||||
load(node)() // all other events trigger immediately.
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Special handling for certain built-in event handlers
|
||||
switch (on) {
|
||||
|
||||
case "mouseover":
|
||||
// Mirror `touchstart` events (fires immediately)
|
||||
node.addEventListener("touchstart", load(node));
|
||||
|
||||
// WHhen the mouse leaves, immediately disable the preload
|
||||
node.addEventListener("mouseout", function(evt) {
|
||||
if ((evt.target === node) && (node.preloadState === "READY")) {
|
||||
node.preloadState = "PAUSE";
|
||||
}
|
||||
})
|
||||
break;
|
||||
|
||||
case "mousedown":
|
||||
// Mirror `touchstart` events (fires immediately)
|
||||
node.addEventListener("touchstart", load(node));
|
||||
break;
|
||||
}
|
||||
|
||||
// Mark the node as ready to run.
|
||||
node.preloadState = "PAUSE";
|
||||
node.preloadAlways = always;
|
||||
htmx.trigger(node, "preload:init") // This event can be used to load content immediately.
|
||||
}
|
||||
|
||||
// Search for all child nodes that have a "preload" attribute
|
||||
event.target.querySelectorAll("[preload]").forEach(function(node) {
|
||||
|
||||
// Initialize the node with the "preload" attribute
|
||||
init(node)
|
||||
|
||||
// Initialize all child elements that are anchors or have `hx-get` (use with care)
|
||||
node.querySelectorAll("a,[hx-get],[data-hx-get]").forEach(init)
|
||||
})
|
||||
}
|
||||
})
|
3922
public/script/lib/htmx.js
Normal file
3922
public/script/lib/htmx.js
Normal file
File diff suppressed because it is too large
Load diff
2
public/script/lib/htmx.min.js
vendored
2
public/script/lib/htmx.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,5 @@
|
|||
import "./header.js";
|
||||
import "./accessibility.js";
|
||||
import "./config.js";
|
||||
|
||||
function type_out(e) {
|
||||
const text = e.innerText;
|
||||
|
@ -34,46 +34,50 @@ function type_out(e) {
|
|||
}
|
||||
|
||||
function fill_list(list) {
|
||||
const items = list.querySelectorAll("li a, li span");
|
||||
items.innerText = "";
|
||||
const delay = 100;
|
||||
const items = list.querySelectorAll("li a, li span");
|
||||
items.innerText = "";
|
||||
const delay = 100;
|
||||
|
||||
items.forEach((item, iter) => {
|
||||
item.style.animationDelay = `${iter * delay}ms`;
|
||||
item.style.animationPlayState = "playing";
|
||||
});
|
||||
items.forEach((item, iter) => {
|
||||
item.style.animationDelay = `${iter * delay}ms`;
|
||||
item.style.animationPlayState = "playing";
|
||||
});
|
||||
}
|
||||
|
||||
[...document.querySelectorAll("h1, h2, h3, h4, h5, h6")]
|
||||
.filter((e) => e.innerText != "")
|
||||
.forEach((e) => {
|
||||
type_out(e);
|
||||
});
|
||||
[...document.querySelectorAll("ol, ul")]
|
||||
.filter((e) => e.innerText != "")
|
||||
.forEach((e) => {
|
||||
fill_list(e);
|
||||
});
|
||||
function start() {
|
||||
[...document.querySelectorAll("h1, h2, h3, h4, h5, h6")]
|
||||
.filter((e) => e.innerText != "")
|
||||
.forEach((e) => {
|
||||
type_out(e);
|
||||
});
|
||||
[...document.querySelectorAll("ol, ul")]
|
||||
.filter((e) => e.innerText != "")
|
||||
.forEach((e) => {
|
||||
fill_list(e);
|
||||
});
|
||||
|
||||
document.addEventListener("htmx:afterSwap", async event => {
|
||||
const res = await event.detail.xhr.response;
|
||||
var new_head = res.substring(res.indexOf("<head>")+1, res.indexOf("</head>"));
|
||||
if (new_head) {
|
||||
document.head.innerHTML = new_head;
|
||||
}
|
||||
window.scrollY = 0;
|
||||
});
|
||||
document.addEventListener("htmx:afterSwap", async event => {
|
||||
const res = await event.detail.xhr.response;
|
||||
var new_head = res.substring(res.indexOf("<head>")+1, res.indexOf("</head>"));
|
||||
if (new_head) {
|
||||
document.head.innerHTML = new_head;
|
||||
}
|
||||
window.scrollY = 0;
|
||||
});
|
||||
|
||||
const top_button = document.getElementById("backtotop");
|
||||
window.onscroll = () => {
|
||||
if (!top_button) return;
|
||||
const btt_threshold = 100;
|
||||
if (
|
||||
document.body.scrollTop > btt_threshold ||
|
||||
const top_button = document.getElementById("backtotop");
|
||||
window.onscroll = () => {
|
||||
if (!top_button) return;
|
||||
const btt_threshold = 100;
|
||||
if (
|
||||
document.body.scrollTop > btt_threshold ||
|
||||
document.documentElement.scrollTop > btt_threshold
|
||||
) {
|
||||
top_button.classList.add("active");
|
||||
} else {
|
||||
top_button.classList.remove("active");
|
||||
) {
|
||||
top_button.classList.add("active");
|
||||
} else {
|
||||
top_button.classList.remove("active");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start();
|
||||
|
|
|
@ -1,44 +1,24 @@
|
|||
import "./main.js";
|
||||
|
||||
const bg = document.getElementById("background");
|
||||
bg.style.backgroundImage = `url(${bg.dataset.url})`;
|
||||
bg.removeAttribute("data-url");
|
||||
|
||||
const share_btn = document.getElementById("share");
|
||||
share_btn.onclick = (e) => {
|
||||
navigator.clipboard.writeText(window.location.href);
|
||||
share_btn.classList.remove('active');
|
||||
void share_btn.offsetWidth;
|
||||
share_btn.classList.add('active');
|
||||
}
|
||||
|
||||
const go_back_btn = document.getElementById("go-back")
|
||||
go_back_btn.innerText = "<";
|
||||
go_back_btn.addEventListener("click", () => {
|
||||
window.history.back();
|
||||
});
|
||||
|
||||
apply_funny_bob_to_upcoming_tags();
|
||||
|
||||
function apply_funny_bob_to_upcoming_tags() {
|
||||
const upcomingTags = document.querySelectorAll("#type.upcoming");
|
||||
for (var i = 0; i < upcomingTags.length; i++) {
|
||||
const tag = upcomingTags[i];
|
||||
const upcoming_tags = document.querySelectorAll("#type.upcoming");
|
||||
for (var i = 0; i < upcoming_tags.length; i++) {
|
||||
const tag = upcoming_tags[i];
|
||||
const chars = tag.innerText.split("");
|
||||
const result = chars.map((c, i) => `<span style="animation-delay: -${i * 100}ms;">${c}</span>`);
|
||||
tag.innerHTML = result.join("");
|
||||
}
|
||||
}
|
||||
|
||||
const extras_pairs = Array.from(document.querySelectorAll("div#info > div").values()).map(container => {
|
||||
return {
|
||||
container,
|
||||
button: document.getElementById("extras").querySelector(`ul li a[href="#${container.id}"]`)
|
||||
};
|
||||
});
|
||||
const info_container = document.getElementById("info")
|
||||
info_container.addEventListener("scroll", update_extras_buttons);
|
||||
function update_extras_buttons() {
|
||||
const extras_pairs = Array.from(document.querySelectorAll("div#info > div").values()).map(container => {
|
||||
return {
|
||||
container,
|
||||
button: document.getElementById("extras").querySelector(`ul li a[href="#${container.id}"]`)
|
||||
};
|
||||
});
|
||||
const info_container = document.getElementById("info")
|
||||
info_container.addEventListener("scroll", update_extras_buttons);
|
||||
const info_rect = info_container.getBoundingClientRect();
|
||||
const info_y = info_rect.y;
|
||||
const font_size = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
||||
|
@ -52,57 +32,38 @@ function update_extras_buttons() {
|
|||
if (scroll_diff <= 0) current = pair;
|
||||
})
|
||||
current.button.classList.add("active");
|
||||
}
|
||||
update_extras_buttons();
|
||||
|
||||
document.querySelectorAll("div#extras ul li a[href]").forEach(link => {
|
||||
link.addEventListener("click", event => {
|
||||
event.preventDefault();
|
||||
location.replace(link.href);
|
||||
document.querySelectorAll("div#extras ul li a[href]").forEach(link => {
|
||||
link.addEventListener("click", event => {
|
||||
event.preventDefault();
|
||||
location.replace(link.href);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* handling track previews (currently not implemented)
|
||||
|
||||
const previews = document.querySelectorAll("[id^=preview-]");
|
||||
for (const preview of previews) {
|
||||
preview.addEventListener("click", (e) => {
|
||||
if (e.target.classList.contains('playing')) {
|
||||
stopPreview(e.target);
|
||||
} else {
|
||||
playPreview(e.target);
|
||||
}
|
||||
function bind_go_back_btn() {
|
||||
const go_back_btn = document.getElementById("go-back")
|
||||
go_back_btn.innerText = "<";
|
||||
go_back_btn.addEventListener("click", () => {
|
||||
window.history.back();
|
||||
});
|
||||
preview.querySelector('audio').addEventListener("ended", () => { stopPreview(preview); });
|
||||
}
|
||||
|
||||
var stupidsounds = false;
|
||||
|
||||
function stopPreviews() {
|
||||
for (const preview of previews) stopPreview(preview);
|
||||
function bind_share_btn() {
|
||||
const share_btn = document.getElementById("share");
|
||||
share_btn.onclick = (e) => {
|
||||
navigator.clipboard.writeText(window.location.href);
|
||||
share_btn.classList.remove('active');
|
||||
void share_btn.offsetWidth;
|
||||
share_btn.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
function playPreview(preview) {
|
||||
if (!stupidsounds) stopPreviews();
|
||||
const btn = preview.querySelector('i');
|
||||
btn.classList.remove("play", "fa-play");
|
||||
btn.classList.add("pause", "fa-pause");
|
||||
const audio = preview.querySelector('audio');
|
||||
audio.play();
|
||||
preview.classList.add('playing');
|
||||
function start() {
|
||||
bind_share_btn();
|
||||
bind_go_back_btn();
|
||||
apply_funny_bob_to_upcoming_tags();
|
||||
update_extras_buttons();
|
||||
}
|
||||
|
||||
function stopPreview(preview) {
|
||||
const btn = preview.querySelector('i');
|
||||
btn.classList.remove("pause", "fa-pause");
|
||||
btn.classList.add("play", "fa-play");
|
||||
const audio = preview.querySelector('audio');
|
||||
audio.pause();
|
||||
audio.currentTime = 0;
|
||||
preview.classList.remove('playing');
|
||||
}
|
||||
|
||||
stopPreviews();
|
||||
|
||||
*/
|
||||
start();
|
||||
|
|
53
public/script/swap.js
Normal file
53
public/script/swap.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
async function swap(url) {
|
||||
const res = await fetch(url);
|
||||
|
||||
if (res.status !== 200) return;
|
||||
if (!res.headers.get("content-type").startsWith("text/html")) return;
|
||||
|
||||
const text = await res.text();
|
||||
const content = new DOMParser().parseFromString(text, "text/html");
|
||||
|
||||
const stylesheets = [...content.querySelectorAll("link[rel='stylesheet']")];
|
||||
|
||||
// swap title
|
||||
document.title = content.title;
|
||||
// swap body html
|
||||
document.body.innerHTML = content.body.innerHTML;
|
||||
// swap head html
|
||||
document.head.innerHTML = content.head.innerHTML;
|
||||
// swap stylesheets
|
||||
// const old_sheets = document.head.querySelectorAll("link[rel='stylesheet']");
|
||||
// stylesheets.forEach(stylesheet => { document.head.appendChild(stylesheet) });
|
||||
// old_sheets.forEach(stylesheet => { stylesheet.remove(); });
|
||||
// push history
|
||||
window.history.pushState({}, "", url);
|
||||
|
||||
bind(document.body);
|
||||
}
|
||||
|
||||
function bind(content) {
|
||||
if (typeof(content) !== 'object' || content.nodeType !== Node.ELEMENT_NODE) return;
|
||||
|
||||
content.querySelectorAll("a[href]").forEach(element => {
|
||||
if (element.href.includes("#")) return;
|
||||
if (!element.href.startsWith(window.location.origin)) return;
|
||||
const href = element.href.substring(window.location.origin.length);
|
||||
if (href.includes(".")) return;
|
||||
|
||||
element.addEventListener("click", event => {
|
||||
event.preventDefault();
|
||||
swap(element.href);
|
||||
})
|
||||
});
|
||||
|
||||
content.querySelectorAll("[swap-url]").forEach(element => {
|
||||
const href = element.attributes.getNamedItem('swap-url').value;
|
||||
|
||||
element.addEventListener("click", event => {
|
||||
event.preventDefault();
|
||||
swap(href);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bind(document.body);
|
Loading…
Add table
Add a link
Reference in a new issue