Localised the analytics panes.
Tweaked the analytics phrases to make them a little more compact so they don't overlap as badly. Added support for Facebook to the analytics panel. Fixed a bug where language ISO codes weren't tracked properly. Fixed a bug with settings overflowing their containers on Cosora. The panel elements can now take up more room on Nox. Added some information on per-theme overrides to docs/templates.md Added the analytics.now phrase. Added the analytics.today phrase. Added the analytics.days phrase. Added the analytics.days_short phrase. Added the analytics.months phrase. Added the analytics.months_short phrase.
This commit is contained in:
parent
ec313253ac
commit
ce04b6001e
|
@ -4,6 +4,8 @@ Gosora uses a subset of [Go Templates](https://golang.org/pkg/text/template/) wh
|
||||||
|
|
||||||
The base templates are stored in `/templates/` and you can shadow them by placing modified duplicates in `/templates/overrides/`. The default themes all share the same set of templates present there.
|
The base templates are stored in `/templates/` and you can shadow them by placing modified duplicates in `/templates/overrides/`. The default themes all share the same set of templates present there.
|
||||||
|
|
||||||
|
You can also override templates on a per-theme basis by navigating to `/themes/themeName/overrides` (replace themeName with the name of the theme) and placing the modified duplicates there.
|
||||||
|
|
||||||
# Non-standard Extensions
|
# Non-standard Extensions
|
||||||
|
|
||||||
We also have a few non-standard extensions only available on certain pages or areas, but these shouldn't be relied on in favour of more general mechanisms.
|
We also have a few non-standard extensions only available on certain pages or areas, but these shouldn't be relied on in favour of more general mechanisms.
|
||||||
|
|
|
@ -478,17 +478,18 @@ var agentMapEnum = map[string]int{
|
||||||
"seznambot": 17,
|
"seznambot": 17,
|
||||||
"discord": 18,
|
"discord": 18,
|
||||||
"twitter": 19,
|
"twitter": 19,
|
||||||
"cloudflare": 20,
|
"facebook": 20,
|
||||||
"uptimebot": 21,
|
"cloudflare": 21,
|
||||||
"slackbot": 22,
|
"uptimebot": 22,
|
||||||
"discourse": 23,
|
"slackbot": 23,
|
||||||
"lynx": 24,
|
"discourse": 24,
|
||||||
"blank": 25,
|
"lynx": 25,
|
||||||
"malformed": 26,
|
"blank": 26,
|
||||||
"suspicious": 27,
|
"malformed": 27,
|
||||||
"semrush": 28,
|
"suspicious": 28,
|
||||||
"dotbot": 29,
|
"semrush": 29,
|
||||||
"zgrab": 30,
|
"dotbot": 30,
|
||||||
|
"zgrab": 31,
|
||||||
}
|
}
|
||||||
var reverseAgentMapEnum = map[int]string{
|
var reverseAgentMapEnum = map[int]string{
|
||||||
0: "unknown",
|
0: "unknown",
|
||||||
|
@ -511,17 +512,18 @@ var reverseAgentMapEnum = map[int]string{
|
||||||
17: "seznambot",
|
17: "seznambot",
|
||||||
18: "discord",
|
18: "discord",
|
||||||
19: "twitter",
|
19: "twitter",
|
||||||
20: "cloudflare",
|
20: "facebook",
|
||||||
21: "uptimebot",
|
21: "cloudflare",
|
||||||
22: "slackbot",
|
22: "uptimebot",
|
||||||
23: "discourse",
|
23: "slackbot",
|
||||||
24: "lynx",
|
24: "discourse",
|
||||||
25: "blank",
|
25: "lynx",
|
||||||
26: "malformed",
|
26: "blank",
|
||||||
27: "suspicious",
|
27: "malformed",
|
||||||
28: "semrush",
|
28: "suspicious",
|
||||||
29: "dotbot",
|
29: "semrush",
|
||||||
30: "zgrab",
|
30: "dotbot",
|
||||||
|
31: "zgrab",
|
||||||
}
|
}
|
||||||
var markToAgent = map[string]string{
|
var markToAgent = map[string]string{
|
||||||
"OPR": "opera",
|
"OPR": "opera",
|
||||||
|
@ -546,6 +548,8 @@ var markToAgent = map[string]string{
|
||||||
"Slackbot": "slackbot",
|
"Slackbot": "slackbot",
|
||||||
"Discordbot": "discord",
|
"Discordbot": "discord",
|
||||||
"Twitterbot": "twitter",
|
"Twitterbot": "twitter",
|
||||||
|
"facebookexternalhit": "facebook",
|
||||||
|
"Facebot": "facebook",
|
||||||
"Discourse": "discourse",
|
"Discourse": "discourse",
|
||||||
"SemrushBot": "semrush",
|
"SemrushBot": "semrush",
|
||||||
"DotBot": "dotbot",
|
"DotBot": "dotbot",
|
||||||
|
@ -663,7 +667,7 @@ func (r *GenRouter) SuspiciousRequest(req *http.Request, prepend string) {
|
||||||
prepend += "\n"
|
prepend += "\n"
|
||||||
}
|
}
|
||||||
r.DumpRequest(req,prepend+"Suspicious Request")
|
r.DumpRequest(req,prepend+"Suspicious Request")
|
||||||
counters.AgentViewCounter.Bump(27)
|
counters.AgentViewCounter.Bump(28)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Pass the default path or config struct to the router rather than accessing it via a package global
|
// TODO: Pass the default path or config struct to the router rather than accessing it via a package global
|
||||||
|
@ -690,7 +694,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
w.WriteHeader(200) // 400
|
w.WriteHeader(200) // 400
|
||||||
w.Write([]byte(""))
|
w.Write([]byte(""))
|
||||||
r.DumpRequest(req,"Malformed Request")
|
r.DumpRequest(req,"Malformed Request")
|
||||||
counters.AgentViewCounter.Bump(26)
|
counters.AgentViewCounter.Bump(27)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,7 +756,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
// TODO: Use a more efficient detector instead of smashing every possible combination in
|
// TODO: Use a more efficient detector instead of smashing every possible combination in
|
||||||
ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another
|
ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another
|
||||||
if ua == "" {
|
if ua == "" {
|
||||||
counters.AgentViewCounter.Bump(25)
|
counters.AgentViewCounter.Bump(26)
|
||||||
if common.Dev.DebugMode {
|
if common.Dev.DebugMode {
|
||||||
var prepend string
|
var prepend string
|
||||||
for _, char := range req.UserAgent() {
|
for _, char := range req.UserAgent() {
|
||||||
|
@ -870,7 +874,9 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
llLang = seg
|
llLang = seg
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
common.DebugDetail("llLang:", llLang)
|
||||||
if llLang == "" {
|
if llLang == "" {
|
||||||
counters.LangViewCounter.Bump("none")
|
counters.LangViewCounter.Bump("none")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -386,6 +386,13 @@
|
||||||
"topic.copy_button_text":"Copy",
|
"topic.copy_button_text":"Copy",
|
||||||
"topic.upload_button_text":"Upload",
|
"topic.upload_button_text":"Upload",
|
||||||
|
|
||||||
|
"analytics.now": "now",
|
||||||
|
"analytics.today": "today",
|
||||||
|
"analytics.days": " days",
|
||||||
|
"analytics.days_short": "d",
|
||||||
|
"analytics.months": " months",
|
||||||
|
"analytics.months_short": "m",
|
||||||
|
|
||||||
"panel_rank_admins":"Admins",
|
"panel_rank_admins":"Admins",
|
||||||
"panel_rank_mods":"Mods",
|
"panel_rank_mods":"Mods",
|
||||||
"panel_rank_banned":"Banned",
|
"panel_rank_banned":"Banned",
|
||||||
|
|
|
@ -6,32 +6,30 @@
|
||||||
// TODO: Load rawLabels and seriesData dynamically rather than potentially fiddling with nonces for the CSP?
|
// TODO: Load rawLabels and seriesData dynamically rather than potentially fiddling with nonces for the CSP?
|
||||||
function buildStatsChart(rawLabels, seriesData, timeRange, legendNames) {
|
function buildStatsChart(rawLabels, seriesData, timeRange, legendNames) {
|
||||||
let labels = [];
|
let labels = [];
|
||||||
|
let aphrases = phraseBox["analytics"];
|
||||||
if(timeRange=="one-year") {
|
if(timeRange=="one-year") {
|
||||||
labels = ["today","01 months"];
|
labels = [aphrases["analytics.now"],"1" + aphrases["analytics.months_short"]];
|
||||||
for(let i = 2; i < 12; i++) {
|
for(let i = 2; i < 12; i++) {
|
||||||
let label = "0" + i + " months";
|
let label = i + aphrases["analytics.months_short"];
|
||||||
if(label.length > "01 months".length) label = label.substr(1);
|
|
||||||
labels.push(label);
|
labels.push(label);
|
||||||
}
|
}
|
||||||
} else if(timeRange=="three-months") {
|
} else if(timeRange=="three-months") {
|
||||||
labels = ["today","01 days"];
|
labels = [aphrases["analytics.now"],"3" + aphrases["analytics.days_short"]]
|
||||||
for(let i = 2; i < 90; i = i + 3) {
|
for(let i = 6; i < 90; i = i + 3) {
|
||||||
let label = "0" + i + " days";
|
let label = i + aphrases["analytics.days_short"];
|
||||||
if(label.length > "01 days".length) label = label.substr(1);
|
|
||||||
labels.push(label);
|
labels.push(label);
|
||||||
}
|
}
|
||||||
} else if(timeRange=="one-month") {
|
} else if(timeRange=="one-month") {
|
||||||
labels = ["today","01 days"];
|
labels = [aphrases["analytics.now"],"1" + aphrases["analytics.days_short"]];
|
||||||
for(let i = 2; i < 30; i++) {
|
for(let i = 2; i < 30; i++) {
|
||||||
let label = "0" + i + " days";
|
let label = i + aphrases["analytics.days_short"];
|
||||||
if(label.length > "01 days".length) label = label.substr(1);
|
|
||||||
labels.push(label);
|
labels.push(label);
|
||||||
}
|
}
|
||||||
} else if(timeRange=="one-week") {
|
} else if(timeRange=="one-week") {
|
||||||
labels = ["today"];
|
labels = [aphrases["analytics.now"]];
|
||||||
for(let i = 2; i < 14; i++) {
|
for(let i = 2; i < 14; i++) {
|
||||||
if (i%2==0) labels.push("");
|
if (i%2==0) labels.push("");
|
||||||
else labels.push(Math.floor(i/2) + " days");
|
else labels.push(Math.floor(i/2) + aphrases["analytics.days"]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for(const i in rawLabels) {
|
for(const i in rawLabels) {
|
||||||
|
|
|
@ -167,7 +167,7 @@ function RelativeTime(date) {
|
||||||
|
|
||||||
function initPhrases() {
|
function initPhrases() {
|
||||||
console.log("in initPhrases")
|
console.log("in initPhrases")
|
||||||
fetchPhrases("status,topic_list,alerts,paginator")
|
fetchPhrases("status,topic_list,alerts,paginator,analytics")
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchPhrases(plist) {
|
function fetchPhrases(plist) {
|
||||||
|
|
|
@ -213,6 +213,7 @@ func main() {
|
||||||
"seznambot",
|
"seznambot",
|
||||||
"discord",
|
"discord",
|
||||||
"twitter",
|
"twitter",
|
||||||
|
"facebook",
|
||||||
"cloudflare",
|
"cloudflare",
|
||||||
"uptimebot",
|
"uptimebot",
|
||||||
"slackbot",
|
"slackbot",
|
||||||
|
@ -255,6 +256,8 @@ func main() {
|
||||||
"Slackbot",
|
"Slackbot",
|
||||||
"Discordbot",
|
"Discordbot",
|
||||||
"Twitterbot",
|
"Twitterbot",
|
||||||
|
"facebookexternalhit",
|
||||||
|
"Facebot",
|
||||||
"Discourse",
|
"Discourse",
|
||||||
|
|
||||||
"SemrushBot",
|
"SemrushBot",
|
||||||
|
@ -273,20 +276,22 @@ func main() {
|
||||||
"SamsungBrowser": "samsung",
|
"SamsungBrowser": "samsung",
|
||||||
"UCBrowser": "ucbrowser",
|
"UCBrowser": "ucbrowser",
|
||||||
|
|
||||||
"Google": "googlebot",
|
"Google": "googlebot",
|
||||||
"Googlebot": "googlebot",
|
"Googlebot": "googlebot",
|
||||||
"yandex": "yandex", // from the URL
|
"yandex": "yandex", // from the URL
|
||||||
"DuckDuckBot": "duckduckgo",
|
"DuckDuckBot": "duckduckgo",
|
||||||
"Baiduspider": "baidu",
|
"Baiduspider": "baidu",
|
||||||
"bingbot": "bing",
|
"bingbot": "bing",
|
||||||
"BingPreview": "bing",
|
"BingPreview": "bing",
|
||||||
"SeznamBot": "seznambot",
|
"SeznamBot": "seznambot",
|
||||||
"CloudFlare": "cloudflare", // Track alwayson specifically in case there are other bots?
|
"CloudFlare": "cloudflare", // Track alwayson specifically in case there are other bots?
|
||||||
"Uptimebot": "uptimebot",
|
"Uptimebot": "uptimebot",
|
||||||
"Slackbot": "slackbot",
|
"Slackbot": "slackbot",
|
||||||
"Discordbot": "discord",
|
"Discordbot": "discord",
|
||||||
"Twitterbot": "twitter",
|
"Twitterbot": "twitter",
|
||||||
"Discourse": "discourse",
|
"facebookexternalhit": "facebook",
|
||||||
|
"Facebot": "facebook",
|
||||||
|
"Discourse": "discourse",
|
||||||
|
|
||||||
"SemrushBot": "semrush",
|
"SemrushBot": "semrush",
|
||||||
"DotBot": "dotbot",
|
"DotBot": "dotbot",
|
||||||
|
@ -662,7 +667,9 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
llLang = seg
|
llLang = seg
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
common.DebugDetail("llLang:", llLang)
|
||||||
if llLang == "" {
|
if llLang == "" {
|
||||||
counters.LangViewCounter.Bump("none")
|
counters.LangViewCounter.Bump("none")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -143,6 +143,7 @@ var phraseWhitelist = []string{
|
||||||
"status",
|
"status",
|
||||||
"alerts",
|
"alerts",
|
||||||
"paginator",
|
"paginator",
|
||||||
|
"analytics",
|
||||||
}
|
}
|
||||||
|
|
||||||
func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
func routeAPIPhrases(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||||
|
|
|
@ -198,6 +198,7 @@
|
||||||
float: none;
|
float: none;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
padding-top: 14px;
|
padding-top: 14px;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
#panel_page_list textarea, #panel_page_edit textarea {
|
#panel_page_list textarea, #panel_page_edit textarea {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
.colstack_right {
|
.colstack_right {
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
width: 75%;
|
width: 90%;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
padding-right: 24px;
|
padding-right: 24px;
|
||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
|
|
Loading…
Reference in New Issue