a8862721cd
Static directory for public folders and business logic for the app within internal, split into domain specific folders to keep clear seperation of concerns.
121 lines
3.5 KiB
JavaScript
121 lines
3.5 KiB
JavaScript
function gridCellDimensions() {
|
|
const element = document.createElement("div");
|
|
element.style.position = "fixed";
|
|
element.style.height = "var(--line-height)";
|
|
element.style.width = "1ch";
|
|
document.body.appendChild(element);
|
|
const rect = element.getBoundingClientRect();
|
|
document.body.removeChild(element);
|
|
return { width: rect.width, height: rect.height };
|
|
}
|
|
|
|
// Add padding to each media to maintain grid.
|
|
function adjustMediaPadding() {
|
|
const cell = gridCellDimensions();
|
|
|
|
function setHeightFromRatio(media, ratio) {
|
|
const rect = media.getBoundingClientRect();
|
|
const realHeight = rect.width / ratio;
|
|
const diff = cell.height - (realHeight % cell.height);
|
|
media.style.setProperty("padding-bottom", `${diff}px`);
|
|
}
|
|
|
|
function setFallbackHeight(media) {
|
|
const rect = media.getBoundingClientRect();
|
|
const height = Math.round((rect.width / 2) / cell.height) * cell.height;
|
|
media.style.setProperty("height", `${height}px`);
|
|
}
|
|
|
|
function onMediaLoaded(media) {
|
|
var width, height;
|
|
switch (media.tagName) {
|
|
case "IMG":
|
|
width = media.naturalWidth;
|
|
height = media.naturalHeight;
|
|
break;
|
|
case "VIDEO":
|
|
width = media.videoWidth;
|
|
height = media.videoHeight;
|
|
break;
|
|
}
|
|
if (width > 0 && height > 0) {
|
|
setHeightFromRatio(media, width / height);
|
|
} else {
|
|
setFallbackHeight(media);
|
|
}
|
|
}
|
|
|
|
const medias = document.querySelectorAll("img, video");
|
|
for (media of medias) {
|
|
switch (media.tagName) {
|
|
case "IMG":
|
|
if (media.complete) {
|
|
onMediaLoaded(media);
|
|
} else {
|
|
media.addEventListener("load", () => onMediaLoaded(media));
|
|
media.addEventListener("error", function() {
|
|
setFallbackHeight(media);
|
|
});
|
|
}
|
|
break;
|
|
case "VIDEO":
|
|
switch (media.readyState) {
|
|
case HTMLMediaElement.HAVE_CURRENT_DATA:
|
|
case HTMLMediaElement.HAVE_FUTURE_DATA:
|
|
case HTMLMediaElement.HAVE_ENOUGH_DATA:
|
|
onMediaLoaded(media);
|
|
break;
|
|
default:
|
|
media.addEventListener("loadeddata", () => onMediaLoaded(media));
|
|
media.addEventListener("error", function() {
|
|
setFallbackHeight(media);
|
|
});
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
adjustMediaPadding();
|
|
window.addEventListener("load", adjustMediaPadding);
|
|
window.addEventListener("resize", adjustMediaPadding);
|
|
|
|
function checkOffsets() {
|
|
const ignoredTagNames = new Set([
|
|
"THEAD",
|
|
"TBODY",
|
|
"TFOOT",
|
|
"TR",
|
|
"TD",
|
|
"TH",
|
|
]);
|
|
const cell = gridCellDimensions();
|
|
const elements = document.querySelectorAll("body :not(.debug-grid, .debug-toggle)");
|
|
for (const element of elements) {
|
|
if (ignoredTagNames.has(element.tagName)) {
|
|
continue;
|
|
}
|
|
const rect = element.getBoundingClientRect();
|
|
if (rect.width === 0 && rect.height === 0) {
|
|
continue;
|
|
}
|
|
const top = rect.top + window.scrollY;
|
|
const left = rect.left + window.scrollX;
|
|
const offset = top % (cell.height / 2);
|
|
if(offset > 0) {
|
|
element.classList.add("off-grid");
|
|
console.error("Incorrect vertical offset for", element, "with remainder", top % cell.height, "when expecting divisible by", cell.height / 2);
|
|
} else {
|
|
element.classList.remove("off-grid");
|
|
}
|
|
}
|
|
}
|
|
|
|
const debugToggle = document.querySelector(".debug-toggle");
|
|
function onDebugToggle() {
|
|
document.body.classList.toggle("debug", debugToggle.checked);
|
|
}
|
|
debugToggle.addEventListener("change", onDebugToggle);
|
|
onDebugToggle();
|