Refactor jsonp js for cuteness

This commit is contained in:
Cadence Ember 2025-11-05 16:35:17 +13:00
parent 048709b2d1
commit 1dd90f5a7d
5 changed files with 106 additions and 44 deletions

View file

@ -163,11 +163,13 @@
#:head-data [head-data-in #f] #:head-data [head-data-in #f]
#:siteinfo [siteinfo-in #f] #:siteinfo [siteinfo-in #f]
#:user-cookies [user-cookies-in #f] #:user-cookies [user-cookies-in #f]
#:online-styles [online-styles #t]) #:online-styles [online-styles #t]
#:path [path-in #f])
(define siteinfo (or siteinfo-in siteinfo-default)) (define siteinfo (or siteinfo-in siteinfo-default))
(define head-data (or head-data-in ((head-data-getter wikiname)))) (define head-data (or head-data-in ((head-data-getter wikiname))))
(define user-cookies (or user-cookies-in (user-cookies-getter req))) (define user-cookies (or user-cookies-in (user-cookies-getter req)))
(define origin (format "https://~a.fandom.com" wikiname)) (define origin (format "https://~a.fandom.com" wikiname))
(define path (or path-in ""))
(define required-styles (define required-styles
(cond (cond
[online-styles [online-styles
@ -197,7 +199,8 @@
(link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "main.css")))) (link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "main.css"))))
(script "const BWData = " (script "const BWData = "
,(jsexpr->string (hasheq 'wikiname wikiname ,(jsexpr->string (hasheq 'wikiname wikiname
'strict_proxy (config-true? 'strict_proxy)))) 'strict_proxy (config-true? 'strict_proxy)
'path path)))
,(if (config-true? 'feature_search_suggestions) ,(if (config-true? 'feature_search_suggestions)
`(script (@ (type "module") (src ,(get-static-url "search-suggestions.js")))) `(script (@ (type "module") (src ,(get-static-url "search-suggestions.js"))))
"") "")

View file

