export const b = { init: 'activatePostImages getUserData', } const POST_IMAGES_SELECTOR = 'img.post-image:not(aside img.post-image)' const WHOAMI_ENDPOINT = '/api/whoami/' const THREAD_PERM_ENDPOINT = '/api/thread-permission/' const TOGGLE_REACTION_ENDPOINT = '/api/toggle-reaction/' const REPLACE_REACTIONS_ENDPOINT = '/hyperapi/reactions/' const getThreadId = () => { const scheme = window.location.pathname.split("/"); if (scheme[1] !== 'threads' || scheme[2] === 'new') { return -1; } return parseInt(scheme[2]); } let images = []; let currentIndex = 0; let currentUser = null; let reactionMenuState = {}; export function activatePostImages(_, __, ___) { const images = document.querySelectorAll(POST_IMAGES_SELECTOR); images.forEach(image => { image.style.cursor = 'pointer'; image.dataset.s = 'collectImages'; }); } export function collectImages(_, sender, el) { if (!el.contains(sender)) return; images = Array.from(el.querySelectorAll(POST_IMAGES_SELECTOR)); currentIndex = images.indexOf(sender); b.trigger('showLightbox'); } export function showLightbox(_, __, el) { const originalImg = images[currentIndex]; const lightboxImg = el.querySelector('img'); const anchor = el.querySelector('a'); anchor.href = originalImg.src; lightboxImg.src = originalImg.src; lightboxImg.alt = originalImg.alt; if (!el.open) { el.showModal(); } b.trigger('lightboxSetCounter'); } export function closeLightbox(_, __, el) { el.close(); } export function lightboxSetCounter(_, __, el) { el.innerText = `${currentIndex + 1}/${images.length}`; } export function lightboxNext(_, __, ___) { if (images.length == 1) return; currentIndex++; if (currentIndex >= images.length) { currentIndex = 0; } b.trigger('showLightbox'); } export function lightboxPrevious(_, __, ___) { if (images.length == 1) return; currentIndex--; if (currentIndex < 0) { currentIndex = images.length - 1; } b.trigger('showLightbox'); } export async function getUserData(_, __, ___) { currentUser = await b.getData(WHOAMI_ENDPOINT); b.trigger('highlightMentions'); const d = (await b.getData(`${THREAD_PERM_ENDPOINT}${getThreadId()}`)).can_post; if (d) { b.trigger('enableReactionMenuButton'); b.trigger('enableReactionButtons'); } else { b.trigger('disableReactionMenuButton'); } } export function highlightMentions(_, __, el) { if (!el) return; if (el.dataset.username === currentUser.username) { el.classList.add('me'); } } export function openReactionMenu(ev, sender, el) { if (!el) return; if (reactionMenuState.state === undefined) { el.addEventListener('toggle', e => { if (e.newState === 'closed') { reactionMenuState.state = 'closed'; } }); } if (reactionMenuState.state === 'open' && reactionMenuState.invoker === sender) { el.hidePopover(); return; } // TODO: [el, sender].prop(key) searches for ancestors with attr [data-${key}] if current element does not have `dataset[key]` but dataset transforms key names whereas css does not reactionMenuState.post = sender.prop('postid'); reactionMenuState.invoker = sender; reactionMenuState.state = 'open'; el.showPopover(); const bRect = sender.getBoundingClientRect(); const scrollY = window.scrollY; el.style.left = `${bRect.left}px`; el.style.top = `${bRect.bottom + scrollY}px`; } export function closeReactionMenu(_, __, el) { el.hidePopover(); } export async function toggleReaction(_, sender, __) { const emoji = sender.dataset.emoji; const post = sender.prop('postid') ? sender.prop('postid') : reactionMenuState.post; const res = await fetch(TOGGLE_REACTION_ENDPOINT, { method: 'POST', body: JSON.stringify({ reaction: emoji, post: post }), headers: { 'content-type': 'application/json', }, }); if (res.status !== 200) { return; } b.send({ postId: post }, 'replaceReactionButtons'); } export async function replaceReactionButtons(payload, __, el) { if (payload.postId !== el.prop('postid')) return; const res = await fetch(`${REPLACE_REACTIONS_ENDPOINT}${payload.postId}`); if (res.status !== 200) { return; } const body = await res.text(); const p = new DOMParser(); const e = p.parseFromString(body, 'text/html').body; el.replaceChildren(...e.children); el.childNodes.forEach(b => { if (!b instanceof HTMLButtonElement) return; b.disabled = false; }) } export function disableReactionMenuButton(_, __, el) { el.title = 'You do not have permission to add reactions to this post.'; } export function enableReactionMenuButton(_, __, el) { el.disabled = false; el.title = ''; } export function enableReactionButtons(_, __, el) { el.disabled = false; }