Renamed the pre_render_panel_mod_log pre-render hook to pre_render_panel_modlogs.
Added the half-second task type, you'll why later ;) Reduced the amount of code duplication in the panel routes (saved a hundred lines). Added the two day time range option for graphs. We now track the discord, lynx and blank user agents. Renamed some template files for consistency and to help stamp out some duplicate code. Began work on topic move.
This commit is contained in:
parent
5f5994726e
commit
5ba7aa74f7
|
@ -112,7 +112,7 @@ var PreRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User
|
|||
"pre_render_panel_edit_group": nil,
|
||||
"pre_render_panel_edit_group_perms": nil,
|
||||
"pre_render_panel_themes": nil,
|
||||
"pre_render_panel_mod_log": nil,
|
||||
"pre_render_panel_modlogs": nil,
|
||||
|
||||
"pre_render_error": nil, // Note: This hook isn't run for a few errors whose templates are computed at startup and reused, such as InternalError. This hook is also not available in JS mode.
|
||||
"pre_render_security_error": nil,
|
||||
|
|
|
@ -19,6 +19,7 @@ type TaskStmts struct {
|
|||
getSync *sql.Stmt
|
||||
}
|
||||
|
||||
var ScheduledHalfSecondTasks []func() error
|
||||
var ScheduledSecondTasks []func() error
|
||||
var ScheduledFifteenMinuteTasks []func() error
|
||||
var ShutdownTasks []func() error
|
||||
|
@ -37,6 +38,11 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
// AddScheduledHalfSecondTask is not concurrency safe
|
||||
func AddScheduledHalfSecondTask(task func() error) {
|
||||
ScheduledHalfSecondTasks = append(ScheduledHalfSecondTasks, task)
|
||||
}
|
||||
|
||||
// AddScheduledSecondTask is not concurrency safe
|
||||
func AddScheduledSecondTask(task func() error) {
|
||||
ScheduledSecondTasks = append(ScheduledSecondTasks, task)
|
||||
|
|
|
@ -15,6 +15,7 @@ type Stmts struct {
|
|||
isThemeDefault *sql.Stmt
|
||||
getModlogs *sql.Stmt
|
||||
getModlogsOffset *sql.Stmt
|
||||
getAdminlogsOffset *sql.Stmt
|
||||
getReplyTID *sql.Stmt
|
||||
getTopicFID *sql.Stmt
|
||||
getUserReplyUID *sql.Stmt
|
||||
|
@ -122,6 +123,13 @@ func _gen_mssql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing getAdminlogsOffset statement.")
|
||||
stmts.getAdminlogsOffset, err = db.Prepare("SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [administration_logs] ORDER BY doneAt DESC OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY")
|
||||
if err != nil {
|
||||
log.Print("Bad Query: ","SELECT [action],[elementID],[elementType],[ipaddress],[actorID],[doneAt] FROM [administration_logs] ORDER BY doneAt DESC OFFSET ?1 ROWS FETCH NEXT ?2 ROWS ONLY")
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing getReplyTID statement.")
|
||||
stmts.getReplyTID, err = db.Prepare("SELECT [tid] FROM [replies] WHERE [rid] = ?1")
|
||||
if err != nil {
|
||||
|
|
|
@ -17,6 +17,7 @@ type Stmts struct {
|
|||
isThemeDefault *sql.Stmt
|
||||
getModlogs *sql.Stmt
|
||||
getModlogsOffset *sql.Stmt
|
||||
getAdminlogsOffset *sql.Stmt
|
||||
getReplyTID *sql.Stmt
|
||||
getTopicFID *sql.Stmt
|
||||
getUserReplyUID *sql.Stmt
|
||||
|
@ -118,6 +119,12 @@ func _gen_mysql() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing getAdminlogsOffset statement.")
|
||||
stmts.getAdminlogsOffset, err = db.Prepare("SELECT `action`,`elementID`,`elementType`,`ipaddress`,`actorID`,`doneAt` FROM `administration_logs` ORDER BY doneAt DESC LIMIT ?,?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Print("Preparing getReplyTID statement.")
|
||||
stmts.getReplyTID, err = db.Prepare("SELECT `tid` FROM `replies` WHERE `rid` = ?")
|
||||
if err != nil {
|
||||
|
|
|
@ -233,6 +233,9 @@ var agentMapEnum = map[string]int{
|
|||
"bing": 9,
|
||||
"baidu": 10,
|
||||
"duckduckgo": 11,
|
||||
"discord": 12,
|
||||
"lynx": 13,
|
||||
"blank": 14,
|
||||
}
|
||||
var reverseAgentMapEnum = map[int]string{
|
||||
0: "unknown",
|
||||
|
@ -247,6 +250,9 @@ var reverseAgentMapEnum = map[int]string{
|
|||
9: "bing",
|
||||
10: "baidu",
|
||||
11: "duckduckgo",
|
||||
12: "discord",
|
||||
13: "lynx",
|
||||
14: "blank",
|
||||
}
|
||||
|
||||
// TODO: Stop spilling these into the package scope?
|
||||
|
@ -344,7 +350,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
// Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like.
|
||||
// TODO: Add a setting to disable this?
|
||||
// TODO: Use a more efficient detector instead of smashing every possible combination in
|
||||
ua := strings.TrimSuffix(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36") // Noise, no one's going to be running this and it complicates implementing an efficient UA parser, particularly the more efficient right-to-left one I have in mind
|
||||
ua := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36")) // Noise, no one's going to be running this and it complicates implementing an efficient UA parser, particularly the more efficient right-to-left one I have in mind
|
||||
switch {
|
||||
case strings.Contains(ua,"Google"):
|
||||
common.AgentViewCounter.Bump(7)
|
||||
|
@ -368,6 +374,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
common.AgentViewCounter.Bump(10)
|
||||
case strings.Contains(ua,"DuckDuckBot"):
|
||||
common.AgentViewCounter.Bump(11)
|
||||
case strings.Contains(ua,"Discordbot"):
|
||||
common.AgentViewCounter.Bump(12)
|
||||
case strings.Contains(ua,"Lynx"):
|
||||
common.AgentViewCounter.Bump(13)
|
||||
case ua == "":
|
||||
common.AgentViewCounter.Bump(14)
|
||||
default:
|
||||
common.AgentViewCounter.Bump(0)
|
||||
if common.Dev.DebugMode {
|
||||
|
|
|
@ -69,23 +69,24 @@
|
|||
"register":"Registration",
|
||||
"ip-search":"IP Search",
|
||||
|
||||
"panel-dashboard":"Control Panel Dashboard",
|
||||
"panel-forums":"Forum Manager",
|
||||
"panel-delete-forum":"Delete Forum",
|
||||
"panel-edit-forum":"Forum Editor",
|
||||
"panel-analytics":"Analytics",
|
||||
"panel-settings":"Setting Manager",
|
||||
"panel-edit-setting":"Edit Setting",
|
||||
"panel-word-filters":"Word Filter Manager",
|
||||
"panel-edit-word-filter":"Edit Word Filter",
|
||||
"panel-plugins":"Plugin Manager",
|
||||
"panel-users":"User Manager",
|
||||
"panel-edit-user":"User Editor",
|
||||
"panel-groups":"Group Manager",
|
||||
"panel-edit-group":"Group Editor",
|
||||
"panel-themes":"Theme Manager",
|
||||
"panel-backups":"Backups",
|
||||
"panel-mod-logs":"Moderation Logs",
|
||||
"panel-debug":"Debug"
|
||||
"panel_dashboard":"Control Panel Dashboard",
|
||||
"panel_forums":"Forum Manager",
|
||||
"panel_delete_forum":"Delete Forum",
|
||||
"panel_edit_forum":"Forum Editor",
|
||||
"panel_analytics":"Analytics",
|
||||
"panel_settings":"Setting Manager",
|
||||
"panel_edit_setting":"Edit Setting",
|
||||
"panel_word_filters":"Word Filter Manager",
|
||||
"panel_edit_word_filter":"Edit Word Filter",
|
||||
"panel_plugins":"Plugin Manager",
|
||||
"panel_users":"User Manager",
|
||||
"panel_edit_user":"User Editor",
|
||||
"panel_groups":"Group Manager",
|
||||
"panel_edit_group":"Group Editor",
|
||||
"panel_themes":"Theme Manager",
|
||||
"panel_backups":"Backups",
|
||||
"panel_mod_logs":"Moderation Logs",
|
||||
"panel_admin_logs":"Administration Logs",
|
||||
"panel_debug":"Debug"
|
||||
}
|
||||
}
|
13
main.go
13
main.go
|
@ -246,13 +246,18 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
// Run this goroutine once a second
|
||||
// Run this goroutine once every half second
|
||||
halfSecondTicker := time.NewTicker(time.Second / 2)
|
||||
secondTicker := time.NewTicker(1 * time.Second)
|
||||
fifteenMinuteTicker := time.NewTicker(15 * time.Minute)
|
||||
//hourTicker := time.NewTicker(1 * time.Hour)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-halfSecondTicker.C:
|
||||
// TODO: Add a plugin hook here
|
||||
runTasks(common.ScheduledHalfSecondTasks)
|
||||
// TODO: Add a plugin hook here
|
||||
case <-secondTicker.C:
|
||||
// TODO: Add a plugin hook here
|
||||
runTasks(common.ScheduledSecondTasks)
|
||||
|
@ -291,13 +296,14 @@ func main() {
|
|||
}
|
||||
}()
|
||||
|
||||
// TODO: Move these routes into the new routes list
|
||||
log.Print("Initialising the router")
|
||||
router = NewGenRouter(http.FileServer(http.Dir("./uploads")))
|
||||
router.HandleFunc("/topic/create/submit/", routeTopicCreateSubmit)
|
||||
router.HandleFunc("/topic/", routeTopicID)
|
||||
router.HandleFunc("/reply/create/", routeCreateReply)
|
||||
//router.HandleFunc("/reply/edit/", routeReplyEdit)
|
||||
//router.HandleFunc("/reply/delete/", routeReplyDelete)
|
||||
//router.HandleFunc("/reply/edit/", routeReplyEdit) // No js fallback
|
||||
//router.HandleFunc("/reply/delete/", routeReplyDelete) // No js confirmation page? We could have a confirmation modal for the JS case
|
||||
router.HandleFunc("/reply/edit/submit/", routeReplyEditSubmit)
|
||||
router.HandleFunc("/reply/delete/submit/", routeReplyDeleteSubmit)
|
||||
router.HandleFunc("/reply/like/submit/", routeReplyLikeSubmit)
|
||||
|
@ -307,6 +313,7 @@ func main() {
|
|||
router.HandleFunc("/topic/unstick/submit/", routeUnstickTopic)
|
||||
router.HandleFunc("/topic/lock/submit/", routeLockTopic)
|
||||
router.HandleFunc("/topic/unlock/submit/", routeUnlockTopic)
|
||||
router.HandleFunc("/topic/move/submit/", routeMoveTopic)
|
||||
router.HandleFunc("/topic/like/submit/", routeLikeTopic)
|
||||
|
||||
// Accounts
|
||||
|
|
|
@ -312,6 +312,48 @@ func routeUnlockTopic(w http.ResponseWriter, r *http.Request, user common.User)
|
|||
return nil
|
||||
}
|
||||
|
||||
func routeMoveTopic(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
return common.NoPermissions(w, r, user)
|
||||
|
||||
tid, err := strconv.Atoi(r.URL.Path[len("/topic/move/submit/"):])
|
||||
if err != nil {
|
||||
return common.PreError("The provided TopicID is not a valid number.", w, r)
|
||||
}
|
||||
|
||||
topic, err := common.Topics.Get(tid)
|
||||
if err == ErrNoRows {
|
||||
return common.PreError("The topic you tried to move doesn't exist.", w, r)
|
||||
} else if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
// TODO: Add hooks to make use of headerLite
|
||||
_, ferr := common.SimpleForumUserCheck(w, r, &user, topic.ParentID)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ViewTopic { // TODO: MoveTopic permission?
|
||||
return common.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
err = topic.Unlock()
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
err = common.ModLogs.Create("move", tid, "topic", user.LastIP, user.ID)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
err = topic.CreateActionReply("move", user.LastIP, user)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Disable stat updates in posts handled by plugin_guilds
|
||||
// TODO: Update the stats after edits so that we don't under or over decrement stats during deletes
|
||||
func routeReplyEditSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
|
|
289
panel_routes.go
289
panel_routes.go
|
@ -30,20 +30,18 @@ func panelSuccessRedirect(dest string, w http.ResponseWriter, r *http.Request, i
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Implement this properly
|
||||
/*func panelRenderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, user common.User, pi interface{}) common.RouteError {
|
||||
func panelRenderTemplate(tmplName string, w http.ResponseWriter, r *http.Request, user common.User, pi interface{}) common.RouteError {
|
||||
if common.PreRenderHooks["pre_render_"+tmplName] != nil {
|
||||
if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &user, &pi) {
|
||||
if common.RunPreRenderHook("pre_render_"+tmplName, w, r, &user, pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, tmplName+".html", pi)
|
||||
err := common.Templates.ExecuteTemplate(w, tmplName+".html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
}*/
|
||||
}
|
||||
|
||||
func routePanel(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||
|
@ -170,18 +168,8 @@ func routePanel(w http.ResponseWriter, r *http.Request, user common.User) common
|
|||
gridElements = append(gridElements, common.GridElement{"dash-postsperuser", "5 posts / user / week", 14, "grid_stat stat_disabled", "", "", "Coming Soon!" /*"The average number of posts made by each active user over the past week"*/})
|
||||
}
|
||||
|
||||
pi := common.PanelDashboardPage{common.GetTitlePhrase("panel-dashboard"), user, headerVars, stats, "dashboard", gridElements}
|
||||
if common.PreRenderHooks["pre_render_panel_dashboard"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_dashboard", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel_dashboard.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
//return panelRenderTemplate("panel_dashboard",w,r,user,pi)
|
||||
pi := common.PanelDashboardPage{common.GetTitlePhrase("panel_dashboard"), user, headerVars, stats, "dashboard", gridElements}
|
||||
return panelRenderTemplate("panel_dashboard", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelForums(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
|
@ -210,18 +198,8 @@ func routePanelForums(w http.ResponseWriter, r *http.Request, user common.User)
|
|||
forumList = append(forumList, fadmin)
|
||||
}
|
||||
}
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel-forums"), user, headerVars, stats, "forums", forumList, nil}
|
||||
if common.PreRenderHooks["pre_render_panel_forums"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_forums", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-forums.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
return nil
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel_forums"), user, headerVars, stats, "forums", forumList, nil}
|
||||
return panelRenderTemplate("panel_forums", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
|
@ -274,7 +252,7 @@ func routePanelForumsDelete(w http.ResponseWriter, r *http.Request, user common.
|
|||
confirmMsg := "Are you sure you want to delete the '" + forum.Name + "' forum?"
|
||||
yousure := common.AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg}
|
||||
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel-delete-forum"), user, headerVars, stats, "forums", tList, yousure}
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel_delete_forum"), user, headerVars, stats, "forums", tList, yousure}
|
||||
if common.PreRenderHooks["pre_render_panel_delete_forum"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_delete_forum", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
@ -351,7 +329,7 @@ func routePanelForumsEdit(w http.ResponseWriter, r *http.Request, user common.Us
|
|||
gplist = append(gplist, common.GroupForumPermPreset{group, common.ForumPermsToGroupForumPreset(group.Forums[fid])})
|
||||
}
|
||||
|
||||
pi := common.PanelEditForumPage{common.GetTitlePhrase("panel-edit-forum"), user, headerVars, stats, "forums", forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist}
|
||||
pi := common.PanelEditForumPage{common.GetTitlePhrase("panel_edit_forum"), user, headerVars, stats, "forums", forum.ID, forum.Name, forum.Desc, forum.Active, forum.Preset, gplist}
|
||||
if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
@ -513,7 +491,7 @@ func routePanelForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, us
|
|||
addNameLangToggle("PinTopic", forumPerms.PinTopic)
|
||||
addNameLangToggle("CloseTopic", forumPerms.CloseTopic)
|
||||
|
||||
pi := common.PanelEditForumGroupPage{common.GetTitlePhrase("panel-edit-forum"), user, headerVars, stats, "forums", forum.ID, gid, forum.Name, forum.Desc, forum.Active, forum.Preset, formattedPermList}
|
||||
pi := common.PanelEditForumGroupPage{common.GetTitlePhrase("panel_edit_forum"), user, headerVars, stats, "forums", forum.ID, gid, forum.Name, forum.Desc, forum.Active, forum.Preset, formattedPermList}
|
||||
if common.PreRenderHooks["pre_render_panel_edit_forum"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_edit_forum", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
@ -596,6 +574,12 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo
|
|||
var timeRange = "six-hours"
|
||||
|
||||
switch r.FormValue("timeRange") {
|
||||
case "two-days": // Two days is experimental
|
||||
timeQuantity = 2
|
||||
timeUnit = "day"
|
||||
timeSlices = 24
|
||||
sliceWidth = 60 * 60 * 2
|
||||
timeRange = "two-days"
|
||||
case "one-day":
|
||||
timeQuantity = 1
|
||||
timeUnit = "day"
|
||||
|
@ -668,7 +652,7 @@ func routePanelAnalyticsViews(w http.ResponseWriter, r *http.Request, user commo
|
|||
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
|
||||
log.Printf("graph: %+v\n", graph)
|
||||
|
||||
pi := common.PanelAnalyticsPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", graph, viewItems, timeRange}
|
||||
pi := common.PanelAnalyticsPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", graph, viewItems, timeRange}
|
||||
if common.PreRenderHooks["pre_render_panel_analytics"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_analytics", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
@ -696,6 +680,12 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user
|
|||
var timeRange = "six-hours"
|
||||
|
||||
switch r.FormValue("timeRange") {
|
||||
case "two-days": // Two days is experimental
|
||||
timeQuantity = 2
|
||||
timeUnit = "day"
|
||||
timeSlices = 24
|
||||
sliceWidth = 60 * 60 * 2
|
||||
timeRange = "two-days"
|
||||
case "one-day":
|
||||
timeQuantity = 1
|
||||
timeUnit = "day"
|
||||
|
@ -767,17 +757,8 @@ func routePanelAnalyticsRouteViews(w http.ResponseWriter, r *http.Request, user
|
|||
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
|
||||
log.Printf("graph: %+v\n", graph)
|
||||
|
||||
pi := common.PanelAnalyticsRoutePage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", html.EscapeString(route), graph, timeRange}
|
||||
if common.PreRenderHooks["pre_render_panel_analytics_route_views"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_analytics_route_views", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-analytics-route-views.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelAnalyticsRoutePage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", html.EscapeString(route), graph, timeRange}
|
||||
return panelRenderTemplate("panel_analytics_route_views", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user common.User, agent string) common.RouteError {
|
||||
|
@ -795,6 +776,12 @@ func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user
|
|||
var timeRange = "six-hours"
|
||||
|
||||
switch r.FormValue("timeRange") {
|
||||
case "two-days": // Two days is experimental
|
||||
timeQuantity = 2
|
||||
timeUnit = "day"
|
||||
timeSlices = 24
|
||||
sliceWidth = 60 * 60 * 2
|
||||
timeRange = "two-days"
|
||||
case "one-day":
|
||||
timeQuantity = 1
|
||||
timeUnit = "day"
|
||||
|
@ -866,17 +853,8 @@ func routePanelAnalyticsAgentViews(w http.ResponseWriter, r *http.Request, user
|
|||
graph := common.PanelTimeGraph{Series: viewList, Labels: labelList}
|
||||
log.Printf("graph: %+v\n", graph)
|
||||
|
||||
pi := common.PanelAnalyticsAgentPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", html.EscapeString(agent), graph, timeRange}
|
||||
if common.PreRenderHooks["pre_render_panel_analytics_agent_views"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_analytics_agent_views", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-analytics-agent-views.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelAnalyticsAgentPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", html.EscapeString(agent), graph, timeRange}
|
||||
return panelRenderTemplate("panel_analytics_agent_views", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
|
@ -919,17 +897,8 @@ func routePanelAnalyticsRoutes(w http.ResponseWriter, r *http.Request, user comm
|
|||
})
|
||||
}
|
||||
|
||||
pi := common.PanelAnalyticsRoutesPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", routeItems}
|
||||
if common.PreRenderHooks["pre_render_panel_analytics_routes"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_analytics_routes", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-analytics-routes.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelAnalyticsRoutesPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", routeItems}
|
||||
return panelRenderTemplate("panel_analytics_routes", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelAnalyticsAgents(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
|
@ -972,17 +941,8 @@ func routePanelAnalyticsAgents(w http.ResponseWriter, r *http.Request, user comm
|
|||
})
|
||||
}
|
||||
|
||||
pi := common.PanelAnalyticsAgentsPage{common.GetTitlePhrase("panel-analytics"), user, headerVars, stats, "analytics", agentItems}
|
||||
if common.PreRenderHooks["pre_render_panel_analytics_agents"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_analytics_agents", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-analytics-agents.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelAnalyticsAgentsPage{common.GetTitlePhrase("panel_analytics"), user, headerVars, stats, "analytics", agentItems}
|
||||
return panelRenderTemplate("panel_analytics_agents", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelSettings(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
|
@ -1021,17 +981,8 @@ func routePanelSettings(w http.ResponseWriter, r *http.Request, user common.User
|
|||
settingList[setting.Name] = setting.Content
|
||||
}
|
||||
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel-settings"), user, headerVars, stats, "settings", tList, settingList}
|
||||
if common.PreRenderHooks["pre_render_panel_settings"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_settings", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-settings.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel_settings"), user, headerVars, stats, "settings", tList, settingList}
|
||||
return panelRenderTemplate("panel_settings", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user common.User, sname string) common.RouteError {
|
||||
|
@ -1067,17 +1018,8 @@ func routePanelSettingEdit(w http.ResponseWriter, r *http.Request, user common.U
|
|||
}
|
||||
}
|
||||
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel-edit-setting"), user, headerVars, stats, "settings", itemList, setting}
|
||||
if common.PreRenderHooks["pre_render_panel_setting"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_setting", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-setting.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel_edit_setting"), user, headerVars, stats, "settings", itemList, setting}
|
||||
return panelRenderTemplate("panel_setting", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelSettingEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, sname string) common.RouteError {
|
||||
|
@ -1112,17 +1054,8 @@ func routePanelWordFilters(w http.ResponseWriter, r *http.Request, user common.U
|
|||
}
|
||||
|
||||
var filterList = common.WordFilterBox.Load().(common.WordFilterMap)
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel-word-filters"), user, headerVars, stats, "word-filters", tList, filterList}
|
||||
if common.PreRenderHooks["pre_render_panel_word_filters"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_word_filters", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err := common.Templates.ExecuteTemplate(w, "panel-word-filters.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel_word_filters"), user, headerVars, stats, "word-filters", tList, filterList}
|
||||
return panelRenderTemplate("panel_word_filters", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
|
@ -1156,6 +1089,7 @@ func routePanelWordFiltersCreate(w http.ResponseWriter, r *http.Request, user co
|
|||
return panelSuccessRedirect("/panel/settings/word-filters/", w, r, isJs)
|
||||
}
|
||||
|
||||
// TODO: Implement this as a non-JS fallback
|
||||
func routePanelWordFiltersEdit(w http.ResponseWriter, r *http.Request, user common.User, wfid string) common.RouteError {
|
||||
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
|
@ -1167,17 +1101,8 @@ func routePanelWordFiltersEdit(w http.ResponseWriter, r *http.Request, user comm
|
|||
|
||||
_ = wfid
|
||||
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel-edit-word-filter"), user, headerVars, stats, "word-filters", tList, nil}
|
||||
if common.PreRenderHooks["pre_render_panel_word_filters_edit"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_word_filters_edit", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err := common.Templates.ExecuteTemplate(w, "panel-word-filters-edit.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel_edit_word_filter"), user, headerVars, stats, "word-filters", tList, nil}
|
||||
return panelRenderTemplate("panel_word_filters_edit", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelWordFiltersEditSubmit(w http.ResponseWriter, r *http.Request, user common.User, wfid string) common.RouteError {
|
||||
|
@ -1260,17 +1185,8 @@ func routePanelPlugins(w http.ResponseWriter, r *http.Request, user common.User)
|
|||
pluginList = append(pluginList, plugin)
|
||||
}
|
||||
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel-plugins"), user, headerVars, stats, "plugins", pluginList, nil}
|
||||
if common.PreRenderHooks["pre_render_panel_plugins"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_plugins", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err := common.Templates.ExecuteTemplate(w, "panel-plugins.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel_plugins"), user, headerVars, stats, "plugins", pluginList, nil}
|
||||
return panelRenderTemplate("panel_plugins", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelPluginsActivate(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||
|
@ -1481,17 +1397,8 @@ func routePanelUsers(w http.ResponseWriter, r *http.Request, user common.User) c
|
|||
}
|
||||
|
||||
pageList := common.Paginate(stats.Users, perPage, 5)
|
||||
pi := common.PanelUserPage{common.GetTitlePhrase("panel-users"), user, headerVars, stats, "users", userList, pageList, page, lastPage}
|
||||
if common.PreRenderHooks["pre_render_panel_users"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_users", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-users.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelUserPage{common.GetTitlePhrase("panel_users"), user, headerVars, stats, "users", userList, pageList, page, lastPage}
|
||||
return panelRenderTemplate("panel_users", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user common.User, suid string) common.RouteError {
|
||||
|
@ -1536,7 +1443,7 @@ func routePanelUsersEdit(w http.ResponseWriter, r *http.Request, user common.Use
|
|||
groupList = append(groupList, group)
|
||||
}
|
||||
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel-edit-user"), user, headerVars, stats, "users", groupList, targetUser}
|
||||
pi := common.PanelPage{common.GetTitlePhrase("panel_edit_user"), user, headerVars, stats, "users", groupList, targetUser}
|
||||
if common.PreRenderHooks["pre_render_panel_edit_user"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_edit_user", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
@ -1679,18 +1586,8 @@ func routePanelGroups(w http.ResponseWriter, r *http.Request, user common.User)
|
|||
//log.Printf("groupList: %+v\n", groupList)
|
||||
|
||||
pageList := common.Paginate(stats.Groups, perPage, 5)
|
||||
pi := common.PanelGroupPage{common.GetTitlePhrase("panel-groups"), user, headerVars, stats, "groups", groupList, pageList, page, lastPage}
|
||||
if common.PreRenderHooks["pre_render_panel_groups"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_groups", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
err := common.Templates.ExecuteTemplate(w, "panel-groups.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelGroupPage{common.GetTitlePhrase("panel_groups"), user, headerVars, stats, "groups", groupList, pageList, page, lastPage}
|
||||
return panelRenderTemplate("panel_groups", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user common.User, sgid string) common.RouteError {
|
||||
|
@ -1738,7 +1635,7 @@ func routePanelGroupsEdit(w http.ResponseWriter, r *http.Request, user common.Us
|
|||
|
||||
disableRank := !user.Perms.EditGroupGlobalPerms || (group.ID == 6)
|
||||
|
||||
pi := common.PanelEditGroupPage{common.GetTitlePhrase("panel-edit-group"), user, headerVars, stats, "groups", group.ID, group.Name, group.Tag, rank, disableRank}
|
||||
pi := common.PanelEditGroupPage{common.GetTitlePhrase("panel_edit_group"), user, headerVars, stats, "groups", group.ID, group.Name, group.Tag, rank, disableRank}
|
||||
if common.PreRenderHooks["pre_render_panel_edit_group"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_edit_group", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
@ -1825,7 +1722,7 @@ func routePanelGroupsEditPerms(w http.ResponseWriter, r *http.Request, user comm
|
|||
addGlobalPerm("ViewIPs", group.Perms.ViewIPs)
|
||||
addGlobalPerm("UploadFiles", group.Perms.UploadFiles)
|
||||
|
||||
pi := common.PanelEditGroupPermsPage{common.GetTitlePhrase("panel-edit-group"), user, headerVars, stats, "groups", group.ID, group.Name, localPerms, globalPerms}
|
||||
pi := common.PanelEditGroupPermsPage{common.GetTitlePhrase("panel_edit_group"), user, headerVars, stats, "groups", group.ID, group.Name, localPerms, globalPerms}
|
||||
if common.PreRenderHooks["pre_render_panel_edit_group_perms"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_edit_group_perms", w, r, &user, &pi) {
|
||||
return nil
|
||||
|
@ -2055,17 +1952,8 @@ func routePanelThemes(w http.ResponseWriter, r *http.Request, user common.User)
|
|||
|
||||
}
|
||||
|
||||
pi := common.PanelThemesPage{common.GetTitlePhrase("panel-themes"), user, headerVars, stats, "themes", pThemeList, vThemeList}
|
||||
if common.PreRenderHooks["pre_render_panel_themes"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_themes", w, r, &user, &pi) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err := common.Templates.ExecuteTemplate(w, "panel-themes.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelThemesPage{common.GetTitlePhrase("panel_themes"), user, headerVars, stats, "themes", pThemeList, vThemeList}
|
||||
return panelRenderTemplate("panel_themes", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user common.User, uname string) common.RouteError {
|
||||
|
@ -2172,12 +2060,8 @@ func routePanelBackups(w http.ResponseWriter, r *http.Request, user common.User,
|
|||
backupList = append(backupList, common.BackupItem{backupFile.Name(), backupFile.ModTime()})
|
||||
}
|
||||
|
||||
pi := common.PanelBackupPage{common.GetTitlePhrase("panel-backups"), user, headerVars, stats, "backups", backupList}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-backups.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelBackupPage{common.GetTitlePhrase("panel_backups"), user, headerVars, stats, "backups", backupList}
|
||||
return panelRenderTemplate("panel_backups", w, r, user, &pi)
|
||||
}
|
||||
|
||||
// TODO: Log errors when something really screwy is going on?
|
||||
|
@ -2270,17 +2154,48 @@ func routePanelLogsMod(w http.ResponseWriter, r *http.Request, user common.User)
|
|||
}
|
||||
|
||||
pageList := common.Paginate(logCount, perPage, 5)
|
||||
pi := common.PanelLogsPage{common.GetTitlePhrase("panel-mod-logs"), user, headerVars, stats, "logs", logs, pageList, page, lastPage}
|
||||
if common.PreRenderHooks["pre_render_panel_mod_log"] != nil {
|
||||
if common.RunPreRenderHook("pre_render_panel_mod_log", w, r, &user, &pi) {
|
||||
return nil
|
||||
pi := common.PanelLogsPage{common.GetTitlePhrase("panel_mod_logs"), user, headerVars, stats, "logs", logs, pageList, page, lastPage}
|
||||
return panelRenderTemplate("panel_modlogs", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelLogsAdmin(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
headerVars, stats, ferr := common.PanelUserCheck(w, r, &user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
}
|
||||
err = common.Templates.ExecuteTemplate(w, "panel-modlogs.html", pi)
|
||||
|
||||
logCount := common.ModLogs.GlobalCount()
|
||||
page, _ := strconv.Atoi(r.FormValue("page"))
|
||||
perPage := 10
|
||||
offset, page, lastPage := common.PageOffset(logCount, page, perPage)
|
||||
|
||||
rows, err := stmts.getAdminlogsOffset.Query(offset, perPage)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
defer rows.Close()
|
||||
|
||||
var logs []common.LogItem
|
||||
var action, elementType, ipaddress, doneAt string
|
||||
var elementID, actorID int
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&action, &elementID, &elementType, &ipaddress, &actorID, &doneAt)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
actor := handleUnknownUser(common.Users.Get(actorID))
|
||||
action = modlogsElementType(action, elementType, elementID, actor)
|
||||
logs = append(logs, common.LogItem{Action: template.HTML(action), IPAddress: ipaddress, DoneAt: doneAt})
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
pageList := common.Paginate(logCount, perPage, 5)
|
||||
pi := common.PanelLogsPage{common.GetTitlePhrase("panel_admin_logs"), user, headerVars, stats, "logs", logs, pageList, page, lastPage}
|
||||
return panelRenderTemplate("panel_adminlogs", w, r, user, &pi)
|
||||
}
|
||||
|
||||
func routePanelDebug(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError {
|
||||
|
@ -2294,10 +2209,6 @@ func routePanelDebug(w http.ResponseWriter, r *http.Request, user common.User) c
|
|||
openConnCount := dbStats.OpenConnections
|
||||
// Disk I/O?
|
||||
|
||||
pi := common.PanelDebugPage{common.GetTitlePhrase("panel-debug"), user, headerVars, stats, "debug", uptime, openConnCount, dbAdapter}
|
||||
err := common.Templates.ExecuteTemplate(w, "panel-debug.html", pi)
|
||||
if err != nil {
|
||||
return common.InternalError(err, w, r)
|
||||
}
|
||||
return nil
|
||||
pi := common.PanelDebugPage{common.GetTitlePhrase("panel_debug"), user, headerVars, stats, "debug", uptime, openConnCount, dbAdapter}
|
||||
return panelRenderTemplate("panel_debug", w, r, user, &pi)
|
||||
}
|
||||
|
|
|
@ -507,6 +507,14 @@ $(document).ready(function(){
|
|||
let action = optionNode.getAttribute("val");
|
||||
//console.log("action",action);
|
||||
|
||||
// Handle these specially
|
||||
switch(action) {
|
||||
case "move":
|
||||
console.log("move action");
|
||||
$("#mod_topic_mover").removeClass("auto_hide");
|
||||
return;
|
||||
}
|
||||
|
||||
let url = "/topic/"+action+"/submit/";
|
||||
//console.log("JSON.stringify(selectedTopics) ", JSON.stringify(selectedTopics));
|
||||
$.ajax({
|
||||
|
|
|
@ -230,6 +230,8 @@ func writeSelects(adapter qgen.Adapter) error {
|
|||
|
||||
build.Select("getModlogsOffset").Table("moderation_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Parse()
|
||||
|
||||
build.Select("getAdminlogsOffset").Table("administration_logs").Columns("action, elementID, elementType, ipaddress, actorID, doneAt").Orderby("doneAt DESC").Limit("?,?").Parse()
|
||||
|
||||
build.Select("getReplyTID").Table("replies").Columns("tid").Where("rid = ?").Parse()
|
||||
|
||||
build.Select("getTopicFID").Table("topics").Columns("parentID").Where("tid = ?").Parse()
|
||||
|
|
|
@ -171,6 +171,9 @@ func main() {
|
|||
"bing",
|
||||
"baidu",
|
||||
"duckduckgo",
|
||||
"discord",
|
||||
"lynx",
|
||||
"blank",
|
||||
}
|
||||
|
||||
tmplVars.AllAgentMap = make(map[string]int)
|
||||
|
@ -307,7 +310,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
// Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like.
|
||||
// TODO: Add a setting to disable this?
|
||||
// TODO: Use a more efficient detector instead of smashing every possible combination in
|
||||
ua := strings.TrimSuffix(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36") // Noise, no one's going to be running this and it complicates implementing an efficient UA parser, particularly the more efficient right-to-left one I have in mind
|
||||
ua := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36")) // Noise, no one's going to be running this and it complicates implementing an efficient UA parser, particularly the more efficient right-to-left one I have in mind
|
||||
switch {
|
||||
case strings.Contains(ua,"Google"):
|
||||
common.AgentViewCounter.Bump({{.AllAgentMap.googlebot}})
|
||||
|
@ -331,6 +334,12 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
common.AgentViewCounter.Bump({{.AllAgentMap.baidu}})
|
||||
case strings.Contains(ua,"DuckDuckBot"):
|
||||
common.AgentViewCounter.Bump({{.AllAgentMap.duckduckgo}})
|
||||
case strings.Contains(ua,"Discordbot"):
|
||||
common.AgentViewCounter.Bump({{.AllAgentMap.discord}})
|
||||
case strings.Contains(ua,"Lynx"):
|
||||
common.AgentViewCounter.Bump({{.AllAgentMap.lynx}})
|
||||
case ua == "":
|
||||
common.AgentViewCounter.Bump({{.AllAgentMap.blank}})
|
||||
default:
|
||||
common.AgentViewCounter.Bump({{.AllAgentMap.unknown}})
|
||||
if common.Dev.DebugMode {
|
||||
|
|
113
template_list.go
113
template_list.go
|
@ -811,6 +811,7 @@ var topics_8 = []byte(`
|
|||
<select class="mod_floater_options">
|
||||
<option val="delete">Delete them</option>
|
||||
<option val="lock">Lock them</option>
|
||||
<option val="move">Move them</option>
|
||||
</select>
|
||||
<button class="mod_floater_submit">Run</button>
|
||||
</div>
|
||||
|
@ -819,21 +820,40 @@ var topics_8 = []byte(`
|
|||
|
||||
`)
|
||||
var topics_9 = []byte(`
|
||||
<div id="mod_topic_mover" class="modal_pane auto_hide">
|
||||
<form action="/topic/move/submit/" method="post">
|
||||
<div class="pane_header">
|
||||
<h3>Move Topics (3)</h3>
|
||||
</div>
|
||||
<div class="pane_body">
|
||||
<div class="pane_table">
|
||||
<div class="pane_row"></div>
|
||||
`)
|
||||
var topics_10 = []byte(`<div class="pane_row">`)
|
||||
var topics_11 = []byte(`</div>`)
|
||||
var topics_12 = []byte(`
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane_buttons">
|
||||
<button>Move Topics</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="rowblock topic_create_form quick_create_form" style="display: none;" aria-label="Quick Topic Form">
|
||||
<form name="topic_create_form_form" id="topic_create_form_form" enctype="multipart/form-data" action="/topic/create/submit/" method="post"></form>
|
||||
<img class="little_row_avatar" src="`)
|
||||
var topics_10 = []byte(`" height="64" alt="Your Avatar" title="Your Avatar" />
|
||||
var topics_13 = []byte(`" height="64" alt="Your Avatar" title="Your Avatar" />
|
||||
<div class="main_form">
|
||||
<div class="topic_meta">
|
||||
<div class="formrow topic_board_row real_first_child">
|
||||
<div class="formitem"><select form="topic_create_form_form" id="topic_board_input" name="topic-board">
|
||||
`)
|
||||
var topics_11 = []byte(`<option `)
|
||||
var topics_12 = []byte(`selected`)
|
||||
var topics_13 = []byte(` value="`)
|
||||
var topics_14 = []byte(`">`)
|
||||
var topics_15 = []byte(`</option>`)
|
||||
var topics_16 = []byte(`
|
||||
var topics_14 = []byte(`<option `)
|
||||
var topics_15 = []byte(`selected`)
|
||||
var topics_16 = []byte(` value="`)
|
||||
var topics_17 = []byte(`">`)
|
||||
var topics_18 = []byte(`</option>`)
|
||||
var topics_19 = []byte(`
|
||||
</select></div>
|
||||
</div>
|
||||
<div class="formrow topic_name_row">
|
||||
|
@ -851,77 +871,77 @@ var topics_16 = []byte(`
|
|||
<div class="formitem">
|
||||
<button form="topic_create_form_form" class="formbutton">Create Topic</button>
|
||||
`)
|
||||
var topics_17 = []byte(`
|
||||
var topics_20 = []byte(`
|
||||
<input name="upload_files" form="topic_create_form_form" id="upload_files" multiple type="file" style="display: none;" />
|
||||
<label for="upload_files" class="formbutton add_file_button">Add File</label>
|
||||
<div id="upload_file_dock"></div>`)
|
||||
var topics_18 = []byte(`
|
||||
var topics_21 = []byte(`
|
||||
<button class="formbutton close_form">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
var topics_19 = []byte(`
|
||||
var topics_22 = []byte(`
|
||||
<div id="topic_list" class="rowblock topic_list" aria-label="A list containing topics from every forum">
|
||||
`)
|
||||
var topics_20 = []byte(`<div class="topic_row" data-tid="`)
|
||||
var topics_21 = []byte(`">
|
||||
<div class="rowitem topic_left passive datarow `)
|
||||
var topics_22 = []byte(`topic_sticky`)
|
||||
var topics_23 = []byte(`topic_closed`)
|
||||
var topics_23 = []byte(`<div class="topic_row" data-tid="`)
|
||||
var topics_24 = []byte(`">
|
||||
<div class="rowitem topic_left passive datarow `)
|
||||
var topics_25 = []byte(`topic_sticky`)
|
||||
var topics_26 = []byte(`topic_closed`)
|
||||
var topics_27 = []byte(`">
|
||||
<span class="selector"></span>
|
||||
<a href="`)
|
||||
var topics_25 = []byte(`"><img src="`)
|
||||
var topics_26 = []byte(`" height="64" alt="`)
|
||||
var topics_27 = []byte(`'s Avatar" title="`)
|
||||
var topics_28 = []byte(`'s Avatar" /></a>
|
||||
var topics_28 = []byte(`"><img src="`)
|
||||
var topics_29 = []byte(`" height="64" alt="`)
|
||||
var topics_30 = []byte(`'s Avatar" title="`)
|
||||
var topics_31 = []byte(`'s Avatar" /></a>
|
||||
<span class="topic_inner_left">
|
||||
<a class="rowtopic" href="`)
|
||||
var topics_29 = []byte(`" itemprop="itemListElement"><span>`)
|
||||
var topics_30 = []byte(`</span></a> `)
|
||||
var topics_31 = []byte(`<a class="rowsmall parent_forum" href="`)
|
||||
var topics_32 = []byte(`">`)
|
||||
var topics_33 = []byte(`</a>`)
|
||||
var topics_34 = []byte(`
|
||||
<br /><a class="rowsmall starter" href="`)
|
||||
var topics_32 = []byte(`" itemprop="itemListElement"><span>`)
|
||||
var topics_33 = []byte(`</span></a> `)
|
||||
var topics_34 = []byte(`<a class="rowsmall parent_forum" href="`)
|
||||
var topics_35 = []byte(`">`)
|
||||
var topics_36 = []byte(`</a>
|
||||
var topics_36 = []byte(`</a>`)
|
||||
var topics_37 = []byte(`
|
||||
<br /><a class="rowsmall starter" href="`)
|
||||
var topics_38 = []byte(`">`)
|
||||
var topics_39 = []byte(`</a>
|
||||
`)
|
||||
var topics_37 = []byte(`<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎</span>`)
|
||||
var topics_38 = []byte(`<span class="rowsmall topic_status_e topic_status_sticky" title="Status: Pinned"> | 📍︎</span>`)
|
||||
var topics_39 = []byte(`
|
||||
var topics_40 = []byte(`<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎</span>`)
|
||||
var topics_41 = []byte(`<span class="rowsmall topic_status_e topic_status_sticky" title="Status: Pinned"> | 📍︎</span>`)
|
||||
var topics_42 = []byte(`
|
||||
</span>
|
||||
<span class="topic_inner_right rowsmall" style="float: right;">
|
||||
<span class="replyCount">`)
|
||||
var topics_40 = []byte(`</span><br />
|
||||
var topics_43 = []byte(`</span><br />
|
||||
<span class="likeCount">`)
|
||||
var topics_41 = []byte(`</span>
|
||||
var topics_44 = []byte(`</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="rowitem topic_right passive datarow `)
|
||||
var topics_42 = []byte(`topic_sticky`)
|
||||
var topics_43 = []byte(`topic_closed`)
|
||||
var topics_44 = []byte(`">
|
||||
var topics_45 = []byte(`topic_sticky`)
|
||||
var topics_46 = []byte(`topic_closed`)
|
||||
var topics_47 = []byte(`">
|
||||
<a href="`)
|
||||
var topics_45 = []byte(`"><img src="`)
|
||||
var topics_46 = []byte(`" height="64" alt="`)
|
||||
var topics_47 = []byte(`'s Avatar" title="`)
|
||||
var topics_48 = []byte(`'s Avatar" /></a>
|
||||
var topics_48 = []byte(`"><img src="`)
|
||||
var topics_49 = []byte(`" height="64" alt="`)
|
||||
var topics_50 = []byte(`'s Avatar" title="`)
|
||||
var topics_51 = []byte(`'s Avatar" /></a>
|
||||
<span>
|
||||
<a href="`)
|
||||
var topics_49 = []byte(`" class="lastName" style="font-size: 14px;">`)
|
||||
var topics_50 = []byte(`</a><br>
|
||||
var topics_52 = []byte(`" class="lastName" style="font-size: 14px;">`)
|
||||
var topics_53 = []byte(`</a><br>
|
||||
<span class="rowsmall lastReplyAt">`)
|
||||
var topics_51 = []byte(`</span>
|
||||
var topics_54 = []byte(`</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>`)
|
||||
var topics_52 = []byte(`<div class="rowitem passive">There aren't any topics yet.`)
|
||||
var topics_53 = []byte(` <a href="/topics/create/">Start one?</a>`)
|
||||
var topics_54 = []byte(`</div>`)
|
||||
var topics_55 = []byte(`
|
||||
var topics_55 = []byte(`<div class="rowitem passive">There aren't any topics yet.`)
|
||||
var topics_56 = []byte(` <a href="/topics/create/">Start one?</a>`)
|
||||
var topics_57 = []byte(`</div>`)
|
||||
var topics_58 = []byte(`
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
@ -973,6 +993,7 @@ var forum_18 = []byte(`
|
|||
<select class="mod_floater_options">
|
||||
<option val="delete">Delete them</option>
|
||||
<option val="lock">Lock them</option>
|
||||
<option val="move">Move them</option>
|
||||
</select>
|
||||
<button>Run</button>
|
||||
</div>
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
// Code generated by Gosora. More below:
|
||||
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||
package main
|
||||
import "net/http"
|
||||
import "./common"
|
||||
import "strconv"
|
||||
import "net/http"
|
||||
|
||||
// nolint
|
||||
func init() {
|
||||
|
@ -99,108 +99,116 @@ if tmpl_topics_vars.CurrentUser.ID != 0 {
|
|||
w.Write(topics_8)
|
||||
if len(tmpl_topics_vars.ForumList) != 0 {
|
||||
w.Write(topics_9)
|
||||
w.Write([]byte(tmpl_topics_vars.CurrentUser.Avatar))
|
||||
w.Write(topics_10)
|
||||
if len(tmpl_topics_vars.ForumList) != 0 {
|
||||
for _, item := range tmpl_topics_vars.ForumList {
|
||||
w.Write(topics_11)
|
||||
if item.ID == tmpl_topics_vars.DefaultForum {
|
||||
w.Write(topics_12)
|
||||
}
|
||||
w.Write(topics_13)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topics_14)
|
||||
w.Write(topics_10)
|
||||
w.Write([]byte(item.Name))
|
||||
w.Write(topics_11)
|
||||
}
|
||||
}
|
||||
w.Write(topics_12)
|
||||
w.Write([]byte(tmpl_topics_vars.CurrentUser.Avatar))
|
||||
w.Write(topics_13)
|
||||
if len(tmpl_topics_vars.ForumList) != 0 {
|
||||
for _, item := range tmpl_topics_vars.ForumList {
|
||||
w.Write(topics_14)
|
||||
if item.ID == tmpl_topics_vars.DefaultForum {
|
||||
w.Write(topics_15)
|
||||
}
|
||||
}
|
||||
w.Write(topics_16)
|
||||
if tmpl_topics_vars.CurrentUser.Perms.UploadFiles {
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topics_17)
|
||||
}
|
||||
w.Write([]byte(item.Name))
|
||||
w.Write(topics_18)
|
||||
}
|
||||
}
|
||||
w.Write(topics_19)
|
||||
if tmpl_topics_vars.CurrentUser.Perms.UploadFiles {
|
||||
w.Write(topics_20)
|
||||
}
|
||||
w.Write(topics_21)
|
||||
}
|
||||
}
|
||||
w.Write(topics_22)
|
||||
if len(tmpl_topics_vars.TopicList) != 0 {
|
||||
for _, item := range tmpl_topics_vars.TopicList {
|
||||
w.Write(topics_20)
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topics_21)
|
||||
if item.Sticky {
|
||||
w.Write(topics_22)
|
||||
} else {
|
||||
if item.IsClosed {
|
||||
w.Write(topics_23)
|
||||
}
|
||||
}
|
||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||
w.Write(topics_24)
|
||||
w.Write([]byte(item.Creator.Link))
|
||||
if item.Sticky {
|
||||
w.Write(topics_25)
|
||||
w.Write([]byte(item.Creator.Avatar))
|
||||
w.Write(topics_26)
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(topics_27)
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(topics_28)
|
||||
w.Write([]byte(item.Link))
|
||||
w.Write(topics_29)
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(topics_30)
|
||||
if item.ForumName != "" {
|
||||
w.Write(topics_31)
|
||||
w.Write([]byte(item.ForumLink))
|
||||
w.Write(topics_32)
|
||||
w.Write([]byte(item.ForumName))
|
||||
w.Write(topics_33)
|
||||
}
|
||||
w.Write(topics_34)
|
||||
w.Write([]byte(item.Creator.Link))
|
||||
w.Write(topics_35)
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(topics_36)
|
||||
if item.IsClosed {
|
||||
w.Write(topics_37)
|
||||
}
|
||||
if item.Sticky {
|
||||
w.Write(topics_38)
|
||||
}
|
||||
w.Write(topics_39)
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(topics_40)
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topics_41)
|
||||
if item.Sticky {
|
||||
w.Write(topics_42)
|
||||
} else {
|
||||
if item.IsClosed {
|
||||
w.Write(topics_26)
|
||||
}
|
||||
}
|
||||
w.Write(topics_27)
|
||||
w.Write([]byte(item.Creator.Link))
|
||||
w.Write(topics_28)
|
||||
w.Write([]byte(item.Creator.Avatar))
|
||||
w.Write(topics_29)
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(topics_30)
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(topics_31)
|
||||
w.Write([]byte(item.Link))
|
||||
w.Write(topics_32)
|
||||
w.Write([]byte(item.Title))
|
||||
w.Write(topics_33)
|
||||
if item.ForumName != "" {
|
||||
w.Write(topics_34)
|
||||
w.Write([]byte(item.ForumLink))
|
||||
w.Write(topics_35)
|
||||
w.Write([]byte(item.ForumName))
|
||||
w.Write(topics_36)
|
||||
}
|
||||
w.Write(topics_37)
|
||||
w.Write([]byte(item.Creator.Link))
|
||||
w.Write(topics_38)
|
||||
w.Write([]byte(item.Creator.Name))
|
||||
w.Write(topics_39)
|
||||
if item.IsClosed {
|
||||
w.Write(topics_40)
|
||||
}
|
||||
if item.Sticky {
|
||||
w.Write(topics_41)
|
||||
}
|
||||
w.Write(topics_42)
|
||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||
w.Write(topics_43)
|
||||
}
|
||||
}
|
||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||
w.Write(topics_44)
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
if item.Sticky {
|
||||
w.Write(topics_45)
|
||||
w.Write([]byte(item.LastUser.Avatar))
|
||||
} else {
|
||||
if item.IsClosed {
|
||||
w.Write(topics_46)
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
}
|
||||
}
|
||||
w.Write(topics_47)
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_48)
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
w.Write(topics_48)
|
||||
w.Write([]byte(item.LastUser.Avatar))
|
||||
w.Write(topics_49)
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_50)
|
||||
w.Write([]byte(item.RelativeLastReplyAt))
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_51)
|
||||
}
|
||||
} else {
|
||||
w.Write([]byte(item.LastUser.Link))
|
||||
w.Write(topics_52)
|
||||
if tmpl_topics_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write([]byte(item.LastUser.Name))
|
||||
w.Write(topics_53)
|
||||
}
|
||||
w.Write([]byte(item.RelativeLastReplyAt))
|
||||
w.Write(topics_54)
|
||||
}
|
||||
} else {
|
||||
w.Write(topics_55)
|
||||
if tmpl_topics_vars.CurrentUser.Perms.CreateTopic {
|
||||
w.Write(topics_56)
|
||||
}
|
||||
w.Write(topics_57)
|
||||
}
|
||||
w.Write(topics_58)
|
||||
w.Write(footer_0)
|
||||
w.Write([]byte(common.BuildWidget("footer",tmpl_topics_vars.Header)))
|
||||
w.Write(footer_1)
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
<select class="mod_floater_options">
|
||||
<option val="delete">Delete them</option>
|
||||
<option val="lock">Lock them</option>
|
||||
<option val="move">Move them</option>
|
||||
</select>
|
||||
<button>Run</button>
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<div class="rowitem">
|
||||
<a>Views</a>
|
||||
<select class="timeRangeSelector to_right" name="timeRange">
|
||||
<option val="two-days"{{if eq .TimeRange "two-days"}} selected{{end}}>2 days</option>
|
||||
<option val="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>1 day</option>
|
||||
<option val="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>12 hours</option>
|
||||
<option val="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>6 hours</option>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<div class="rowitem">
|
||||
<a>{{.Agent}} Views</a>
|
||||
<select class="timeRangeSelector to_right" name="timeRange">
|
||||
<option val="two-days"{{if eq .TimeRange "two-days"}} selected{{end}}>2 days</option>
|
||||
<option val="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>1 day</option>
|
||||
<option val="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>12 hours</option>
|
||||
<option val="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>6 hours</option>
|
|
@ -7,6 +7,7 @@
|
|||
<div class="rowitem">
|
||||
<a>{{.Route}} Views</a>
|
||||
<select class="timeRangeSelector to_right" name="timeRange">
|
||||
<option val="two-days"{{if eq .TimeRange "two-days"}} selected{{end}}>2 days</option>
|
||||
<option val="one-day"{{if eq .TimeRange "one-day"}} selected{{end}}>1 day</option>
|
||||
<option val="twelve-hours"{{if eq .TimeRange "twelve-hours"}} selected{{end}}>12 hours</option>
|
||||
<option val="six-hours"{{if eq .TimeRange "six-hours"}} selected{{end}}>6 hours</option>
|
|
@ -17,6 +17,7 @@
|
|||
</div>
|
||||
|
||||
{{if ne .CurrentUser.ID 0}}
|
||||
{{/** TODO: Hide these from unauthorised users? **/}}
|
||||
<div class="mod_floater auto_hide">
|
||||
<form method="post">
|
||||
<div class="mod_floater_head">
|
||||
|
@ -26,6 +27,7 @@
|
|||
<select class="mod_floater_options">
|
||||
<option val="delete">Delete them</option>
|
||||
<option val="lock">Lock them</option>
|
||||
<option val="move">Move them</option>
|
||||
</select>
|
||||
<button class="mod_floater_submit">Run</button>
|
||||
</div>
|
||||
|
@ -33,6 +35,24 @@
|
|||
</div>
|
||||
|
||||
{{if .ForumList}}
|
||||
{{/** TODO: Have a seperate forum list for moving topics? Maybe an AJAX forum search compatible with plugin_guilds? **/}}
|
||||
{{/** TODO: Add ARIA attributes for this **/}}
|
||||
<div id="mod_topic_mover" class="modal_pane auto_hide">
|
||||
<form action="/topic/move/submit/" method="post">
|
||||
<div class="pane_header">
|
||||
<h3>Move Topics (3)</h3>
|
||||
</div>
|
||||
<div class="pane_body">
|
||||
<div class="pane_table">
|
||||
<div class="pane_row"></div>
|
||||
{{range .ForumList}}<div class="pane_row">{{.Name}}</div>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane_buttons">
|
||||
<button>Move Topics</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="rowblock topic_create_form quick_create_form" style="display: none;" aria-label="Quick Topic Form">
|
||||
<form name="topic_create_form_form" id="topic_create_form_form" enctype="multipart/form-data" action="/topic/create/submit/" method="post"></form>
|
||||
<img class="little_row_avatar" src="{{.CurrentUser.Avatar}}" height="64" alt="Your Avatar" title="Your Avatar" />
|
||||
|
|
|
@ -220,16 +220,18 @@ ul {
|
|||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
color: var(--primary-text-color);
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
margin-block-start: 0;
|
||||
margin-block-end: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
.colstack_head a h1 {
|
||||
font-size: 16px;
|
||||
color: var(--primary-link-color);
|
||||
}
|
||||
h1, h3 {
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
margin-block-start: 0;
|
||||
margin-block-end: 0;
|
||||
}
|
||||
|
||||
.colstack {
|
||||
display: flex;
|
||||
|
@ -261,9 +263,9 @@ ul {
|
|||
position: fixed;
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
background-color: var(--inverse-primary-text-color);
|
||||
width: 200px;
|
||||
height: 115px;
|
||||
background-color: var(--inverse-primary-text-color);
|
||||
border: 1px solid var(--header-border-color);
|
||||
border-bottom: 2px solid var(--header-border-color);
|
||||
z-index: 9999;
|
||||
|
@ -308,6 +310,17 @@ ul {
|
|||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.modal_pane {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: var(--inverse-primary-text-color);
|
||||
border: 1px solid var(--header-border-color);
|
||||
border-bottom: 2px solid var(--header-border-color);
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
|
|
|
@ -174,7 +174,7 @@
|
|||
stroke: hsl(359,98%,23%) !important;
|
||||
}
|
||||
.ct-point:hover {
|
||||
stroke: hsl(359,98%,20%) !important;
|
||||
stroke: hsl(359,98%,30%) !important;
|
||||
}
|
||||
.timeRangeSelector {
|
||||
margin-top: -5px;
|
||||
|
|
Loading…
Reference in New Issue