`
}
else if (e.type == "error") {
accum += e.content
}
else if (e.content != null ){
accum += pegAstToHtml(e.content)
}
else {
accum += e
}
return accum
},"")
return res
}
function makePreview(txt) {
//dbg(pegAstToHtml(bbcodePegParser.parse(txt)))
// Faster, but less dynamic
//let html = bbCodeParser.parse(txt)
// Slower, but more dynamic
let html = pegAstToHtml(bbcodePegParser.parse(txt))
let tmpl = document.createElement("div")
tmpl.innerHTML = html
return tmpl
}
function fastPreview(txt) {
// Faster, but less dynamic
// (not much faster either)
let html = bbCodeParser.parse(txt)
let tmpl = document.createElement("div")
tmpl.innerHTML = html
return tmpl
}
let previewDivTempl = document.createElement("div")
function createPreviewCallbacks() {
let forms = Object.values(document.querySelectorAll(".post_edit_form"))
forms = forms.concat( Object.values(document.querySelectorAll("#post_reply_form")))
forms = forms.concat( Object.values(document.querySelectorAll("#change_profile_form")))
forms.forEach((forum)=>{
// Try to make it side by side
//e.parentElement.parentElement.insertBefore(previewDiv,e.parentElement)
//e.parentElement.classList.add("sticky-top", "pt-5", "col-6")
let textarea = forum.querySelector("textarea")
let previewDiv = makePreview(textarea.value)
forum.parentElement.insertBefore(previewDiv,forum)
let curDisplayedVersion = 0
let nextVersion = 0
let updateTimeout
let updateTimeoutDelay = 50
let maxAcceptableDelay = 500
let useFallbackPreview = false
function UpdatePreview() {
// Measure load speed. Used for setting update delay dynamicly.
let startTime = Date.now()
// Create a preview buffer
let thisVersion = nextVersion++
let newPreview
if (useFallbackPreview) {
newPreview = fastPreview(textarea.value)
}
else {
newPreview = makePreview(textarea.value)
}
let imgLoadPromises = []
Object.values(newPreview.querySelectorAll("img")).forEach((img) => {
imgLoadPromises.push(new Promise(resolve => {
img.addEventListener('load', resolve)
// Errors dont really matter to us
img.addEventListener('error', resolve)
// Esure we are not already done
if (img.complete) {
resolve()
}
}))
})
// Wait for all images to load or error (size calculations needed) before we swap and rescroll
// This is the part that actualy updates the preview
Promise.all(imgLoadPromises).then(()=>{
let endTime = Date.now()
let updateLoadDelay = endTime - startTime
if (!useFallbackPreview && updateLoadDelay > maxAcceptableDelay) {
useFallbackPreview = true
dbg(`It took ${updateLoadDelay} milli to update. Max acceptable delay was ${maxAcceptableDelay}! Switching to fallback preview!`)
// We intentionally do not update the timout delay when we swap to fallback preview
}
else {
// average out the times
updateTimeoutDelay = (updateTimeoutDelay + updateLoadDelay) / 2
dbg(`It took ${updateLoadDelay} milli to update. Changing delay to ${updateTimeoutDelay} `)
}
// Return if we are older than cur preview
if (thisVersion < curDisplayedVersion) {
newPreview.remove()
return
}
curDisplayedVersion = thisVersion
// Remember scroll position
let old_height = $(document).height(); //store document height before modifications
let old_scroll = $(window).scrollTop(); //remember the scroll position
// Replace the Preview with the buffered content
previewDiv.parentElement.insertBefore(newPreview,previewDiv)
previewDiv.remove()
previewDiv=newPreview
// Scroll back to position
$(document).scrollTop(old_scroll + $(document).height() - old_height);
})
}
function UpdatePreviewProxy() {
dbg(`Reseting timeout with delay ${updateTimeoutDelay} `)
clearTimeout(updateTimeout)
updateTimeout = setTimeout(UpdatePreview,updateTimeoutDelay)
}
let buttons = Object.values(forum.querySelectorAll("button"))
buttons.forEach((btn)=>{
btn.addEventListener('click', UpdatePreviewProxy)
})
textarea.oninput = UpdatePreviewProxy
})
}
createPreviewCallbacks()