2020-02-21 12:35:19 +00:00
|
|
|
import {q, ElemJS} from "./elemjs/elemjs.js"
|
2020-02-26 07:12:48 +00:00
|
|
|
import {timeline} from "./post_series.js"
|
2020-02-21 12:35:19 +00:00
|
|
|
|
|
|
|
/** @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") {
|
2020-02-26 07:12:48 +00:00
|
|
|
console.log(event.state.shortcode, postOverlays.map(o => o.identifier))
|
|
|
|
/*if (postOverlays.length >= 2 && postOverlays.slice(-2)[0].identifier === event.state.shortcode) {
|
|
|
|
// continue down to actually pop please
|
|
|
|
} else {*/
|
|
|
|
return loadPostOverlay(event.state.shortcode, "none")
|
|
|
|
/*}*/
|
2020-02-21 12:35:19 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-26 07:12:48 +00:00
|
|
|
// 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()
|
|
|
|
}
|
|
|
|
})
|
2020-02-21 12:35:19 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
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 {
|
2020-02-26 07:12:48 +00:00
|
|
|
constructor(identifier) {
|
2020-02-21 12:35:19 +00:00
|
|
|
super("div")
|
2020-02-26 07:12:48 +00:00
|
|
|
this.identifier = identifier
|
|
|
|
this.loaded = false
|
|
|
|
this.available = true
|
|
|
|
this.keyboardListeners = []
|
|
|
|
|
2020-02-21 12:35:19 +00:00
|
|
|
this.class("post-overlay")
|
|
|
|
this.event("click", event => {
|
|
|
|
if (event.target === event.currentTarget) history.back()
|
|
|
|
})
|
|
|
|
setTimeout(() => {
|
|
|
|
if (!this.loaded) {
|
|
|
|
this.class("loading")
|
|
|
|
this.child(
|
|
|
|
new ElemJS("div").class("loading-inner").text("Loading...")
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}, 0)
|
|
|
|
}
|
|
|
|
|
2020-02-26 07:12:48 +00:00
|
|
|
addKeyboardCallback(callback) {
|
|
|
|
if (this.available) {
|
|
|
|
this.keyboardListeners.push(callback)
|
|
|
|
document.addEventListener("keydown", callback)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-21 12:35:19 +00:00
|
|
|
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
|
2020-02-26 07:12:48 +00:00
|
|
|
while (this.keyboardListeners.length) {
|
|
|
|
document.removeEventListener("keydown", this.keyboardListeners.shift())
|
|
|
|
}
|
2020-02-21 12:35:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-26 07:12:48 +00:00
|
|
|
const timelineElement = q("#timeline")
|
|
|
|
if (timelineElement) {
|
|
|
|
timelineElement.addEventListener("click", event => {
|
2020-02-21 12:35:19 +00:00
|
|
|
/** @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")
|
2020-02-26 07:12:48 +00:00
|
|
|
loadPostOverlay(shortcode, "push")
|
2020-02-21 12:35:19 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function fetchShortcodeFragment(shortcode) {
|
|
|
|
if (shortcodeDataMap.has(shortcode)) return Promise.resolve(shortcodeDataMap.get(shortcode))
|
|
|
|
else return fetch(`/fragment/post/${shortcode}`).then(res => res.json())
|
|
|
|
}
|
|
|
|
|
2020-02-26 07:12:48 +00:00
|
|
|
function loadPostOverlay(shortcode, stateChangeType) {
|
|
|
|
const overlay = new PostOverlay(shortcode)
|
2020-02-21 12:35:19 +00:00
|
|
|
document.body.appendChild(overlay.element)
|
|
|
|
pushOverlay(overlay)
|
2020-02-26 07:12:48 +00:00
|
|
|
if (stateChangeType === "push") {
|
|
|
|
history.pushState({view: "post_overlay", shortcode: shortcode}, "", `/p/${shortcode}`)
|
|
|
|
} else if (stateChangeType === "replace") {
|
|
|
|
history.replaceState({view: "post_overlay", shortcode: shortcode}, "", `/p/${shortcode}`)
|
|
|
|
} else if (stateChangeType !== "none") {
|
|
|
|
throw new Error("Unknown stateChangeType: "+stateChangeType)
|
|
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const fetcher = fetchShortcodeFragment(shortcode)
|
|
|
|
fetcher.then(root => {
|
|
|
|
shortcodeDataMap.set(shortcode, root)
|
2020-02-21 12:35:19 +00:00
|
|
|
if (overlay.available) {
|
2020-02-26 07:12:48 +00:00
|
|
|
const {title, html} = root
|
|
|
|
overlay.setContent(html)
|
|
|
|
if (overlay.available) {
|
|
|
|
document.title = title
|
|
|
|
}
|
|
|
|
while (postOverlays.length >= 2) postOverlays.shift().pop()
|
|
|
|
const entry = timeline.entries.get(shortcode)
|
|
|
|
let canInteractWithNavigation = true
|
|
|
|
overlay.element.querySelectorAll(".navigate-posts").forEach(button => {
|
|
|
|
button.addEventListener("click", async event => {
|
|
|
|
/** @type {HTMLButtonElement} */
|
|
|
|
//@ts-ignore
|
|
|
|
const button = event.currentTarget
|
|
|
|
if (button.classList.contains("next")) {
|
|
|
|
navigate("next")
|
|
|
|
} else {
|
|
|
|
navigate("previous")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
overlay.addKeyboardCallback(event => {
|
|
|
|
if (event.key === "ArrowRight") navigate("next")
|
|
|
|
else if (event.key === "ArrowLeft") navigate("previous")
|
|
|
|
})
|
|
|
|
async function navigate(direction) {
|
|
|
|
if (canInteractWithNavigation) {
|
|
|
|
/** @type {HTMLButtonElement} */
|
|
|
|
//@ts-ignore
|
|
|
|
if (direction === "next") {
|
|
|
|
canInteractWithNavigation = false
|
|
|
|
if (entry.isLastEntry()) await timeline.fetch()
|
|
|
|
if (!overlay.available) return
|
|
|
|
var futureShortcode = entry.getNextShortcode()
|
|
|
|
} else { // "previous"
|
|
|
|
if (entry.isFirstEntry()) return
|
|
|
|
canInteractWithNavigation = false
|
|
|
|
var futureShortcode = entry.getPreviousShortcode()
|
|
|
|
}
|
|
|
|
await loadPostOverlay(futureShortcode, "replace")
|
|
|
|
const newOverlay = postOverlays.slice(-1)[0]
|
|
|
|
if (newOverlay === overlay) { // was cancelled
|
|
|
|
canInteractWithNavigation = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-21 12:35:19 +00:00
|
|
|
}
|
2020-02-26 07:12:48 +00:00
|
|
|
resolve()
|
|
|
|
})
|
|
|
|
fetcher.catch(error => {
|
|
|
|
console.error(error)
|
|
|
|
overlay.showError()
|
|
|
|
reject(error)
|
|
|
|
})
|
2020-02-21 12:35:19 +00:00
|
|
|
})
|
|
|
|
}
|