1
0
mirror of https://git.sr.ht/~cadence/bibliogram synced 2024-09-28 23:07:30 +00:00
bibliogram/src/site/html/static/js/post_overlay.js

126 lines
3.1 KiB
JavaScript
Raw Normal View History

2020-02-21 12:35:19 +00:00
import {q, ElemJS} from "./elemjs/elemjs.js"
/** @type {PostOverlay[]} */
const postOverlays = []
const titleHistory = []
titleHistory.push(document.title)
const shortcodeDataMap = new Map()
window.addEventListener("popstate", event => {
// console.log(event.state, postOverlays.length)
if (event.state) {
if (event.state.view === "post_overlay") {
loadPostOverlay(event.state.shortcode, false)
}
} else { // event.state === null which means back to originally loaded page, so pop overlay
setTimeout(() => { // make sure document is entirely loaded
if (titleHistory.length === 1) {
document.title = titleHistory[0]
} else if (titleHistory.length >= 2) {
titleHistory.pop()
document.title = titleHistory.slice(-1)[0]
}
if (postOverlays.length) {
popOverlay()
} else {
window.location.reload()
}
})
}
})
function pushOverlay(overlay) {
postOverlays.push(overlay)
document.body.style.overflowY = "hidden"
}
function popOverlay() {
const top = postOverlays.pop()
if (top) {
top.pop()
}
if (postOverlays.length === 0) document.body.style.overflowY = "auto"
}
class PostOverlay extends ElemJS {
constructor() {
super("div")
this.class("post-overlay")
this.event("click", event => {
if (event.target === event.currentTarget) history.back()
})
this.loaded = false
this.available = true
setTimeout(() => {
if (!this.loaded) {
this.class("loading")
this.child(
new ElemJS("div").class("loading-inner").text("Loading...")
)
}
}, 0)
}
setContent(html) {
this.html(html)
this.loaded = true
this.removeClass("loading")
}
showError() {
this.loaded = true
this.class("loading")
this.clearChildren()
this.child(
new ElemJS("div").class("loading-inner").text("Request failed.")
)
}
pop() {
this.element.remove()
this.available = false
}
}
const timeline = q("#timeline")
if (timeline) {
timeline.addEventListener("click", event => {
/** @type {HTMLElement[]} */
//@ts-ignore
const path = event.composedPath()
const postLink = path.find(element => element.classList && element.classList.contains("sized-link") && element.hasAttribute("data-shortcode"))
if (postLink) {
event.preventDefault()
const shortcode = postLink.getAttribute("data-shortcode")
loadPostOverlay(shortcode, true)
}
})
}
function fetchShortcodeFragment(shortcode) {
if (shortcodeDataMap.has(shortcode)) return Promise.resolve(shortcodeDataMap.get(shortcode))
else return fetch(`/fragment/post/${shortcode}`).then(res => res.json())
}
function loadPostOverlay(shortcode, shouldPushState) {
const overlay = new PostOverlay()
document.body.appendChild(overlay.element)
pushOverlay(overlay)
if (shouldPushState) history.pushState({view: "post_overlay", shortcode: shortcode}, "", `/p/${shortcode}`)
const fetcher = fetchShortcodeFragment(shortcode)
fetcher.then(root => {
shortcodeDataMap.set(shortcode, root)
if (overlay.available) {
const {title, html} = root
overlay.setContent(html)
if (overlay.available) {
document.title = title
}
}
})
fetcher.catch(error => {
console.error(error)
overlay.showError()
})
}