diff --git a/common/files.go b/common/files.go index f192e2d9..468945ed 100644 --- a/common/files.go +++ b/common/files.go @@ -224,7 +224,7 @@ func (list SFileList) JSTmplInit() error { for name, _ := range Themes { if strings.HasSuffix(shortName, "_"+name) { - data = append(data, "\nlet Template_"+strings.TrimSuffix(shortName, "_"+name)+" = Template_"+shortName+";"...) + data = append(data, "\nvar Template_"+strings.TrimSuffix(shortName, "_"+name)+" = Template_"+shortName+";"...) break } } diff --git a/langs/english.json b/langs/english.json index b9593f14..09f11142 100644 --- a/langs/english.json +++ b/langs/english.json @@ -90,7 +90,7 @@ "id_must_be_integer": "The ID must be an integer.", "url_id_must_be_integer": "The ID in the URL needs to be a valid integer.", - "register_might_be_machine":"You might be a machine.", + "register_might_be_machine":"Our algorithms have detected that you may be a machine. If not, please try to avoid acting so quickly.", "register_need_username":"You didn't put in a username.", "register_need_email":"You didn't put in an email.", "register_first_word_numeric":"The first word of your name must not be purely numeric", @@ -709,6 +709,7 @@ "option_no":"No", "panel_menu_head":"Control Panel", + "panel_menu_aria":"The control panel menu", "panel_menu_users":"Users", "panel_menu_groups":"Groups", "panel_menu_forums":"Forums", diff --git a/public/global.js b/public/global.js index e8474753..f1f5949f 100644 --- a/public/global.js +++ b/public/global.js @@ -7,6 +7,7 @@ var moreTopicCount = 0; var conn = false; var selectedTopics = []; var attachItemCallback = function(){} +var baseTitle = document.title; // Topic move var forumToMoveTo = 0; @@ -17,9 +18,7 @@ function ajaxError(xhr,status,errstr) { console.log("xhr", xhr); console.log("status", status); console.log("errstr", errstr); - if(status=="parsererror") { - console.log("The server didn't respond with a valid JSON response"); - } + if(status=="parsererror") console.log("The server didn't respond with a valid JSON response"); console.trace(); } @@ -30,19 +29,28 @@ function postLink(event) { } function bindToAlerts() { + console.log("bindToAlerts"); $(".alertItem.withAvatar a").unbind("click"); $(".alertItem.withAvatar a").click(function(event) { event.stopPropagation(); - $.ajax({ url: "/api/?action=set&module=dismiss-alert", type: "POST", dataType: "json", error: ajaxError, data: { asid: $(this).attr("data-asid") } }); + event.preventDefault(); + $.ajax({ + url: "/api/?action=set&module=dismiss-alert", + type: "POST", + dataType: "json", + data: { asid: $(this).attr("data-asid") }, + error: ajaxError, + success: () => { + window.location.href = this.getAttribute("href"); + } + }); }); } function addAlert(msg, notice = false) { var mmsg = msg.msg; if("sub" in msg) { - for(var i = 0; i < msg.sub.length; i++) { - mmsg = mmsg.replace("\{"+i+"\}", msg.sub[i]); - } + for(var i = 0; i < msg.sub.length; i++) mmsg = mmsg.replace("\{"+i+"\}", msg.sub[i]); } let aItem = Template_alert({ @@ -51,7 +59,10 @@ function addAlert(msg, notice = false) { Avatar: msg.avatar || "", Message: mmsg }) - alertMapping[msg.asid] = aItem; + //alertMapping[msg.asid] = aItem; + let div = document.createElement('div'); + div.innerHTML = aItem.trim(); + alertMapping[msg.asid] = div.firstChild; alertList.push(msg.asid); if(notice) { @@ -74,21 +85,31 @@ function updateAlertList(menuAlerts) { let alertCounterNode = menuAlerts.getElementsByClassName("alert_counter")[0]; alertCounterNode.textContent = "0"; - let outList = ""; + alertListNode.innerHTML = ""; + let any = false; + /*let outList = ""; let j = 0; for(var i = 0; i < alertList.length && j < 8; i++) { outList += alertMapping[alertList[i]]; j++; + }*/ + let j = 0; + for(var i = 0; i < alertList.length && j < 8; i++) { + any = true; + alertListNode.appendChild(alertMapping[alertList[i]]); + //outList += alertMapping[alertList[i]]; + j++; } - - if(outList == "") outList = "
"+phraseBox["alerts"]["alerts.no_alerts"]+"
"; - alertListNode.innerHTML = outList; + if(!any) alertListNode.innerHTML = "
"+phraseBox["alerts"]["alerts.no_alerts"]+"
"; if(alertCount != 0) { alertCounterNode.textContent = alertCount; menuAlerts.classList.add("has_alerts"); + let nTitle = "("+alertCount+") "+baseTitle; + if(document.title!=nTitle) document.title = nTitle; } else { menuAlerts.classList.remove("has_alerts"); + if(document.title!=baseTitle) document.title = baseTitle; } bindToAlerts(); @@ -155,14 +176,20 @@ function SplitN(data,ch,n) { } function wsAlertEvent(data) { + console.log("wsAlertEvent:",data) addAlert(data, true); + alertCount++; - var alist = ""; - for (var i = 0; i < alertList.length; i++) alist += alertMapping[alertList[i]]; + let aTmp = alertList; + alertList = [alertList[alertList.length-1]]; + aTmp = aTmp.slice(0,-1); + for(let i = 0; i < aTmp.length; i++) alertList.push(aTmp[i]); + //var alist = ""; + //for (var i = 0; i < alertList.length; i++) alist += alertMapping[alertList[i]]; // TODO: Add support for other alert feeds like PM Alerts var generalAlerts = document.getElementById("general_alerts"); // TODO: Make sure we update alertCount here - updateAlertList(generalAlerts, alist); + updateAlertList(generalAlerts/*, alist*/); } function runWebSockets() { @@ -179,9 +206,7 @@ function runWebSockets() { console.log("The WebSockets connection was opened"); conn.send("page " + document.location.pathname + '\r'); // TODO: Don't ask again, if it's denied. We could have a setting in the UCP which automatically requests this when someone flips desktop notifications on - if(me.User.ID > 0) { - Notification.requestPermission(); - } + if(me.User.ID > 0) Notification.requestPermission(); } conn.onclose = () => { @@ -291,8 +316,13 @@ function runWebSockets() { (() => { addInitHook("pre_init", () => { + console.log("before notify on alert") // 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 :( - notifyOnScriptW("/static/template_alert", () => {}, () => { + notifyOnScriptW("template_alert", (e) => { + if(e!=undefined) console.log("failed alert? why?", e) + }, () => { + console.log("ha") + if(!Template_alert) throw("template function not found"); addInitHook("after_phrases", () => { // TODO: The load part of loadAlerts could be done asynchronously while the update of the DOM could be deferred $(document).ready(() => { @@ -438,10 +468,13 @@ function mainInit(){ // TODO: Try to de-duplicate some of these fetch calls fetch(url+q+"&js=1", {credentials: "same-origin"}) - .then((resp) => resp.json()) - .then((data) => { + .then((resp) => { + if(!resp.ok) throw(url+q+"&js=1 failed to load"); + return resp.json(); + }).then((data) => { if(!"Topics" in data) throw("no Topics in data"); let topics = data["Topics"]; + console.log("ajax navigated to different page"); // TODO: Fix the data race where the function hasn't been loaded yet let out = ""; @@ -470,10 +503,14 @@ function mainInit(){ let url = "//"+window.location.host+"/topics/?fids="+fid; fetch(url+"&js=1", {credentials: "same-origin"}) - .then((resp) => resp.json()) - .then((data) => { + .then((resp) => { + if(!resp.ok) throw(url+"&js=1 failed to load"); + return resp.json(); + }).then((data) => { + console.log("data:",data); if(!"Topics" in data) throw("no Topics in data"); let topics = data["Topics"]; + console.log("ajax navigated to "+that.innerText); // TODO: Fix the data race where the function hasn't been loaded yet let out = ""; @@ -481,6 +518,9 @@ function mainInit(){ $(".topic_list").html(out); //$(".topic_list").addClass("single_forum"); + baseTitle = that.innerText; + if(alertCount > 0) document.title = "("+alertCount+") "+baseTitle; + else document.title = baseTitle; let obj = {Title: document.title, Url: url}; history.pushState(obj, obj.Title, obj.Url); rebuildPaginator(data.LastPage) @@ -515,18 +555,23 @@ function mainInit(){ // TODO: Try to de-duplicate some of these fetch calls fetch(url+q+"&js=1", {credentials: "same-origin"}) - .then((resp) => resp.json()) - .then((data) => { + .then((resp) => { + if(!resp.ok) throw(url+q+"&js=1 failed to load"); + return resp.json(); + }).then((data) => { if(!"Topics" in data) throw("no Topics in data"); let topics = data["Topics"]; + console.log("ajax navigated to search page"); // TODO: Fix the data race where the function hasn't been loaded yet let out = ""; for(let i = 0; i < topics.length;i++) out += Template_topics_topic(topics[i]); $(".topic_list").html(out); - document.title = phraseBox["topic_list"]["topic_list.search_head"]; + baseTitle = phraseBox["topic_list"]["topic_list.search_head"]; $(".topic_list_title h1").text(phraseBox["topic_list"]["topic_list.search_head"]); + if(alertCount > 0) document.title = "("+alertCount+") "+baseTitle; + else document.title = baseTitle; let obj = {Title: document.title, Url: url+q}; history.pushState(obj, obj.Title, obj.Url); rebuildPaginator(data.LastPage); diff --git a/public/init.js b/public/init.js index 1c1e0d1e..5c50a79d 100644 --- a/public/init.js +++ b/public/init.js @@ -81,23 +81,30 @@ function asyncGetScript(source) { } function notifyOnScript(source) { + source = "/static/"+source; return new Promise((resolve, reject) => { + let ss = source.replace("/static/",""); + try { + let ssp = ss.charAt(0).toUpperCase() + ss.slice(1) + console.log("ssp:",ssp) + if(window[ssp]) { + resolve(); + return; + } + } catch(e) {} + + console.log("source:",source) let script = document.querySelectorAll('[src^="'+source+'"]')[0]; + console.log("script:",script); 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(); - } + const onloadHandler = (e) => { + script.onload = null; + script.onreadystatechange = null; + resolve(); } script.onerror = (e) => { @@ -105,7 +112,6 @@ function notifyOnScript(source) { }; script.onload = onloadHandler; script.onreadystatechange = onloadHandler; - script.src = source; }); } @@ -119,7 +125,7 @@ function notifyOnScriptW(name, complete, success) { console.log("Unable to get script name '"+name+"'"); console.log("e: ", e); console.trace(); - complete(); + complete(e); }); } @@ -168,6 +174,7 @@ function RelativeTime(date) { function initPhrases() { console.log("in initPhrases") + console.log("tmlInits:",tmplInits) fetchPhrases("status,topic_list,alerts,paginator,analytics") } @@ -206,11 +213,13 @@ function fetchPhrases(plist) { 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", () => { + notifyOnScriptW("template_topics_topic", () => { + if(!Template_topics_topic) throw("template function not found"); toLoad--; if(toLoad===0) initPhrases(); }); - notifyOnScriptW("/static/template_paginator", () => { + notifyOnScriptW("template_paginator", () => { + if(!Template_paginator) throw("template function not found"); toLoad--; if(toLoad===0) initPhrases(); }); diff --git a/routes.go b/routes.go index 629fd906..0f74669f 100644 --- a/routes.go +++ b/routes.go @@ -63,6 +63,7 @@ func routeAPI(w http.ResponseWriter, r *http.Request, user common.User) common.R if common.EnableWebsockets && count > 0 { _ = common.WsHub.PushMessage(user.ID, `{"event":"dismiss-alert","asid":`+strconv.Itoa(asid)+`}`) } + w.Write(successJSONBytes) // TODO: Split this into it's own function case "alerts": // A feed of events tailored for a specific user if !user.Loggedin { diff --git a/routes/account.go b/routes/account.go index a36a3732..78d0c392 100644 --- a/routes/account.go +++ b/routes/account.go @@ -778,8 +778,7 @@ func AccountPasswordReset(w http.ResponseWriter, r *http.Request, user common.Us header.AddNotice("password_reset_email_sent") } header.Title = phrases.GetTitlePhrase("password_reset") - pi := common.Page{header, tList, nil} - return renderTemplate("password_reset", w, r, header, pi) + return renderTemplate("password_reset", w, r, header, common.Page{header, tList, nil}) } // TODO: Ratelimit this diff --git a/templates/panel_group_edit.html b/templates/panel_group_edit.html index 2a25fc7d..205f50b9 100644 --- a/templates/panel_group_edit.html +++ b/templates/panel_group_edit.html @@ -1,16 +1,6 @@ {{template "header.html" . }}
- +{{template "panel_group_menu.html" . }}

{{.Name}}{{lang "panel_group_head_suffix"}}

diff --git a/templates/panel_group_edit_perms.html b/templates/panel_group_edit_perms.html index 93390594..c479d0e3 100644 --- a/templates/panel_group_edit_perms.html +++ b/templates/panel_group_edit_perms.html @@ -1,16 +1,6 @@ {{template "header.html" . }}
- +{{template "panel_group_menu.html" . }}

{{.Name}}{{lang "panel_group_head_suffix"}}

diff --git a/templates/panel_group_menu.html b/templates/panel_group_menu.html new file mode 100644 index 00000000..6794ebd4 --- /dev/null +++ b/templates/panel_group_menu.html @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/templates/panel_menu.html b/templates/panel_menu.html index d0bc677d..dd39062a 100644 --- a/templates/panel_menu.html +++ b/templates/panel_menu.html @@ -1 +1 @@ - + diff --git a/themes/nox/overrides/panel_group_menu.html b/themes/nox/overrides/panel_group_menu.html new file mode 100644 index 00000000..98be77e0 --- /dev/null +++ b/themes/nox/overrides/panel_group_menu.html @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/themes/nox/overrides/panel_inner_menu.html b/themes/nox/overrides/panel_inner_menu.html new file mode 100644 index 00000000..bdc5d943 --- /dev/null +++ b/themes/nox/overrides/panel_inner_menu.html @@ -0,0 +1,91 @@ + + + + + +
+ {{if .CurrentUser.Perms.ManagePlugins}}{{end}} + {{if .CurrentUser.IsSuperAdmin}}{{end}} + {{if .CurrentUser.IsAdmin}}{{end}} +
diff --git a/themes/nox/overrides/panel_menu.html b/themes/nox/overrides/panel_menu.html new file mode 100644 index 00000000..09fb2b3d --- /dev/null +++ b/themes/nox/overrides/panel_menu.html @@ -0,0 +1,5 @@ + diff --git a/themes/nox/public/panel.css b/themes/nox/public/panel.css index 176d1235..3d143b4c 100644 --- a/themes/nox/public/panel.css +++ b/themes/nox/public/panel.css @@ -24,6 +24,9 @@ .menu_stats { margin-left: 4px; } +.back_to_site { + font-size: 18px; +} .colstack_right { background-color: #333333;