Files
pyrom/data/static/js/ui.js

236 lines
7.4 KiB
JavaScript

function openLightbox(post, idx) {
lightboxCurrentPost = post;
lightboxCurrentIdx = idx;
lightboxObj.img.src = lightboxImages.get(post)[idx].src;
lightboxObj.openOriginalAnchor.href = lightboxImages.get(post)[idx].src
lightboxObj.prevButton.disabled = lightboxImages.get(post).length === 1
lightboxObj.nextButton.disabled = lightboxImages.get(post).length === 1
lightboxObj.imageCount.textContent = `Image ${idx + 1} of ${lightboxImages.get(post).length}`
if (!lightboxObj.dialog.open) {
lightboxObj.dialog.showModal();
}
}
const modulo = (n, m) => ((n % m) + m) % m
function lightboxNext() {
const l = lightboxImages.get(lightboxCurrentPost).length;
const target = modulo(lightboxCurrentIdx + 1, l);
openLightbox(lightboxCurrentPost, target);
}
function lightboxPrev() {
const l = lightboxImages.get(lightboxCurrentPost).length;
const target = modulo(lightboxCurrentIdx - 1, l);
openLightbox(lightboxCurrentPost, target);
}
function constructLightbox() {
const dialog = document.createElement("dialog");
dialog.classList.add("lightbox-dialog");
dialog.addEventListener("click", (e) => {
if (e.target === dialog) {
dialog.close();
}
})
const dialogInner = document.createElement("div");
dialogInner.classList.add("lightbox-inner");
dialog.appendChild(dialogInner);
const img = document.createElement("img");
img.classList.add("lightbox-image")
dialogInner.appendChild(img);
const openOriginalAnchor = document.createElement("a")
openOriginalAnchor.text = "Open original in new window"
openOriginalAnchor.target = "_blank"
openOriginalAnchor.rel = "noopener noreferrer nofollow"
dialogInner.appendChild(openOriginalAnchor);
const navSpan = document.createElement("span");
navSpan.classList.add("lightbox-nav");
const prevButton = document.createElement("button");
prevButton.type = "button";
prevButton.textContent = "Previous";
prevButton.addEventListener("click", lightboxPrev);
const nextButton = document.createElement("button");
nextButton.type = "button";
nextButton.textContent = "Next";
nextButton.addEventListener("click", lightboxNext);
const imageCount = document.createElement("span");
imageCount.textContent = "Image of ";
navSpan.appendChild(prevButton);
navSpan.appendChild(imageCount);
navSpan.appendChild(nextButton);
dialogInner.appendChild(navSpan);
return {
img: img,
dialog: dialog,
openOriginalAnchor: openOriginalAnchor,
prevButton: prevButton,
nextButton: nextButton,
imageCount: imageCount,
}
}
let lightboxImages = new Map(); //.post-inner : Array<Object>
let lightboxObj = null;
let lightboxCurrentPost = null;
let lightboxCurrentIdx = -1;
document.addEventListener("DOMContentLoaded", () => {
//lightboxes
lightboxObj = constructLightbox();
document.body.appendChild(lightboxObj.dialog);
function setImageMaxSize(img) {
const {
maxWidth: origMaxWidth,
maxHeight: origMaxHeight,
minWidth: origMinWidth,
minHeight: origMinHeight,
} = getComputedStyle(img);
if (img.naturalWidth < parseInt(origMinWidth)) {
img.style.minWidth = img.naturalWidth + "px";
}
if (img.naturalHeight < parseInt(origMinHeight)) {
img.style.minHeight = img.naturalHeight + "px";
}
if (img.naturalWidth < parseInt(origMaxWidth)) {
img.style.maxWidth = img.naturalWidth + "px";
}
if (img.naturalHeight < parseInt(origMaxHeight)) {
img.style.maxHeight = img.naturalHeight + "px";
}
}
const postImages = document.querySelectorAll(".post-inner img.post-image");
postImages.forEach(postImage => {
const belongingTo = postImage.closest(".post-inner");
const images = lightboxImages.get(belongingTo) ?? [];
images.push({
src: postImage.src,
alt: postImage.alt,
});
const idx = images.length - 1;
lightboxImages.set(belongingTo, images);
postImage.style.cursor = "pointer";
postImage.addEventListener("click", () => {
openLightbox(belongingTo, idx);
});
});
const postAndSigImages = document.querySelectorAll("img.post-image");
postAndSigImages.forEach(image => {
if (image.complete) {
setImageMaxSize(image);
} else {
image.addEventListener("load", () => setImageMaxSize(image));
}
})
});
{
function isBefore(el1, el2) {
if (el2.parentNode === el1.parentNode) {
for (let cur = el1.previousSibling; cur; cur = cur.previousSibling) {
if (cur === el2) return true;
}
}
return false;
}
let draggedItem = null;
function sortableItemDragStart(e, item) {
const box = item.getBoundingClientRect();
const oX = e.clientX - box.left;
const oY = e.clientY - box.top;
draggedItem = item;
item.classList.add('dragged');
e.dataTransfer.setDragImage(item, oX, oY);
e.dataTransfer.effectAllowed = 'move';
}
function sortableItemDragEnd(e, item) {
draggedItem = null;
item.classList.remove('dragged');
}
function sortableItemDragOver(e, item) {
const target = e.target.closest('.sortable-item');
if (!target || target === draggedItem) {
return;
}
const inSameList = draggedItem.dataset.sortableListKey === target.dataset.sortableListKey;
if (!inSameList) {
return;
}
const targetList = draggedItem.closest('.sortable-list');
if (isBefore(draggedItem, target)) {
targetList.insertBefore(draggedItem, target);
} else {
targetList.insertBefore(draggedItem, target.nextSibling);
}
}
const listItemsHandled = new Map();
const getListItemsHandled = (list) => {
return listItemsHandled.get(list) || new Set();
}
function registerSortableList(list) {
list.querySelectorAll('li:not(.immovable)').forEach(item => {
const listItems = getListItemsHandled(list);
listItems.add(item);
listItemsHandled.set(list, listItems);
const dragger = item.querySelector('.dragger');
dragger.addEventListener('dragstart', e => {sortableItemDragStart(e, item)});
dragger.addEventListener('dragend', e => {sortableItemDragEnd(e, item)});
item.addEventListener('dragover', e => {sortableItemDragOver(e, item)});
});
const obs = new MutationObserver(records => {
for (const mutation of records) {
mutation.addedNodes.forEach(node => {
if (!(node instanceof HTMLElement)) {
return;
}
if (!node.classList.contains('sortable-item')) {
return;
}
const listItems = getListItemsHandled(list)
if (listItems.has(node)) {
return;
}
const dragger = node.querySelector('.dragger');
dragger.addEventListener('dragstart', e => {sortableItemDragStart(e, node)});
dragger.addEventListener('dragend', e => {sortableItemDragEnd(e, node)});
node.addEventListener('dragover', e => {sortableItemDragOver(e, node)});
listItems.add(node);
listItemsHandled.set(list, listItems);
});
}
});
obs.observe(list, {childList: true});
}
document.querySelectorAll('.sortable-list').forEach(registerSortableList);
listsObs = new MutationObserver(records => {
for (const mutation of records) {
mutation.addedNodes.forEach(node => {
if (!(node instanceof HTMLElement)) {
return;
}
if (!node.classList.contains('sortable-list')) {
return;
}
registerSortableList(node);
})
}
})
listsObs.observe(document.body, {childList: true, subtree: true});
}