cc1d0f089a
The client templates load earlier now for a smoother user experience. Added a setting for setting a Google Site Verification meta tag without editing header.html Added support for favicons. /static/favicon.ico will be mapped to favicon.ico, if it exists. The parent forum is now visible on the topics list for Nox. Language headers which contain the wildcard character are no longer considered unknowns. Meta descriptions and open graph descriptions are no longer emitted for logged in users. Slimmed down topics_topic slightly for Nox. Pre-parsed widgets are now minified. Stale WebSockets connections should be cleaned up far quicker now. Template generation is now logged separately. Commented out some obsolete template logic. Marked a few template generator fields as unexported. Fixed the styling for the ban page in the profile for Nox. Fixed the styling for colline for Cosora and Tempra Simple. Fixed the sidebar overflowing outside of the box on Nox. Fixed the meta description text overflowing the box in the Setting Manager on Nox. Fixed excessive padding in the Page Manager. Fixed a few missing border on the profiles for Tempra Simple. Fixed the sidebar appearing in places it shouldn't on Tempra Simple. Fixed the status code emitted by NotFoundJS Fixed a bug where Gosora kept falling back to interpreted templates. Fixed a bug where WebSockets connections weren't getting closed properly if the user cache overflowed. Fixed a bug where WebSocket connections weren't getting initialised for guests. Fixed a bug where template overrides weren't always getting applied. Fixed a bug where root template overrides weren't always getting applied. Added the google_site_verify setting. Added the google_site_verify phrase. You will need to run the patcher or updater for this commit.
231 lines
5.4 KiB
JavaScript
231 lines
5.4 KiB
JavaScript
'use strict';
|
|
|
|
var me = {};
|
|
var phraseBox = {};
|
|
if(tmplInits===undefined) var tmplInits = {};
|
|
var tmplPhrases = []; // [key] array of phrases indexed by order of use
|
|
var hooks = {
|
|
"pre_iffe": [],
|
|
"pre_init": [],
|
|
"start_init": [],
|
|
"end_init": [],
|
|
"after_phrases":[],
|
|
"after_add_alert":[],
|
|
"after_update_alert_list":[],
|
|
"open_edit":[],
|
|
"close_edit":[],
|
|
};
|
|
var ranInitHooks = {}
|
|
|
|
function runHook(name, ...args) {
|
|
if(!(name in hooks)) {
|
|
console.log("Couldn't find hook '" + name + "'");
|
|
return;
|
|
}
|
|
console.log("Running hook '"+name+"'");
|
|
|
|
let hook = hooks[name];
|
|
for (const index in hook) {
|
|
hook[index](...args);
|
|
}
|
|
}
|
|
|
|
function addHook(name, callback) {
|
|
hooks[name].push(callback);
|
|
}
|
|
|
|
// InitHooks are slightly special, as if they are run, then any adds after the initial run will run immediately, this is to deal with the async nature of script loads
|
|
function runInitHook(name, ...args) {
|
|
runHook(name,...args);
|
|
ranInitHooks[name] = true;
|
|
}
|
|
|
|
function addInitHook(name, callback) {
|
|
addHook(name, callback);
|
|
if(name in ranInitHooks) {
|
|
callback();
|
|
}
|
|
}
|
|
|
|
// Temporary hack for templates
|
|
function len(item) {
|
|
return item.length;
|
|
}
|
|
|
|
function asyncGetScript(source) {
|
|
return new Promise((resolve, reject) => {
|
|
let script = document.createElement('script');
|
|
script.async = true;
|
|
|
|
const onloadHandler = (e, isAbort) => {
|
|
if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
|
|
script.onload = null;
|
|
script.onreadystatechange = null;
|
|
script = undefined;
|
|
|
|
isAbort ? reject(e) : resolve();
|
|
}
|
|
}
|
|
|
|
script.onerror = (e) => {
|
|
reject(e);
|
|
};
|
|
script.onload = onloadHandler;
|
|
script.onreadystatechange = onloadHandler;
|
|
script.src = source;
|
|
|
|
const prior = document.getElementsByTagName('script')[0];
|
|
prior.parentNode.insertBefore(script, prior);
|
|
});
|
|
}
|
|
|
|
function notifyOnScript(source) {
|
|
return new Promise((resolve, reject) => {
|
|
let script = document.querySelectorAll('[src^="'+source+'"]')[0];
|
|
if(script===undefined) {
|
|
reject("no script found");
|
|
return;
|
|
}
|
|
if(!script.readyState) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
const onloadHandler = (e, isAbort) => {
|
|
if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
|
|
script.onload = null;
|
|
script.onreadystatechange = null;
|
|
isAbort ? reject(e) : resolve();
|
|
}
|
|
}
|
|
|
|
script.onerror = (e) => {
|
|
reject(e);
|
|
};
|
|
script.onload = onloadHandler;
|
|
script.onreadystatechange = onloadHandler;
|
|
script.src = source;
|
|
});
|
|
}
|
|
|
|
function notifyOnScriptW(name, complete, success) {
|
|
notifyOnScript(name)
|
|
.then(() => {
|
|
console.log("Loaded " +name+".js");
|
|
complete();
|
|
if(success!==undefined) success();
|
|
}).catch((e) => {
|
|
console.log("Unable to get script name '"+name+"'");
|
|
console.log("e: ", e);
|
|
console.trace();
|
|
complete();
|
|
});
|
|
}
|
|
|
|
// TODO: Send data at load time so we don't have to rely on a fallback template here
|
|
function loadScript(name, callback,fail) {
|
|
let fname = name;
|
|
let value = "; " + document.cookie;
|
|
let parts = value.split("; current_theme=");
|
|
if (parts.length == 2) fname += "_"+ parts.pop().split(";").shift();
|
|
|
|
let url = "/static/"+fname+".js"
|
|
let iurl = "/static/"+name+".js"
|
|
asyncGetScript(url)
|
|
.then(callback)
|
|
.catch((e) => {
|
|
console.log("Unable to get script '"+url+"'");
|
|
if(fname!=name) {
|
|
asyncGetScript(iurl)
|
|
.then(callback)
|
|
.catch((e) => {
|
|
console.log("Unable to get script '"+iurl+"'");
|
|
console.log("e: ", e);
|
|
console.trace();
|
|
});
|
|
}
|
|
console.log("e: ", e);
|
|
console.trace();
|
|
fail(e);
|
|
});
|
|
}
|
|
|
|
/*
|
|
function loadTmpl(name,callback) {
|
|
let url = "/static/"+name
|
|
let worker = new Worker(url);
|
|
}
|
|
*/
|
|
|
|
function DoNothingButPassBack(item) {
|
|
return item;
|
|
}
|
|
|
|
function RelativeTime(date) {
|
|
return date;
|
|
}
|
|
|
|
function initPhrases() {
|
|
console.log("in initPhrases")
|
|
fetchPhrases("status,topic_list,alerts,paginator")
|
|
}
|
|
|
|
function fetchPhrases(plist) {
|
|
fetch("/api/phrases/?query="+plist)
|
|
.then((resp) => resp.json())
|
|
.then((data) => {
|
|
console.log("loaded phrase endpoint data");
|
|
console.log("data:",data);
|
|
Object.keys(tmplInits).forEach((key) => {
|
|
let phrases = [];
|
|
let tmplInit = tmplInits[key];
|
|
for(let phraseName of tmplInit) phrases.push(data[phraseName]);
|
|
console.log("Adding phrases");
|
|
console.log("key:",key);
|
|
console.log("phrases:",phrases);
|
|
tmplPhrases[key] = phrases;
|
|
});
|
|
|
|
let prefixes = {};
|
|
Object.keys(data).forEach((key) => {
|
|
let prefix = key.split(".")[0];
|
|
if(prefixes[prefix]===undefined) prefixes[prefix] = {};
|
|
prefixes[prefix][key] = data[key];
|
|
});
|
|
Object.keys(prefixes).forEach((prefix) => {
|
|
console.log("adding phrase prefix '"+prefix+"' to box");
|
|
phraseBox[prefix] = prefixes[prefix];
|
|
});
|
|
|
|
runInitHook("after_phrases");
|
|
});
|
|
}
|
|
|
|
(() => {
|
|
runInitHook("pre_iife");
|
|
let toLoad = 2;
|
|
// TODO: Shunt this into loggedIn if there aren't any search and filter widgets?
|
|
notifyOnScriptW("/static/template_topics_topic", () => {
|
|
toLoad--;
|
|
if(toLoad===0) initPhrases();
|
|
});
|
|
notifyOnScriptW("/static/template_paginator", () => {
|
|
toLoad--;
|
|
if(toLoad===0) initPhrases();
|
|
});
|
|
|
|
let loggedIn = document.head.querySelector("[property='x-loggedin']").content;
|
|
if(loggedIn=="true") {
|
|
fetch("/api/me/")
|
|
.then((resp) => resp.json())
|
|
.then((data) => {
|
|
console.log("loaded me endpoint data");
|
|
console.log("data:",data);
|
|
me = data;
|
|
runInitHook("pre_init");
|
|
});
|
|
} else {
|
|
me = {User:{ID:0,Session:""},Site:{"MaxRequestSize":0}};
|
|
runInitHook("pre_init");
|
|
}
|
|
})(); |