@ -92,7 +92,7 @@
(link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "internal.css")))) (link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "internal.css"))))
(link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "main.css")))) (link (@ (rel "stylesheet") (type "text/css") (href ,(get-static-url "main.css"))))
(link (@ (rel "icon") (href ,(head-data^-icon-url head-data-default)))) (link (@ (rel "icon") (href ,(head-data^-icon-url head-data-default))))
(script (@ (defer) (src "/static/captcha.js"))) (script (@ (defer) (src ,(get-static-url "captcha.js"))))
(body (@ (class "skin-fandomdesktop theme-fandomdesktop-light internal")) (body (@ (class "skin-fandomdesktop theme-fandomdesktop-light internal"))
(div (@ (class "main-container")) (div (@ (class "main-container"))
(div (@ (class "fandom-community-header__background tileBoth header"))) (div (@ (class "fandom-community-header__background tileBoth header")))

View file

@ -30,7 +30,7 @@
("prop" . "text|headhtml|langlinks") ("prop" . "text|headhtml|langlinks")
("formatversion" . "2") ("formatversion" . "2")
("format" . "json") ("format" . "json")
("callback" . "wikiPageCallback"))))) ("callback" . "proxy.wikipage")))))
(define siteinfo-script-url (define siteinfo-script-url
(format "https://~a.fandom.com/api.php?~a" (format "https://~a.fandom.com/api.php?~a"
wikiname wikiname
@ -39,27 +39,29 @@
("siprop" . "general|rightsinfo") ("siprop" . "general|rightsinfo")
("format" . "json") ("format" . "json")
("formatversion" . "2") ("formatversion" . "2")
("callback" . "siteinfoCallback"))))) ("callback" . "proxy.siteinfo")))))
(define body (define body
(generate-wiki-page (generate-wiki-page
`(div `(div
(noscript "You have to enable JavaScript to load wiki pages. Sorry!") (noscript "You have to enable JavaScript to load wiki pages. Sorry!")
(div (@ (id "loading"))) (div (@ (id "loading")))
(progress (@ (id "progress") (style "margin-bottom: 50vh"))) (div (@ (id "progress-bar") (style "margin-bottom: 50vh"))
(script ,(format #<<END (progress))
var wikiname = ~v; (script #<<END
var path = ~v; var jsonpData = {}
var proxy = new Proxy(jsonpData, {get(obj, prop) { return value => obj[prop] = value }})
END END
wikiname path)) )
(script (@ (src ,(get-static-url "jsonp.js"))))
(script (@ (async) (src ,wiki-page-script-url))) (script (@ (async) (src ,wiki-page-script-url)))
(script (@ (async) (src ,siteinfo-script-url)))) (script (@ (async) (src ,siteinfo-script-url)))
(script (@ (type "module") (src ,(get-static-url "jsonp.js")))))
#:req req #:req req
#:source-url source-url #:source-url source-url
#:wikiname wikiname #:wikiname wikiname
#:title (url-segments->guess-title segments) #:title (url-segments->guess-title segments)
#:siteinfo siteinfo-default)) #:siteinfo siteinfo-default
#:path path))
(when (config-true? 'debug) (when (config-true? 'debug)
(xexp->html body)) (xexp->html body))
(response/output (response/output

View file

@ -97,9 +97,27 @@
(define (page-wiki-with-data req) (define (page-wiki-with-data req)
(response-handler (response-handler
(let/cc return
(define post-data/bytes (request-post-data/raw req)) (define post-data/bytes (request-post-data/raw req))
(when (not post-data/bytes) (when (not post-data/bytes)
(raise-user-error 'page-wiki-with-data "POST requests only, please.")) (return (response/jsexpr
#:code 400
#:headers always-headers
'#hasheq((error .
#hasheq((code . "breezewiki")
(info . "POST requests only, please.")))))))
(define origin-header
(or (headers-assq* #"origin" (request-headers/raw req))
(headers-assq* #"referer" (request-headers/raw req))))
(when (or (not origin-header) (not (string-prefix? (bytes->string/latin-1 (header-value origin-header)) (config-get 'canonical_origin))))
(return (response/jsexpr
#:code 400
#:headers always-headers
'#hasheq((error .
#hasheq((code . "breezewiki")
(info . "Origin/Referer header failed validation - cross-origin requests are not allowed here")))))))
(define post-data/string (bytes->string/utf-8 post-data/bytes)) (define post-data/string (bytes->string/utf-8 post-data/bytes))
(define post-data (string->jsexpr post-data/string)) (define post-data (string->jsexpr post-data/string))
(define wikiname (jp "/wikiname" post-data)) (define wikiname (jp "/wikiname" post-data))
@ -109,7 +127,7 @@
#:wikiname wikiname #:wikiname wikiname
#:source-url (format "https://~a.fandom.com/wiki/~a" wikiname path) #:source-url (format "https://~a.fandom.com/wiki/~a" wikiname path)
#:data (jp "/data" post-data) #:data (jp "/data" post-data)
#:siteinfo (data->siteinfo (jp "/siteinfo" post-data))))) #:siteinfo (data->siteinfo (jp "/siteinfo" post-data))))))
(define (take-json-rewrite-and-return-page #:req req #:wikiname wikiname #:source-url source-url #:data data #:siteinfo siteinfo) (define (take-json-rewrite-and-return-page #:req req #:wikiname wikiname #:source-url source-url #:data data #:siteinfo siteinfo)
(define title (jp "/parse/title" data "")) (define title (jp "/parse/title" data ""))

View file

@ -1,21 +1,40 @@
const loading = document.getElementById("loading") import {h, htm, render, signal, computed, effect} from "./preact.js"
loading.textContent = "Loading, please wait..." const html = htm.bind(h)
const progress = document.getElementById("progress")
let wikiPage = null // *** Loading indicator
function wikiPageCallback(data) {
wikiPage = data
cont()
}
let siteinfo = null render(html`Loading, please wait...`, document.getElementById("loading"))
function siteinfoCallback(data) {
siteinfo = data // *** Progress bar
const progress = signal(null)
const progressBar = document.getElementById("progress-bar")
while (progressBar.childNodes[0] !== undefined) progressBar.childNodes[0].remove() // clear out loading indicators
render(html`<progress value="${progress}" max="1"></progress>`, progressBar)
// *** Incoming data processing
// Handle case where data is immediately available
cont()
// Handle case where data may become available in the future
window.proxy = new Proxy(jsonpData, {
get(obj, prop) {
return value => {
obj[prop] = value
cont() cont()
} }
}
})
// *** Data upload and download
async function cont() { async function cont() {
if (!(wikiPage && siteinfo)) return if (jsonpData.wikipage?.error) return error(jsonpData.wikipage)
if (jsonpData.siteinfo?.error) return error(jsonpData.siteinfo)
if (!(jsonpData.wikipage && jsonpData.siteinfo)) return
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
@ -46,14 +65,34 @@ async function cont() {
document.head.appendChild(imported) document.head.appendChild(imported)
} }
} }
const redirectTo = document.querySelector("#content .redirectMsg a")
if (redirectTo) {
redirectTo.click()
}
}) })
xhr.open("POST", "/api/render/wiki") xhr.open("POST", "/api/render/wiki")
xhr.responseType = "document" xhr.responseType = "document"
xhr.send(JSON.stringify({ xhr.send(JSON.stringify({
data: wikiPage, data: jsonpData.wikipage,
siteinfo, siteinfo: jsonpData.siteinfo,
wikiname, wikiname: BWData.wikiname,
path path: BWData.path
})); }));
} }
function error(data) {
const eContent = document.getElementById("content")
while (eContent.childNodes[0] !== undefined) eContent.childNodes[0].remove() // clear out loading indicators
document.title = `Error | BreezeWiki`
render(html`
${data.error.code === "missingtitle"
? html`<p><strong>This page doesn't exist on Fandom.</strong></p>`
: html`
<p>BreezeWiki wasn't able to load this page.</p>
<p><strong>${data.error.code}: ${data.error.info}</strong></p>
`
}
<p><small><a href="/${BWData.wikiname}/wiki/Main_Page">Return to the homepage?</a></small></p>
`, eContent)
}