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 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}); }