Added the init.js file to make certain bits of JS run sooner than others.
The template_*.js files should get cached now. The phrase API results might get cached now. Solved an edge case in the attachment parser where a redirect is triggered on a HTTPS site when the attachment is posted as a HTTP URL. Fixed runHook in the JS files.
This commit is contained in:
parent
317ab8856b
commit
3fc2d6a867
|
@ -22,7 +22,10 @@
|
|||
},
|
||||
"globals": {
|
||||
"$": true,
|
||||
"session": true,
|
||||
"siteURL": true
|
||||
"addHook": true,
|
||||
"runHook": true,
|
||||
"addInitHook": true,
|
||||
"runInitHook": true,
|
||||
"loadScript": true
|
||||
}
|
||||
}
|
|
@ -758,7 +758,7 @@ func parseMediaBytes(data []byte) (media MediaEmbed, ok bool) {
|
|||
hostname = strings.Split(Site.URL, ":")[0]
|
||||
// ?- Test this as I'm not sure it'll do what it should. If someone's running SSL on port 80 or non-SSL on port 443 then... Well... They're in far worse trouble than this...
|
||||
port = Site.Port
|
||||
if scheme == "" && Site.EnableSsl {
|
||||
if Site.EnableSsl {
|
||||
scheme = "https"
|
||||
}
|
||||
}
|
||||
|
|
120
public/global.js
120
public/global.js
|
@ -1,32 +1,15 @@
|
|||
'use strict';
|
||||
var formVars = {};
|
||||
var tmplInits = {};
|
||||
var tmplPhrases = []; // [key] array of phrases indexed by order of use
|
||||
var phraseBox = {};
|
||||
var alertList = [];
|
||||
var alertCount = 0;
|
||||
var moreTopicCount = 0;
|
||||
var conn;
|
||||
var me = {};
|
||||
var selectedTopics = [];
|
||||
var attachItemCallback = function(){}
|
||||
var hooks = {
|
||||
"start_init": [],
|
||||
"end_init": [],
|
||||
};
|
||||
|
||||
// Topic move
|
||||
var forumToMoveTo = 0;
|
||||
|
||||
function runHook(name, ...args) {
|
||||
if(!(name in hooks)) return;
|
||||
|
||||
let hook = hooks[name];
|
||||
for (const callback in hook) {
|
||||
callback(...args);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Write a friendlier error handler which uses a .notice or something, we could have a specialised one for alerts
|
||||
function ajaxError(xhr,status,errstr) {
|
||||
console.log("The AJAX request failed");
|
||||
|
@ -193,6 +176,10 @@ function runWebSockets() {
|
|||
conn = new WebSocket("wss://" + document.location.host + "/ws/");
|
||||
} else conn = new WebSocket("ws://" + document.location.host + "/ws/");
|
||||
|
||||
conn.onerror = (err) => {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
conn.onopen = () => {
|
||||
console.log("The WebSockets connection was opened");
|
||||
conn.send("page " + document.location.pathname + '\r');
|
||||
|
@ -201,10 +188,12 @@ function runWebSockets() {
|
|||
Notification.requestPermission();
|
||||
}
|
||||
}
|
||||
|
||||
conn.onclose = () => {
|
||||
conn = false;
|
||||
console.log("The WebSockets connection was closed");
|
||||
}
|
||||
|
||||
conn.onmessage = (event) => {
|
||||
//console.log("WSMessage:", event.data);
|
||||
if(event.data[0] == "{") {
|
||||
|
@ -270,102 +259,29 @@ function runWebSockets() {
|
|||
}
|
||||
}
|
||||
|
||||
// Temporary hack for templates
|
||||
function len(item) {
|
||||
return item.length;
|
||||
}
|
||||
|
||||
function loadScript(name, callback) {
|
||||
let url = "/static/"+name
|
||||
$.getScript(url)
|
||||
.done(callback)
|
||||
.fail((e,xhr,settings,ex) => {
|
||||
console.log("Unable to get script '"+url+"'");
|
||||
console.log("e: ", e);
|
||||
console.log("xhr: ", xhr);
|
||||
console.log("settings: ", settings);
|
||||
console.log("ex: ",ex);
|
||||
console.trace();
|
||||
});
|
||||
}
|
||||
|
||||
function DoNothingButPassBack(item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
function fetchPhrases() {
|
||||
fetch("/api/phrases/?query=status,topic_list")
|
||||
.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];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
(() => {
|
||||
runHook("pre_iife");
|
||||
let loggedIn = document.head.querySelector("[property='x-loggedin']").content;
|
||||
|
||||
fetch("/api/me/")
|
||||
.then((resp) => resp.json())
|
||||
.then((data) => {
|
||||
console.log("loaded me endpoint data");
|
||||
console.log("data:",data);
|
||||
me = data;
|
||||
runHook("pre_init");
|
||||
|
||||
// We can only get away with this because template_alert has no phrases, otherwise it too would have to be part of the "dance", I miss Go concurrency :(
|
||||
loadScript("template_alert.js", () => {
|
||||
console.log("Loaded template_alert.js");
|
||||
addInitHook("pre_init", () => {
|
||||
// We can only get away with this because template_alert has no phrases, otherwise it too would have to be part of the "dance", I miss Go concurrency :(
|
||||
loadScript("template_alert.js", () => {
|
||||
console.log("Loaded template_alert.js");
|
||||
$(document).ready(() => {
|
||||
alertsInitted = true;
|
||||
var alertMenuList = document.getElementsByClassName("menu_alerts");
|
||||
for(var i = 0; i < alertMenuList.length; i++) {
|
||||
loadAlerts(alertMenuList[i]);
|
||||
}
|
||||
});
|
||||
|
||||
if(window["WebSocket"]) runWebSockets();
|
||||
else conn = false;
|
||||
|
||||
$(document).ready(mainInit);
|
||||
});
|
||||
|
||||
if(loggedIn) {
|
||||
let toLoad = 1;
|
||||
loadScript("template_topics_topic.js", () => {
|
||||
console.log("Loaded template_topics_topic.js");
|
||||
toLoad--;
|
||||
if(toLoad===0) fetchPhrases();
|
||||
});
|
||||
}
|
||||
if(window["WebSocket"]) runWebSockets();
|
||||
else conn = false;
|
||||
|
||||
$(document).ready(mainInit);
|
||||
});
|
||||
})();
|
||||
|
||||
function mainInit(){
|
||||
runHook("start_init");
|
||||
runInitHook("start_init");
|
||||
|
||||
$(".more_topics").click((event) => {
|
||||
event.preventDefault();
|
||||
|
@ -839,5 +755,5 @@ function mainInit(){
|
|||
})
|
||||
});
|
||||
|
||||
runHook("end_init");
|
||||
runInitHook("end_init");
|
||||
};
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
'use strict';
|
||||
|
||||
var me = {};
|
||||
var phraseBox = {};
|
||||
var tmplInits = {};
|
||||
var tmplPhrases = []; // [key] array of phrases indexed by order of use
|
||||
var hooks = {
|
||||
"pre_iffe": [],
|
||||
"pre_init": [],
|
||||
"start_init": [],
|
||||
"end_init": [],
|
||||
};
|
||||
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) {
|
||||
runHook(name);
|
||||
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;
|
||||
}
|
||||
|
||||
const asyncGetScript = (source) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let script = document.createElement('script');
|
||||
script.async = true;
|
||||
|
||||
const onloadHander = (haha, isAbort) => {
|
||||
if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
|
||||
script.onload = null;
|
||||
script.onreadystatechange = null;
|
||||
script = undefined;
|
||||
|
||||
isAbort ? reject(haha) : resolve();
|
||||
}
|
||||
}
|
||||
|
||||
script.onerror = (haha) => {
|
||||
reject(haha);
|
||||
};
|
||||
script.onload = onloadHander;
|
||||
script.onreadystatechange = onloadHander;
|
||||
script.src = source;
|
||||
|
||||
const prior = document.getElementsByTagName('script')[0];
|
||||
prior.parentNode.insertBefore(script, prior);
|
||||
});
|
||||
};
|
||||
|
||||
function loadScript(name, callback) {
|
||||
let url = "/static/"+name
|
||||
asyncGetScript(url)
|
||||
.then(callback)
|
||||
.catch((haha) => {
|
||||
console.log("Unable to get script '"+url+"'");
|
||||
console.log("haha: ", haha);
|
||||
console.trace();
|
||||
});
|
||||
}
|
||||
|
||||
function DoNothingButPassBack(item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
function fetchPhrases() {
|
||||
fetch("/api/phrases/?query=status,topic_list")
|
||||
.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("pre_iife");
|
||||
let loggedIn = document.head.querySelector("[property='x-loggedin']").content;
|
||||
|
||||
fetch("/api/me/")
|
||||
.then((resp) => resp.json())
|
||||
.then((data) => {
|
||||
console.log("loaded me endpoint data");
|
||||
console.log("data:",data);
|
||||
me = data;
|
||||
runInitHook("pre_init");
|
||||
});
|
||||
|
||||
if(loggedIn) {
|
||||
let toLoad = 1;
|
||||
loadScript("template_topics_topic.js", () => {
|
||||
console.log("Loaded template_topics_topic.js");
|
||||
toLoad--;
|
||||
if(toLoad===0) fetchPhrases();
|
||||
});
|
||||
}
|
||||
})();
|
|
@ -101,10 +101,17 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user common.User) common.R
|
|||
return nil
|
||||
}
|
||||
|
||||
// TODO: Remove this line after we move routeAPIPhrases to the routes package
|
||||
var cacheControlMaxAge = "max-age=" + strconv.Itoa(int(common.Day))
|
||||
|
||||
// TODO: Be careful with exposing the panel phrases here, maybe move them into a different namespace? We also need to educate the admin that phrases aren't necessarily secret
|
||||
// TODO: Move to the routes package
|
||||
func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
// TODO: Don't make this too JSON dependent so that we can swap in newer more efficient formats
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
h := w.Header()
|
||||
h.Set("Content-Type", "application/json")
|
||||
h.Set("Cache-Control", cacheControlMaxAge) //Cache-Control: max-age=31536000
|
||||
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
return common.PreErrorJS("Bad Form", w, r)
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
{{range .Header.Stylesheets}}
|
||||
<link href="/static/{{.}}" rel="stylesheet" type="text/css">
|
||||
{{end}}
|
||||
<meta property="x-loggedin" content="{{.CurrentUser.Loggedin}}" />
|
||||
<script type="text/javascript" src="/static/init.js"></script>
|
||||
<script type="text/javascript" src="/static/jquery-3.1.1.min.js"></script>
|
||||
<script type="text/javascript" src="/static/chartist/chartist.min.js"></script>
|
||||
{{range .Header.Scripts}}
|
||||
<script type="text/javascript" src="/static/{{.}}"></script>
|
||||
{{end}}
|
||||
<meta property="x-loggedin" content="{{.CurrentUser.Loggedin}}" />
|
||||
<script type="text/javascript" src="/static/global.js"></script>
|
||||
<meta name="viewport" content="width=device-width,initial-scale = 1.0, maximum-scale=1.0,user-scalable=no" />
|
||||
{{if .Header.MetaDesc}}<meta name="description" content="{{.Header.MetaDesc}}" />{{end}}
|
||||
|
|
Loading…
Reference in New Issue