diff --git a/common/counters/langs.go b/common/counters/langs.go index 9f78ccbc..d2f6a384 100644 --- a/common/counters/langs.go +++ b/common/counters/langs.go @@ -96,12 +96,11 @@ var langCodes = []string{ type DefaultLangViewCounter struct { buckets []*RWMutexCounterBucket //[OSID]count codesToIndices map[string]int - insert *sql.Stmt + + insert *sql.Stmt } -func NewDefaultLangViewCounter() (*DefaultLangViewCounter, error) { - acc := qgen.NewAcc() - +func NewDefaultLangViewCounter(acc *qgen.Accumulator) (*DefaultLangViewCounter, error) { var langBuckets = make([]*RWMutexCounterBucket, len(langCodes)) for bucketID, _ := range langBuckets { langBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} diff --git a/common/counters/routes.go b/common/counters/routes.go index d60d2764..ac55aff8 100644 --- a/common/counters/routes.go +++ b/common/counters/routes.go @@ -12,8 +12,7 @@ type DefaultRouteViewCounter struct { insert *sql.Stmt } -func NewDefaultRouteViewCounter() (*DefaultRouteViewCounter, error) { - acc := qgen.NewAcc() +func NewDefaultRouteViewCounter(acc *qgen.Accumulator) (*DefaultRouteViewCounter, error) { var routeBuckets = make([]*RWMutexCounterBucket, len(routeMapEnum)) for bucketID, _ := range routeBuckets { routeBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} diff --git a/common/counters/systems.go b/common/counters/systems.go index 3f24367a..163dc0e9 100644 --- a/common/counters/systems.go +++ b/common/counters/systems.go @@ -14,8 +14,7 @@ type DefaultOSViewCounter struct { insert *sql.Stmt } -func NewDefaultOSViewCounter() (*DefaultOSViewCounter, error) { - acc := qgen.NewAcc() +func NewDefaultOSViewCounter(acc *qgen.Accumulator) (*DefaultOSViewCounter, error) { var osBuckets = make([]*RWMutexCounterBucket, len(osMapEnum)) for bucketID, _ := range osBuckets { osBuckets[bucketID] = &RWMutexCounterBucket{counter: 0} diff --git a/common/files.go b/common/files.go index 468945ed..a8ca909a 100644 --- a/common/files.go +++ b/common/files.go @@ -27,7 +27,7 @@ var staticFileMutex sync.RWMutex type SFile struct { Data []byte GzipData []byte - Sha256 []byte + Sha256 string Pos int64 Length int64 GzipLength int64 @@ -240,7 +240,7 @@ func (list SFileList) JSTmplInit() error { // Get a checksum for CSPs and cache busting hasher := sha256.New() hasher.Write(data) - checksum := []byte(hex.EncodeToString(hasher.Sum(nil))) + checksum := hex.EncodeToString(hasher.Sum(nil)) list.Set("/static/"+path, SFile{data, gzipData, checksum, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}) @@ -267,7 +267,7 @@ func (list SFileList) Init() error { // Get a checksum for CSPs and cache busting hasher := sha256.New() hasher.Write(data) - checksum := []byte(hex.EncodeToString(hasher.Sum(nil))) + checksum := hex.EncodeToString(hasher.Sum(nil)) // Avoid double-compressing images var gzipData []byte @@ -318,7 +318,7 @@ func (list SFileList) Add(path string, prefix string) error { // Get a checksum for CSPs and cache busting hasher := sha256.New() hasher.Write(data) - checksum := []byte(hex.EncodeToString(hasher.Sum(nil))) + checksum := hex.EncodeToString(hasher.Sum(nil)) list.Set("/static"+path, SFile{data, gzipData, checksum, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}) diff --git a/common/pages.go b/common/pages.go index 8303bd32..fe70a062 100644 --- a/common/pages.go +++ b/common/pages.go @@ -10,14 +10,20 @@ import ( "github.com/Azareal/Gosora/common/phrases" ) +type HResource struct { + Name string + Hash string +} + // TODO: Allow resources in spots other than /static/ and possibly even external domains (e.g. CDNs) // TODO: Preload Trumboyg on Cosora on the forum list type Header struct { Title string //Title []byte // Experimenting with []byte for increased efficiency, let's avoid converting too many things to []byte, as it involves a lot of extra boilerplate NoticeList []string - Scripts []string - PreScriptsAsync []string + Scripts []HResource + PreScriptsAsync []HResource + ScriptsAsync []HResource //Preload []string Stylesheets []string Widgets PageWidgets @@ -44,11 +50,41 @@ type Header struct { } func (header *Header) AddScript(name string) { - header.Scripts = append(header.Scripts, name) + fname := "/static/" + name + var hash string + if fname[0] == '/' && fname[1] != '/' { + file, ok := StaticFiles.Get(fname) + if ok { + hash = file.Sha256 + } + } + //log.Print("name:", name) + //log.Print("hash:", hash) + header.Scripts = append(header.Scripts, HResource{name, hash}) } func (header *Header) AddPreScriptAsync(name string) { - header.PreScriptsAsync = append(header.PreScriptsAsync, name) + fname := "/static/" + name + var hash string + if fname[0] == '/' && fname[1] != '/' { + file, ok := StaticFiles.Get(fname) + if ok { + hash = file.Sha256 + } + } + header.PreScriptsAsync = append(header.PreScriptsAsync, HResource{name, hash}) +} + +func (header *Header) AddScriptAsync(name string) { + fname := "/static/" + name + var hash string + if fname[0] == '/' && fname[1] != '/' { + file, ok := StaticFiles.Get(fname) + if ok { + hash = file.Sha256 + } + } + header.ScriptsAsync = append(header.ScriptsAsync, HResource{name, hash}) } /*func (header *Header) Preload(name string) { diff --git a/common/routes_common.go b/common/routes_common.go index f2946076..ca15db58 100644 --- a/common/routes_common.go +++ b/common/routes_common.go @@ -131,7 +131,11 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header if ext == "css" { header.AddSheet(resource.Name) } else if ext == "js" { - header.AddScript(resource.Name) + if resource.Async { + header.AddScriptAsync(resource.Name) + } else { + header.AddScript(resource.Name) + } } } } @@ -229,7 +233,11 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (header *Head if ext == "css" { header.AddSheet(resource.Name) } else if ext == "js" { - header.AddScript(resource.Name) + if resource.Async { + header.AddScriptAsync(resource.Name) + } else { + header.AddScript(resource.Name) + } } } } diff --git a/common/template_init.go b/common/template_init.go index 86a1e3d1..a99b0a12 100644 --- a/common/template_init.go +++ b/common/template_init.go @@ -109,8 +109,9 @@ func tmplInitHeaders(user User, user2 User, user3 User) (*Header, *Header, *Head CurrentUser: user, NoticeList: []string{"test"}, Stylesheets: []string{"panel.css"}, - Scripts: []string{"whatever.js"}, - PreScriptsAsync: []string{"whatever.js"}, + Scripts: []HResource{HResource{"whatever.js", "d"}}, + PreScriptsAsync: []HResource{HResource{"whatever.js", "d"}}, + ScriptsAsync: []HResource{HResource{"whatever.js", "d"}}, Widgets: PageWidgets{ LeftSidebar: template.HTML("lalala"), }, diff --git a/common/templates/templates.go b/common/templates/templates.go index c183e354..87fdc6c8 100644 --- a/common/templates/templates.go +++ b/common/templates/templates.go @@ -2,11 +2,13 @@ package tmpl import ( "bytes" + "fmt" "io/ioutil" "log" "os" "path/filepath" "reflect" + "runtime/debug" "strconv" "strings" "text/template/parse" @@ -70,7 +72,8 @@ type CTemplateSet struct { themeName string perThemeTmpls map[string]bool - logger *log.Logger + logger *log.Logger + loggerf *os.File } func NewCTemplateSet(in string) *CTemplateSet { @@ -110,7 +113,8 @@ func NewCTemplateSet(in string) *CTemplateSet { "dyntmpl": true, "index": true, }, - logger: log.New(f, "", log.LstdFlags), + logger: log.New(f, "", log.LstdFlags), + loggerf: f, } } @@ -155,6 +159,7 @@ func (c *CTemplateSet) ResetLogs(in string) { panic(err) } c.logger = log.New(f, "", log.LstdFlags) + c.loggerf = f } type SkipBlock struct { @@ -268,6 +273,19 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe } func (c *CTemplateSet) compile(name string, content string, expects string, expectsInt interface{}, varList map[string]VarItem, imports ...string) (out string, err error) { + defer func() { + r := recover() + if r != nil { + fmt.Println(r) + debug.PrintStack() + err := c.loggerf.Sync() + if err != nil { + fmt.Println(err) + } + log.Fatal("") + return + } + }() //c.dumpCall("compile", name, content, expects, expectsInt, varList, imports) //c.detailf("c: %+v\n", c) c.importMap = map[string]string{} @@ -1460,6 +1478,16 @@ func (c *CTemplateSet) compileVarSub(con CContext, varname string, val reflect.V c.addText(con, []byte("false")) con.Push("endelse", "}\n") return + case reflect.Slice: + if val.Len() == 0 { + c.critical("varname:", varname) + panic("The sample data needs at-least one or more elements for the slices. We're looking into removing this requirement at some point!") + } + item := val.Index(0) + if item.Type().Name() != "uint8" { // uint8 == byte, complicated because it's a type alias + panic("unable to format " + item.Type().Name() + " as text") + } + base = varname case reflect.String: if val.Type().Name() != "string" && !strings.HasPrefix(varname, "string(") { varname = "string(" + varname + ")" diff --git a/common/theme.go b/common/theme.go index 2e2cecba..626feeab 100644 --- a/common/theme.go +++ b/common/theme.go @@ -77,6 +77,7 @@ type ThemeResource struct { Name string Location string Loggedin bool // Only serve this resource to logged in users + Async bool } type ThemeMapTmplToDock struct { @@ -162,7 +163,7 @@ func (theme *Theme) AddThemeStaticFiles() error { // Get a checksum for CSPs and cache busting hasher := sha256.New() hasher.Write(data) - checksum := []byte(hex.EncodeToString(hasher.Sum(nil))) + checksum := hex.EncodeToString(hasher.Sum(nil)) StaticFiles.Set("/static/"+theme.Name+path, SFile{data, gzipData, checksum, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}) diff --git a/common/websockets.go b/common/websockets.go index 38adec05..1797941f 100644 --- a/common/websockets.go +++ b/common/websockets.go @@ -92,6 +92,12 @@ func RouteWebsockets(w http.ResponseWriter, r *http.Request, user User) RouteErr currentPage = string(msgblocks[1]) wsPageResponses(wsUser, conn, currentPage) } + } else if bytes.HasPrefix(msg, []byte("resume ")) { + msgblocks := bytes.SplitN(msg, []byte(" "), 2) + if len(msgblocks) < 2 { + continue + } + //log.Print("resuming on " + string(msgblocks[1])) } /*if bytes.Equal(message,[]byte(`start-view`)) { } else if bytes.Equal(message,[]byte(`end-view`)) { diff --git a/docs/configuration.md b/docs/configuration.md index cfbad8b4..bce91e23 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -84,7 +84,7 @@ MaxTopicTitleLength - The maximum length that a topic can be. Please note that t MaxUsernameLength - The maximum length that a user's name can be. Please note that this measures the number of bytes and may differ from language to language with it being equal to a letter in English and being two bytes in others. -ReadTimeout - The number of seconds that we are allowed to take to fully read a request. Defaults to 5. +ReadTimeout - The number of seconds that we are allowed to take to fully read a request. Defaults to 8. WriteTimeout - The number of seconds that a route is allowed to run for before the request is automatically terminated. Defaults to 10. diff --git a/gen_router.go b/gen_router.go index 231448fd..efd5b96e 100644 --- a/gen_router.go +++ b/gen_router.go @@ -164,6 +164,7 @@ var RouteMap = map[string]interface{}{ "routes.RobotsTxt": routes.RobotsTxt, "routes.SitemapXml": routes.SitemapXml, "routes.BadRoute": routes.BadRoute, + "routes.HTTPSRedirect": routes.HTTPSRedirect, } // ! NEVER RELY ON THESE REMAINING THE SAME BETWEEN COMMITS @@ -309,6 +310,7 @@ var routeMapEnum = map[string]int{ "routes.RobotsTxt": 138, "routes.SitemapXml": 139, "routes.BadRoute": 140, + "routes.HTTPSRedirect": 141, } var reverseRouteMapEnum = map[int]string{ 0: "routes.Overview", @@ -452,6 +454,7 @@ var reverseRouteMapEnum = map[int]string{ 138: "routes.RobotsTxt", 139: "routes.SitemapXml", 140: "routes.BadRoute", + 141: "routes.HTTPSRedirect", } var osMapEnum = map[string]int{ "unknown": 0, @@ -600,6 +603,17 @@ func (writ *WriterIntercept) WriteHeader(code int) { writ.ResponseWriter.WriteHeader(code) } +// HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS +type HTTPSRedirect struct { +} + +func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Connection", "close") + counters.RouteViewCounter.Bump(141) + dest := "https://" + req.Host + req.URL.String() + http.Redirect(w, req, dest, http.StatusTemporaryRedirect) +} + type GenRouter struct { UploadHandler func(http.ResponseWriter, *http.Request) extraRoutes map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError diff --git a/langs/english.json b/langs/english.json index 09f11142..941ce2d8 100644 --- a/langs/english.json +++ b/langs/english.json @@ -708,6 +708,8 @@ "option_yes":"Yes", "option_no":"No", + "panel_back_to_site":"Back to Site", + "panel_welcome":"Welcome ", "panel_menu_head":"Control Panel", "panel_menu_aria":"The control panel menu", "panel_menu_users":"Users", diff --git a/main.go b/main.go index e9047aad..de7e75ae 100644 --- a/main.go +++ b/main.go @@ -28,7 +28,6 @@ import ( "github.com/Azareal/Gosora/common/counters" "github.com/Azareal/Gosora/common/phrases" "github.com/Azareal/Gosora/query_gen" - "github.com/Azareal/Gosora/routes" "github.com/fsnotify/fsnotify" "github.com/pkg/errors" ) @@ -181,15 +180,15 @@ func afterDBInit() (err error) { if err != nil { return errors.WithStack(err) } - counters.OSViewCounter, err = counters.NewDefaultOSViewCounter() + counters.OSViewCounter, err = counters.NewDefaultOSViewCounter(acc) if err != nil { return errors.WithStack(err) } - counters.LangViewCounter, err = counters.NewDefaultLangViewCounter() + counters.LangViewCounter, err = counters.NewDefaultLangViewCounter(acc) if err != nil { return errors.WithStack(err) } - counters.RouteViewCounter, err = counters.NewDefaultRouteViewCounter() + counters.RouteViewCounter, err = counters.NewDefaultRouteViewCounter(acc) if err != nil { return errors.WithStack(err) } @@ -472,7 +471,7 @@ func startServer() { var newServer = func(addr string, handler http.Handler) *http.Server { rtime := common.Config.ReadTimeout if rtime == 0 { - rtime = 5 + rtime = 8 } else if rtime == -1 { rtime = 0 } @@ -527,7 +526,7 @@ func startServer() { // TODO: Redirect to port 443 go func() { log.Print("Listening on port 80") - common.StoppedServer(newServer(":80", &routes.HTTPSRedirect{}).ListenAndServe()) + common.StoppedServer(newServer(":80", &HTTPSRedirect{}).ListenAndServe()) }() } log.Printf("Listening on port %s", common.Site.Port) diff --git a/public/analytics.js b/public/analytics.js index cf738f72..a47a8a1a 100644 --- a/public/analytics.js +++ b/public/analytics.js @@ -59,4 +59,6 @@ function buildStatsChart(rawLabels, seriesData, timeRange, legendNames) { labels: labels, series: seriesData, }, config); -} \ No newline at end of file +} + +runInitHook("analytics_loaded"); \ No newline at end of file diff --git a/public/global.js b/public/global.js index c3f54a22..55ddb348 100644 --- a/public/global.js +++ b/public/global.js @@ -193,7 +193,7 @@ function wsAlertEvent(data) { updateAlertList(generalAlerts/*, alist*/); } -function runWebSockets() { +function runWebSockets(resume = false) { if(window.location.protocol == "https:") { conn = new WebSocket("wss://" + document.location.host + "/ws/"); } else conn = new WebSocket("ws://" + document.location.host + "/ws/"); @@ -206,6 +206,7 @@ function runWebSockets() { conn.onopen = () => { console.log("The WebSockets connection was opened"); conn.send("page " + document.location.pathname + '\r'); + if(resume) conn.send("resume " + Math.round((new Date()).getTime() / 1000) + '\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(); } @@ -213,23 +214,22 @@ function runWebSockets() { conn.onclose = () => { conn = false; console.log("The WebSockets connection was closed"); - let backoff = 1000; + let backoff = 0.8; if(wsBackoff < 0) wsBackoff = 0; - else if(wsBackoff > 12) backoff = 13000; - else if(wsBackoff > 5) backoff = 7000; + else if(wsBackoff > 12) backoff = 11; + else if(wsBackoff > 5) backoff = 5; wsBackoff++; setTimeout(() => { var alertMenuList = document.getElementsByClassName("menu_alerts"); - for(var i = 0; i < alertMenuList.length; i++) { - loadAlerts(alertMenuList[i]); - } - runWebSockets(); - }, 60 * backoff); + for(var i = 0; i < alertMenuList.length; i++) loadAlerts(alertMenuList[i]); + runWebSockets(true); + }, backoff * 60 * 1000); if(wsBackoff > 0) { - if(wsBackoff <= 5) setTimeout(() => wsBackoff--, 60 * 4000); - else if(wsBackoff <= 12) setTimeout(() => wsBackoff--, 60 * 20000); + if(wsBackoff <= 5) setTimeout(() => wsBackoff--, 5.5 * 60 * 1000); + else if(wsBackoff <= 12) setTimeout(() => wsBackoff--, 11.5 * 60 * 1000); + else setTimeout(() => wsBackoff--, 20 * 60 * 1000); } } @@ -333,16 +333,14 @@ function runWebSockets() { notifyOnScriptW("template_alert", (e) => { if(e!=undefined) console.log("failed alert? why?", e) }, () => { - console.log("ha") + //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(() => { alertsInitted = true; var alertMenuList = document.getElementsByClassName("menu_alerts"); - for(var i = 0; i < alertMenuList.length; i++) { - loadAlerts(alertMenuList[i]); - } + for(var i = 0; i < alertMenuList.length; i++) loadAlerts(alertMenuList[i]); if(window["WebSocket"]) runWebSockets(); }); }); diff --git a/public/init.js b/public/init.js index 2e983d2c..4639886a 100644 --- a/public/init.js +++ b/public/init.js @@ -4,7 +4,7 @@ var me = {}; var phraseBox = {}; if(tmplInits===undefined) var tmplInits = {}; var tmplPhrases = []; // [key] array of phrases indexed by order of use -var hooks = { +var hooks = { // Shorten this list by binding the hooks just in time? "pre_iffe": [], "pre_init": [], "start_init": [], @@ -15,6 +15,7 @@ var hooks = { "open_edit":[], "close_edit":[], "edit_item_pre_bind":[], + "analytics_loaded":[], }; var ranInitHooks = {} diff --git a/router_gen/main.go b/router_gen/main.go index af528789..7cbabc11 100644 --- a/router_gen/main.go +++ b/router_gen/main.go @@ -174,6 +174,7 @@ func main() { mapIt("routes.RobotsTxt") mapIt("routes.SitemapXml") mapIt("routes.BadRoute") + mapIt("routes.HTTPSRedirect") tmplVars.AllRouteNames = allRouteNames tmplVars.AllRouteMap = allRouteMap @@ -381,6 +382,17 @@ func (writ *WriterIntercept) WriteHeader(code int) { writ.ResponseWriter.WriteHeader(code) } +// HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS +type HTTPSRedirect struct { +} + +func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Connection", "close") + counters.RouteViewCounter.Bump({{ index .AllRouteMap "routes.HTTPSRedirect" }}) + dest := "https://" + req.Host + req.URL.String() + http.Redirect(w, req, dest, http.StatusTemporaryRedirect) +} + type GenRouter struct { UploadHandler func(http.ResponseWriter, *http.Request) extraRoutes map[string]func(http.ResponseWriter, *http.Request, common.User) common.RouteError diff --git a/routes/common.go b/routes/common.go index 42b04239..7e0e0fab 100644 --- a/routes/common.go +++ b/routes/common.go @@ -29,8 +29,9 @@ func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, hea } // TODO: Expand this to non-HTTPS requests too if !header.LooseCSP && common.Site.EnableSsl { - w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; upgrade-insecure-requests") + w.Header().Set("Content-Security-Policy", "default-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-eval' 'unsafe-inline'; img-src * data: 'unsafe-eval' 'unsafe-inline'; connect-src * 'unsafe-eval' 'unsafe-inline'; frame-src 'self' www.youtube-nocookie.com;upgrade-insecure-requests") } + header.AddScript("global.js") if header.CurrentUser.IsAdmin { header.Elapsed1 = time.Since(header.StartedAt).String() } diff --git a/routes/panel/analytics.go b/routes/panel/analytics.go index 49282721..83d9299c 100644 --- a/routes/panel/analytics.go +++ b/routes/panel/analytics.go @@ -125,7 +125,7 @@ func PreAnalyticsDetail(w http.ResponseWriter, r *http.Request, user *common.Use } basePage.AddSheet("chartist/chartist.min.css") basePage.AddScript("chartist/chartist.min.js") - basePage.AddScript("analytics.js") + basePage.AddScriptAsync("analytics.js") return basePage, nil } diff --git a/routes/panel/common.go b/routes/panel/common.go index 4d6874d7..e57b77ef 100644 --- a/routes/panel/common.go +++ b/routes/panel/common.go @@ -22,6 +22,7 @@ func successRedirect(dest string, w http.ResponseWriter, r *http.Request, isJs b } func renderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, header *common.Header, pi interface{}) common.RouteError { + header.AddScript("global.js") if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &header.CurrentUser, pi) { return nil } diff --git a/routes/stubs.go b/routes/stubs.go index 66801d85..f673f0d6 100644 --- a/routes/stubs.go +++ b/routes/stubs.go @@ -1,17 +1,5 @@ package routes -import "net/http" - -// HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS -type HTTPSRedirect struct { -} - -func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) { - w.Header().Set("Connection", "close") - dest := "https://" + req.Host + req.URL.String() - http.Redirect(w, req, dest, http.StatusTemporaryRedirect) -} - // Temporary stubs for view tracking func DynamicRoute() { } @@ -19,3 +7,7 @@ func UploadedFile() { } func BadRoute() { } + +// Real implementation is in router_gen/main.go, this is just a stub to map the analytics onto +func HTTPSRedirect() { +} diff --git a/templates/header.html b/templates/header.html index cb39c6e6..5d132488 100644 --- a/templates/header.html +++ b/templates/header.html @@ -6,13 +6,14 @@ {{range .Header.Stylesheets}} {{end}} {{range .Header.PreScriptsAsync}} - {{end}} + {{end}} + {{range .Header.ScriptsAsync}} + {{end}} {{range .Header.Scripts}} - {{end}} - + {{end}} {{if .Header.MetaDesc}}{{end}} {{/** TODO: Have page / forum / topic level tags and descriptions below as-well **/}} diff --git a/templates/panel_adminlogs.html b/templates/panel_adminlogs.html index ddd6e7a3..c9fbc462 100644 --- a/templates/panel_adminlogs.html +++ b/templates/panel_adminlogs.html @@ -2,6 +2,7 @@