Fix turbo nav for settings and stats pages.
Extract settings.js, preserve inline scripts from raw HTML (DOMParser strips them), and load trade config via JSON script tag. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+63
-35
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
(function () {
|
||||
var PERMANENT_CSS = ['/static/css/base.css', '/static/css/tech.css', '/static/css/responsive.css'];
|
||||
var CORE_SCRIPT_MARKERS = ['theme.js', 'symbol.js', 'page.js', 'nav.js', 'pwa.js', 'turbonav.js'];
|
||||
var CORE_SCRIPT_RE = /theme\.js|symbol\.js|page\.js|nav\.js|pwa\.js|turbonav\.js/;
|
||||
var pageCache = new Map();
|
||||
var MAX_CACHE = 10;
|
||||
var inflight = null;
|
||||
@@ -21,12 +21,6 @@
|
||||
return PERMANENT_CSS.some(function (p) { return href.indexOf(p) !== -1; });
|
||||
}
|
||||
|
||||
function isCoreScript(el) {
|
||||
var src = el.getAttribute('src') || '';
|
||||
if (!src) return false;
|
||||
return CORE_SCRIPT_MARKERS.some(function (m) { return src.indexOf(m) !== -1; });
|
||||
}
|
||||
|
||||
function shouldTurboClick(e, link) {
|
||||
if (!link || !link.href) return false;
|
||||
if (e.defaultPrevented) return false;
|
||||
@@ -55,13 +49,13 @@
|
||||
if (!res.ok) throw new Error('HTTP ' + res.status);
|
||||
return res.text();
|
||||
}).then(function (html) {
|
||||
var doc = parseHtml(html);
|
||||
pageCache.set(key, doc);
|
||||
var pack = { doc: parseHtml(html), html: html };
|
||||
pageCache.set(key, pack);
|
||||
if (pageCache.size > MAX_CACHE) {
|
||||
var first = pageCache.keys().next().value;
|
||||
pageCache.delete(first);
|
||||
}
|
||||
return doc;
|
||||
return pack;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,24 +78,42 @@
|
||||
return fetchedMain.innerHTML;
|
||||
}
|
||||
|
||||
function collectPageScripts(doc) {
|
||||
var out = [];
|
||||
var pastCore = false;
|
||||
doc.body.querySelectorAll(':scope > script').forEach(function (el) {
|
||||
if (isCoreScript(el)) {
|
||||
if ((el.getAttribute('src') || '').indexOf('pwa.js') !== -1) pastCore = true;
|
||||
return;
|
||||
/** DOMParser strips inline script bodies — parse from raw HTML instead. */
|
||||
function collectPageScripts(rawHtml) {
|
||||
var scripts = [];
|
||||
var bodyMatch = /<body[\s\S]*?>([\s\S]*)<\/body>/i.exec(rawHtml);
|
||||
if (!bodyMatch) return scripts;
|
||||
var body = bodyMatch[1];
|
||||
var re = /<script(\s[^>]*)?>([\s\S]*?)<\/script>/gi;
|
||||
var pastPwa = false;
|
||||
var m;
|
||||
while ((m = re.exec(body)) !== null) {
|
||||
var attrs = m[1] || '';
|
||||
var text = m[2];
|
||||
var srcMatch = /\ssrc=["']([^"']+)["']/i.exec(attrs);
|
||||
var typeMatch = /\stype=["']([^"']+)["']/i.exec(attrs);
|
||||
var idMatch = /\sid=["']([^"']+)["']/i.exec(attrs);
|
||||
var src = srcMatch ? srcMatch[1] : '';
|
||||
var type = typeMatch ? typeMatch[1].toLowerCase() : 'text/javascript';
|
||||
var id = idMatch ? idMatch[1] : '';
|
||||
if (src) {
|
||||
if (/pwa\.js/.test(src)) pastPwa = true;
|
||||
if (CORE_SCRIPT_RE.test(src)) continue;
|
||||
if (!pastPwa) continue;
|
||||
scripts.push({ src: src, text: '', type: type, id: id });
|
||||
continue;
|
||||
}
|
||||
if (!pastCore) return;
|
||||
if (isCoreScript(el)) return;
|
||||
out.push(el);
|
||||
});
|
||||
return out;
|
||||
if (!pastPwa) continue;
|
||||
scripts.push({ src: '', text: text, type: type, id: id });
|
||||
}
|
||||
return scripts;
|
||||
}
|
||||
|
||||
function removePageAssets() {
|
||||
document.querySelectorAll('[data-page-css]').forEach(function (el) { el.remove(); });
|
||||
document.querySelectorAll('body script[data-page-js]').forEach(function (el) { el.remove(); });
|
||||
document.querySelectorAll('body script[data-page-js], body script[data-page-data]').forEach(function (el) {
|
||||
el.remove();
|
||||
});
|
||||
}
|
||||
|
||||
function applyPageCss(items) {
|
||||
@@ -124,24 +136,37 @@
|
||||
}
|
||||
|
||||
function runPageScripts(items) {
|
||||
return items.reduce(function (chain, srcEl) {
|
||||
return items.reduce(function (chain, item) {
|
||||
return chain.then(function () {
|
||||
return new Promise(function (resolve) {
|
||||
var s = document.createElement('script');
|
||||
s.setAttribute('data-page-js', '');
|
||||
var src = srcEl.getAttribute('src');
|
||||
if (src) {
|
||||
var bust = (src.indexOf('?') >= 0 ? '&' : '?') + '_turbo=' + Date.now();
|
||||
s.src = src + bust;
|
||||
if (item.src) {
|
||||
s.setAttribute('data-page-js', '');
|
||||
var bust = (item.src.indexOf('?') >= 0 ? '&' : '?') + '_turbo=' + Date.now();
|
||||
s.src = item.src + bust;
|
||||
s.async = false;
|
||||
s.onload = function () { resolve(); };
|
||||
s.onerror = function () { resolve(); };
|
||||
document.body.appendChild(s);
|
||||
} else {
|
||||
s.textContent = srcEl.textContent;
|
||||
return;
|
||||
}
|
||||
if (item.type === 'application/json') {
|
||||
s.type = 'application/json';
|
||||
if (item.id) s.id = item.id;
|
||||
s.setAttribute('data-page-data', '');
|
||||
s.textContent = item.text;
|
||||
document.body.appendChild(s);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
if (item.type && item.type !== 'text/javascript' && item.type !== 'module') {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
s.setAttribute('data-page-js', '');
|
||||
s.textContent = item.text;
|
||||
document.body.appendChild(s);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}, Promise.resolve());
|
||||
@@ -166,7 +191,9 @@
|
||||
if (main) main.classList.toggle('nav-loading', on);
|
||||
}
|
||||
|
||||
function applyDocument(doc, url, fromPopstate) {
|
||||
function applyDocument(pack, url, fromPopstate) {
|
||||
var doc = pack.doc;
|
||||
var rawHtml = pack.html;
|
||||
var main = document.querySelector('.main');
|
||||
if (!main || !doc.querySelector('.main')) {
|
||||
window.location.href = url;
|
||||
@@ -178,12 +205,13 @@
|
||||
|
||||
var cssItems = collectPageCss(doc);
|
||||
var mainHtml = prepareMainHtml(doc);
|
||||
var scriptItems = collectPageScripts(rawHtml);
|
||||
|
||||
return applyPageCss(cssItems).then(function () {
|
||||
main.innerHTML = mainHtml;
|
||||
document.title = doc.title || document.title;
|
||||
syncNavActive(doc, url);
|
||||
return runPageScripts(collectPageScripts(doc));
|
||||
return runPageScripts(scriptItems);
|
||||
}).then(function () {
|
||||
currentUrl = normalizeUrl(url);
|
||||
if (!fromPopstate) {
|
||||
@@ -205,10 +233,10 @@
|
||||
inflight = ctrl;
|
||||
setLoading(true);
|
||||
|
||||
return fetchPage(target, ctrl.signal).then(function (doc) {
|
||||
return fetchPage(target, ctrl.signal).then(function (pack) {
|
||||
if (ctrl.signal.aborted) return;
|
||||
inflight = null;
|
||||
return applyDocument(doc, target, !!opts.fromPopstate);
|
||||
return applyDocument(pack, target, !!opts.fromPopstate);
|
||||
}).catch(function () {
|
||||
if (ctrl.signal.aborted) return;
|
||||
inflight = null;
|
||||
|
||||
Reference in New Issue
Block a user