General:
Added better pagination to /forum/{id} Fixed the ordering of the elements in the pagesets. Added hooks to the task system. Reduced the amount of boilerplate for RunVhook and RunVhookNoReturn. Added RunVhookNeedHook to allow plugin developers to add custom content types to the report system. Added BulkGetMap to the DefaultPollStore. Renamed the MultiServer config setting to ServerCount and made it an integer. Don't cache topic lists for empty groups. Don't load replies for topics without any. Tempra Simple: Added chart and submenu CSS. Improved the input and select CSS. Fixed the pageset CSS. Fixed the poll input CSS. Tempra Conflux: Fixed the quick reply button CSS. Hid the avatar in the quick reply area. Added the poll CSS. Fixed the pageset CSS. Shadow: Fixed the time range selector CSS. Fixed the poll input CSS.
This commit is contained in:
parent
fa065bc584
commit
be47066770
|
@ -42,6 +42,15 @@ var VhookSkippable = map[string]func(...interface{}) (bool, RouteError){
|
||||||
|
|
||||||
//var vhookErrorable = map[string]func(...interface{}) (interface{}, RouteError){}
|
//var vhookErrorable = map[string]func(...interface{}) (interface{}, RouteError){}
|
||||||
|
|
||||||
|
var taskHooks = map[string][]func() error{
|
||||||
|
"before_half_second_tick": nil,
|
||||||
|
"after_half_second_tick": nil,
|
||||||
|
"before_second_tick": nil,
|
||||||
|
"after_second_tick": nil,
|
||||||
|
"before_fifteen_minute_tick": nil,
|
||||||
|
"after_fifteen_minute_tick": nil,
|
||||||
|
}
|
||||||
|
|
||||||
// Coming Soon:
|
// Coming Soon:
|
||||||
type Message interface {
|
type Message interface {
|
||||||
ID() int
|
ID() int
|
||||||
|
@ -225,6 +234,7 @@ func NewPlugin(uname string, name string, author string, url string, settings st
|
||||||
}
|
}
|
||||||
|
|
||||||
// ? - Is this racey?
|
// ? - Is this racey?
|
||||||
|
// TODO: Generate the cases in this switch
|
||||||
func (plugin *Plugin) AddHook(name string, handler interface{}) {
|
func (plugin *Plugin) AddHook(name string, handler interface{}) {
|
||||||
switch h := handler.(type) {
|
switch h := handler.(type) {
|
||||||
case func(interface{}) interface{}:
|
case func(interface{}) interface{}:
|
||||||
|
@ -254,6 +264,15 @@ func (plugin *Plugin) AddHook(name string, handler interface{}) {
|
||||||
PreRenderHooks[name] = append(PreRenderHooks[name], h)
|
PreRenderHooks[name] = append(PreRenderHooks[name], h)
|
||||||
}
|
}
|
||||||
plugin.Hooks[name] = len(PreRenderHooks[name])
|
plugin.Hooks[name] = len(PreRenderHooks[name])
|
||||||
|
case func() error: // ! We might want a more generic name, as we might use this signature for things other than tasks hooks
|
||||||
|
if len(taskHooks[name]) == 0 {
|
||||||
|
var hookSlice []func() error
|
||||||
|
hookSlice = append(hookSlice, h)
|
||||||
|
taskHooks[name] = hookSlice
|
||||||
|
} else {
|
||||||
|
taskHooks[name] = append(taskHooks[name], h)
|
||||||
|
}
|
||||||
|
plugin.Hooks[name] = len(taskHooks[name])
|
||||||
case func(...interface{}) interface{}:
|
case func(...interface{}) interface{}:
|
||||||
Vhooks[name] = h
|
Vhooks[name] = h
|
||||||
plugin.Hooks[name] = 0
|
plugin.Hooks[name] = 0
|
||||||
|
@ -266,6 +285,7 @@ func (plugin *Plugin) AddHook(name string, handler interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ? - Is this racey?
|
// ? - Is this racey?
|
||||||
|
// TODO: Generate the cases in this switch
|
||||||
func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
|
func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
|
||||||
switch handler.(type) {
|
switch handler.(type) {
|
||||||
case func(interface{}) interface{}:
|
case func(interface{}) interface{}:
|
||||||
|
@ -295,6 +315,15 @@ func (plugin *Plugin) RemoveHook(name string, handler interface{}) {
|
||||||
hook = append(hook[:key], hook[key+1:]...)
|
hook = append(hook[:key], hook[key+1:]...)
|
||||||
}
|
}
|
||||||
PreRenderHooks[name] = hook
|
PreRenderHooks[name] = hook
|
||||||
|
case func() error:
|
||||||
|
key := plugin.Hooks[name]
|
||||||
|
hook := taskHooks[name]
|
||||||
|
if len(hook) == 1 {
|
||||||
|
hook = []func() error{}
|
||||||
|
} else {
|
||||||
|
hook = append(hook[:key], hook[key+1:]...)
|
||||||
|
}
|
||||||
|
taskHooks[name] = hook
|
||||||
case func(...interface{}) interface{}:
|
case func(...interface{}) interface{}:
|
||||||
delete(Vhooks, name)
|
delete(Vhooks, name)
|
||||||
case func(...interface{}) (bool, RouteError):
|
case func(...interface{}) (bool, RouteError):
|
||||||
|
@ -340,7 +369,11 @@ func RunHookNoreturn(name string, data interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunVhook(name string, data ...interface{}) interface{} {
|
func RunVhook(name string, data ...interface{}) interface{} {
|
||||||
return Vhooks[name](data...)
|
hook := Vhooks[name]
|
||||||
|
if hook != nil {
|
||||||
|
return hook(data...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunVhookSkippable(name string, data ...interface{}) (bool, RouteError) {
|
func RunVhookSkippable(name string, data ...interface{}) (bool, RouteError) {
|
||||||
|
@ -348,7 +381,29 @@ func RunVhookSkippable(name string, data ...interface{}) (bool, RouteError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunVhookNoreturn(name string, data ...interface{}) {
|
func RunVhookNoreturn(name string, data ...interface{}) {
|
||||||
_ = Vhooks[name](data...)
|
hook := Vhooks[name]
|
||||||
|
if hook != nil {
|
||||||
|
_ = hook(data...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Find a better way of doing this
|
||||||
|
func RunVhookNeedHook(name string, data ...interface{}) (ret interface{}, hasHook bool) {
|
||||||
|
hook := Vhooks[name]
|
||||||
|
if hook != nil {
|
||||||
|
return hook(data...), true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunTaskHook(name string) error {
|
||||||
|
for _, hook := range taskHooks[name] {
|
||||||
|
err := hook()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks
|
// Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks
|
||||||
|
@ -360,14 +415,14 @@ func RunSshook(name string, data string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunPreRenderHook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
func RunPreRenderHook(name string, w http.ResponseWriter, r *http.Request, user *User, data interface{}) (halt bool) {
|
||||||
// This hook runs on ALL pre_render hooks
|
// This hook runs on ALL PreRender hooks
|
||||||
for _, hook := range PreRenderHooks["pre_render"] {
|
for _, hook := range PreRenderHooks["pre_render"] {
|
||||||
if hook(w, r, user, data) {
|
if hook(w, r, user, data) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The actual pre_render hook
|
// The actual PreRender hook
|
||||||
for _, hook := range PreRenderHooks[name] {
|
for _, hook := range PreRenderHooks[name] {
|
||||||
if hook(w, r, user, data) {
|
if hook(w, r, user, data) {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -232,9 +232,7 @@ func (mgs *MemoryGroupStore) Create(name string, tag string, isAdmin bool, isMod
|
||||||
var blankIntList []int
|
var blankIntList []int
|
||||||
var pluginPerms = make(map[string]bool)
|
var pluginPerms = make(map[string]bool)
|
||||||
var pluginPermsBytes = []byte("{}")
|
var pluginPermsBytes = []byte("{}")
|
||||||
if Vhooks["create_group_preappend"] != nil {
|
RunVhook("create_group_preappend", &pluginPerms, &pluginPermsBytes)
|
||||||
RunVhook("create_group_preappend", &pluginPerms, &pluginPermsBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate the forum permissions based on the presets...
|
// Generate the forum permissions based on the presets...
|
||||||
fdata, err := Forums.GetAll()
|
fdata, err := Forums.GetAll()
|
||||||
|
|
|
@ -79,6 +79,7 @@ type ForumPage struct {
|
||||||
Header *HeaderVars
|
Header *HeaderVars
|
||||||
ItemList []*TopicsRow
|
ItemList []*TopicsRow
|
||||||
Forum *Forum
|
Forum *Forum
|
||||||
|
PageList []int
|
||||||
Page int
|
Page int
|
||||||
LastPage int
|
LastPage int
|
||||||
}
|
}
|
||||||
|
@ -218,15 +219,15 @@ type PanelAnalyticsRoutePage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelAnalyticsAgentPage struct {
|
type PanelAnalyticsAgentPage struct {
|
||||||
Title string
|
Title string
|
||||||
CurrentUser User
|
CurrentUser User
|
||||||
Header *HeaderVars
|
Header *HeaderVars
|
||||||
Stats PanelStats
|
Stats PanelStats
|
||||||
Zone string
|
Zone string
|
||||||
Agent string
|
Agent string
|
||||||
FriendlyAgent string
|
FriendlyAgent string
|
||||||
PrimaryGraph PanelTimeGraph
|
PrimaryGraph PanelTimeGraph
|
||||||
TimeRange string
|
TimeRange string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelThemesPage struct {
|
type PanelThemesPage struct {
|
||||||
|
|
|
@ -3,6 +3,9 @@ package common
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"../query_gen/lib"
|
"../query_gen/lib"
|
||||||
)
|
)
|
||||||
|
@ -116,6 +119,92 @@ func (store *DefaultPollStore) Get(id int) (*Poll, error) {
|
||||||
return poll, err
|
return poll, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?
|
||||||
|
// TODO: ID of 0 should always error?
|
||||||
|
func (store *DefaultPollStore) BulkGetMap(ids []int) (list map[int]*Poll, err error) {
|
||||||
|
var idCount = len(ids)
|
||||||
|
list = make(map[int]*Poll)
|
||||||
|
if idCount == 0 {
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var stillHere []int
|
||||||
|
sliceList := store.cache.BulkGet(ids)
|
||||||
|
for i, sliceItem := range sliceList {
|
||||||
|
if sliceItem != nil {
|
||||||
|
list[sliceItem.ID] = sliceItem
|
||||||
|
} else {
|
||||||
|
stillHere = append(stillHere, ids[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ids = stillHere
|
||||||
|
|
||||||
|
// If every user is in the cache, then return immediately
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add a function for the qlist stuff
|
||||||
|
var qlist string
|
||||||
|
var pollIDList []interface{}
|
||||||
|
for _, id := range ids {
|
||||||
|
pollIDList = append(pollIDList, strconv.Itoa(id))
|
||||||
|
qlist += "?,"
|
||||||
|
}
|
||||||
|
qlist = qlist[0 : len(qlist)-1]
|
||||||
|
|
||||||
|
acc := qgen.Builder.Accumulator()
|
||||||
|
rows, err := acc.Select("polls").Columns("pollID, parentID, parentTable, type, options, votes").Where("pollID IN(" + qlist + ")").Query(pollIDList...)
|
||||||
|
if err != nil {
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
poll := &Poll{ID: 0}
|
||||||
|
var optionTxt []byte
|
||||||
|
err := rows.Scan(&poll.ID, &poll.ParentID, &poll.ParentTable, &poll.Type, &optionTxt, &poll.VoteCount)
|
||||||
|
if err != nil {
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(optionTxt, &poll.Options)
|
||||||
|
if err != nil {
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
poll.QuickOptions = store.unpackOptionsMap(poll.Options)
|
||||||
|
store.cache.Set(poll)
|
||||||
|
|
||||||
|
list[poll.ID] = poll
|
||||||
|
}
|
||||||
|
|
||||||
|
// Did we miss any polls?
|
||||||
|
if idCount > len(list) {
|
||||||
|
var sidList string
|
||||||
|
for _, id := range ids {
|
||||||
|
_, ok := list[id]
|
||||||
|
if !ok {
|
||||||
|
sidList += strconv.Itoa(id) + ","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We probably don't need this, but it might be useful in case of bugs in BulkCascadeGetMap
|
||||||
|
if sidList == "" {
|
||||||
|
if Dev.DebugMode {
|
||||||
|
log.Print("This data is sampled later in the BulkCascadeGetMap function, so it might miss the cached IDs")
|
||||||
|
log.Print("idCount", idCount)
|
||||||
|
log.Print("ids", ids)
|
||||||
|
log.Print("list", list)
|
||||||
|
}
|
||||||
|
return list, errors.New("We weren't able to find a poll, but we don't know which one")
|
||||||
|
}
|
||||||
|
sidList = sidList[0 : len(sidList)-1]
|
||||||
|
|
||||||
|
err = errors.New("Unable to find the polls with the following IDs: " + sidList)
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
func (store *DefaultPollStore) Reload(id int) error {
|
func (store *DefaultPollStore) Reload(id int) error {
|
||||||
poll := &Poll{ID: id}
|
poll := &Poll{ID: id}
|
||||||
var optionTxt []byte
|
var optionTxt []byte
|
||||||
|
|
|
@ -67,7 +67,7 @@ type config struct {
|
||||||
StaffCSS string // ? - Move this into the settings table? Might be better to implement this as Group CSS
|
StaffCSS string // ? - Move this into the settings table? Might be better to implement this as Group CSS
|
||||||
DefaultForum int // The forum posts go in by default, this used to be covered by the Uncategorised Forum, but we want to replace it with a more robust solution. Make this a setting?
|
DefaultForum int // The forum posts go in by default, this used to be covered by the Uncategorised Forum, but we want to replace it with a more robust solution. Make this a setting?
|
||||||
MinifyTemplates bool
|
MinifyTemplates bool
|
||||||
MultiServer bool
|
ServerCount int
|
||||||
|
|
||||||
Noavatar string // ? - Move this into the settings table?
|
Noavatar string // ? - Move this into the settings table?
|
||||||
ItemsPerPage int // ? - Move this into the settings table?
|
ItemsPerPage int // ? - Move this into the settings table?
|
||||||
|
@ -104,6 +104,9 @@ func VerifyConfig() error {
|
||||||
if !Forums.Exists(Config.DefaultForum) {
|
if !Forums.Exists(Config.DefaultForum) {
|
||||||
return errors.New("Invalid default forum")
|
return errors.New("Invalid default forum")
|
||||||
}
|
}
|
||||||
|
if Config.ServerCount < 1 {
|
||||||
|
return errors.New("You can't have less than one server")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,13 @@ func HandleExpiredScheduledGroups() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use AddScheduledSecondTask
|
// TODO: Use AddScheduledSecondTask
|
||||||
|
// TODO: Be a little more granular with the synchronisation
|
||||||
func HandleServerSync() error {
|
func HandleServerSync() error {
|
||||||
|
// We don't want to run any unnecessary queries when there is nothing to synchronise
|
||||||
|
/*if Config.ServerCount > 1 {
|
||||||
|
return nil
|
||||||
|
}*/
|
||||||
|
|
||||||
var lastUpdate time.Time
|
var lastUpdate time.Time
|
||||||
err := taskStmts.getSync.QueryRow().Scan(&lastUpdate)
|
err := taskStmts.getSync.QueryRow().Scan(&lastUpdate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -93,7 +99,6 @@ func HandleServerSync() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if lastUpdate.After(lastSync) {
|
if lastUpdate.After(lastSync) {
|
||||||
// TODO: A more granular sync
|
|
||||||
err = Forums.LoadForums()
|
err = Forums.LoadForums()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print("Unable to reload the forums")
|
log.Print("Unable to reload the forums")
|
||||||
|
|
|
@ -162,7 +162,7 @@ func compileTemplates() error {
|
||||||
//var topicList []TopicUser
|
//var topicList []TopicUser
|
||||||
//topicList = append(topicList,TopicUser{1,"topic-title","Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","","admin-fred","Admin Fred",config.DefaultGroup,"",0,"","","","",58,false})
|
//topicList = append(topicList,TopicUser{1,"topic-title","Topic Title","The topic content.",1,false,false,"Date","Date",1,"","127.0.0.1",0,1,"classname","","admin-fred","Admin Fred",config.DefaultGroup,"",0,"","","","",58,false})
|
||||||
forumItem := BlankForum(1, "general-forum.1", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0)
|
forumItem := BlankForum(1, "general-forum.1", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0)
|
||||||
forumPage := ForumPage{"General Forum", user, headerVars, topicsList, forumItem, 1, 1}
|
forumPage := ForumPage{"General Forum", user, headerVars, topicsList, forumItem, []int{1}, 1, 1}
|
||||||
forumTmpl, err := c.Compile("forum.html", "templates/", "common.ForumPage", forumPage, varList)
|
forumTmpl, err := c.Compile("forum.html", "templates/", "common.ForumPage", forumPage, varList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -122,6 +122,10 @@ func (tList *DefaultTopicList) Tick() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if group.UserCount == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
topicList, forumList, pageList, page, lastPage, err := tList.getListByGroup(group, 1)
|
topicList, forumList, pageList, page, lastPage, err := tList.getListByGroup(group, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -258,9 +262,7 @@ func (tList *DefaultTopicList) getList(page int, argList []interface{}, qlist st
|
||||||
topicItem.RelativeLastReplyAt = RelativeTime(topicItem.LastReplyAt)
|
topicItem.RelativeLastReplyAt = RelativeTime(topicItem.LastReplyAt)
|
||||||
|
|
||||||
// TODO: Rename this Vhook to better reflect moving the topic list from /routes/ to /common/
|
// TODO: Rename this Vhook to better reflect moving the topic list from /routes/ to /common/
|
||||||
if Vhooks["topics_topic_row_assign"] != nil {
|
RunVhook("topics_topic_row_assign", &topicItem, &forum)
|
||||||
RunVhook("topics_topic_row_assign", &topicItem, &forum)
|
|
||||||
}
|
|
||||||
topicList = append(topicList, &topicItem)
|
topicList = append(topicList, &topicItem)
|
||||||
reqUserList[topicItem.CreatedBy] = true
|
reqUserList[topicItem.CreatedBy] = true
|
||||||
reqUserList[topicItem.LastReplyBy] = true
|
reqUserList[topicItem.LastReplyBy] = true
|
||||||
|
|
|
@ -128,14 +128,14 @@ func (mus *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err erro
|
||||||
acc := qgen.Builder.Accumulator()
|
acc := qgen.Builder.Accumulator()
|
||||||
rows, err := acc.Select("users").Columns("uid, name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group").Where("uid IN(" + qlist + ")").Query(uidList...)
|
rows, err := acc.Select("users").Columns("uid, name, group, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, last_ip, temp_group").Where("uid IN(" + qlist + ")").Query(uidList...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return list, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
user := &User{Loggedin: true}
|
user := &User{Loggedin: true}
|
||||||
err := rows.Scan(&user.ID, &user.Name, &user.Group, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
err := rows.Scan(&user.ID, &user.Name, &user.Group, &user.IsSuperAdmin, &user.Session, &user.Email, &user.Avatar, &user.Message, &user.URLPrefix, &user.URLName, &user.Level, &user.Score, &user.LastIP, &user.TempGroup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return list, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Init()
|
user.Init()
|
||||||
|
|
|
@ -51,7 +51,7 @@ func init() {
|
||||||
common.Config.StaffCSS = "staff_post"
|
common.Config.StaffCSS = "staff_post"
|
||||||
common.Config.DefaultForum = 2
|
common.Config.DefaultForum = 2
|
||||||
common.Config.MinifyTemplates = true
|
common.Config.MinifyTemplates = true
|
||||||
common.Config.MultiServer = false // Experimental: Enable Cross-Server Synchronisation and several other features
|
common.Config.ServerCount = 1 // Experimental: Enable Cross-Server Synchronisation and several other features
|
||||||
|
|
||||||
//common.Config.Noavatar = "https://api.adorable.io/avatars/{width}/{id}@{site_url}.png"
|
//common.Config.Noavatar = "https://api.adorable.io/avatars/{width}/{id}@{site_url}.png"
|
||||||
common.Config.Noavatar = "https://api.adorable.io/avatars/285/{id}@{site_url}.png"
|
common.Config.Noavatar = "https://api.adorable.io/avatars/285/{id}@{site_url}.png"
|
||||||
|
|
|
@ -148,7 +148,7 @@ func init() {
|
||||||
common.Config.StaffCSS = "staff_post"
|
common.Config.StaffCSS = "staff_post"
|
||||||
common.Config.DefaultForum = 2
|
common.Config.DefaultForum = 2
|
||||||
common.Config.MinifyTemplates = true
|
common.Config.MinifyTemplates = true
|
||||||
common.Config.MultiServer = false // Experimental: Enable Cross-Server Synchronisation and several other features
|
common.Config.ServerCount = 1 // Experimental: Enable Cross-Server Synchronisation and several other features
|
||||||
|
|
||||||
//common.Config.Noavatar = "https://api.adorable.io/avatars/{width}/{id}@{site_url}.png"
|
//common.Config.Noavatar = "https://api.adorable.io/avatars/{width}/{id}@{site_url}.png"
|
||||||
common.Config.Noavatar = "https://api.adorable.io/avatars/285/{id}@{site_url}.png"
|
common.Config.Noavatar = "https://api.adorable.io/avatars/285/{id}@{site_url}.png"
|
||||||
|
|
20
main.go
20
main.go
|
@ -289,14 +289,20 @@ func main() {
|
||||||
fifteenMinuteTicker := time.NewTicker(15 * time.Minute)
|
fifteenMinuteTicker := time.NewTicker(15 * time.Minute)
|
||||||
//hourTicker := time.NewTicker(1 * time.Hour)
|
//hourTicker := time.NewTicker(1 * time.Hour)
|
||||||
go func() {
|
go func() {
|
||||||
|
var runHook = func(name string) {
|
||||||
|
err := common.RunTaskHook(name)
|
||||||
|
if err != nil {
|
||||||
|
common.LogError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-halfSecondTicker.C:
|
case <-halfSecondTicker.C:
|
||||||
// TODO: Add a plugin hook here
|
runHook("before_half_second_tick")
|
||||||
runTasks(common.ScheduledHalfSecondTasks)
|
runTasks(common.ScheduledHalfSecondTasks)
|
||||||
// TODO: Add a plugin hook here
|
runHook("after_half_second_tick")
|
||||||
case <-secondTicker.C:
|
case <-secondTicker.C:
|
||||||
// TODO: Add a plugin hook here
|
runHook("before_second_tick")
|
||||||
runTasks(common.ScheduledSecondTasks)
|
runTasks(common.ScheduledSecondTasks)
|
||||||
|
|
||||||
// TODO: Stop hard-coding this
|
// TODO: Stop hard-coding this
|
||||||
|
@ -317,16 +323,14 @@ func main() {
|
||||||
// TODO: Alert the admin, if CPU usage, RAM usage, or the number of posts in the past second are too high
|
// TODO: Alert the admin, if CPU usage, RAM usage, or the number of posts in the past second are too high
|
||||||
// TODO: Clean-up alerts with no unread matches which are over two weeks old. Move this to a 24 hour task?
|
// TODO: Clean-up alerts with no unread matches which are over two weeks old. Move this to a 24 hour task?
|
||||||
// TODO: Rescan the static files for changes
|
// TODO: Rescan the static files for changes
|
||||||
|
runHook("after_second_tick")
|
||||||
// TODO: Add a plugin hook here
|
|
||||||
case <-fifteenMinuteTicker.C:
|
case <-fifteenMinuteTicker.C:
|
||||||
// TODO: Add a plugin hook here
|
runHook("before_fifteen_minute_tick")
|
||||||
runTasks(common.ScheduledFifteenMinuteTasks)
|
runTasks(common.ScheduledFifteenMinuteTasks)
|
||||||
|
|
||||||
// TODO: Automatically lock topics, if they're really old, and the associated setting is enabled.
|
// TODO: Automatically lock topics, if they're really old, and the associated setting is enabled.
|
||||||
// TODO: Publish scheduled posts.
|
// TODO: Publish scheduled posts.
|
||||||
|
runHook("after_fifteen_minute_tick")
|
||||||
// TODO: Add a plugin hook here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle the daily clean-up.
|
// TODO: Handle the daily clean-up.
|
||||||
|
|
|
@ -405,10 +405,11 @@ func routeReportSubmit(w http.ResponseWriter, r *http.Request, user common.User,
|
||||||
title = "Topic: " + title
|
title = "Topic: " + title
|
||||||
content = content + "\n\nOriginal Post: #tid-" + strconv.Itoa(itemID)
|
content = content + "\n\nOriginal Post: #tid-" + strconv.Itoa(itemID)
|
||||||
} else {
|
} else {
|
||||||
if common.Vhooks["report_preassign"] != nil {
|
_, hasHook := common.RunVhookNeedHook("report_preassign", &itemID, &itemType)
|
||||||
common.RunVhookNoreturn("report_preassign", &itemID, &itemType)
|
if hasHook {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't try to guess the type
|
// Don't try to guess the type
|
||||||
return common.LocalError("Unknown type", w, r, user)
|
return common.LocalError("Unknown type", w, r, user)
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,9 +97,7 @@ func routeForum(w http.ResponseWriter, r *http.Request, user common.User, sfid s
|
||||||
topicItem.Link = common.BuildTopicURL(common.NameToSlug(topicItem.Title), topicItem.ID)
|
topicItem.Link = common.BuildTopicURL(common.NameToSlug(topicItem.Title), topicItem.ID)
|
||||||
topicItem.RelativeLastReplyAt = common.RelativeTime(topicItem.LastReplyAt)
|
topicItem.RelativeLastReplyAt = common.RelativeTime(topicItem.LastReplyAt)
|
||||||
|
|
||||||
if common.Vhooks["forum_trow_assign"] != nil {
|
common.RunVhook("forum_trow_assign", &topicItem, &forum)
|
||||||
common.RunVhook("forum_trow_assign", &topicItem, &forum)
|
|
||||||
}
|
|
||||||
topicList = append(topicList, &topicItem)
|
topicList = append(topicList, &topicItem)
|
||||||
reqUserList[topicItem.CreatedBy] = true
|
reqUserList[topicItem.CreatedBy] = true
|
||||||
reqUserList[topicItem.LastReplyBy] = true
|
reqUserList[topicItem.LastReplyBy] = true
|
||||||
|
@ -130,7 +128,8 @@ func routeForum(w http.ResponseWriter, r *http.Request, user common.User, sfid s
|
||||||
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
topicItem.LastUser = userList[topicItem.LastReplyBy]
|
||||||
}
|
}
|
||||||
|
|
||||||
pi := common.ForumPage{forum.Name, user, headerVars, topicList, forum, page, lastPage}
|
pageList := common.Paginate(forum.TopicCount, common.Config.ItemsPerPage, 5)
|
||||||
|
pi := common.ForumPage{forum.Name, user, headerVars, topicList, forum, pageList, page, lastPage}
|
||||||
if common.PreRenderHooks["pre_render_forum"] != nil {
|
if common.PreRenderHooks["pre_render_forum"] != nil {
|
||||||
if common.RunPreRenderHook("pre_render_forum", w, r, &user, &pi) {
|
if common.RunPreRenderHook("pre_render_forum", w, r, &user, &pi) {
|
||||||
return nil
|
return nil
|
||||||
|
|
138
routes/topic.go
138
routes/topic.go
|
@ -37,8 +37,6 @@ func init() {
|
||||||
var successJSONBytes = []byte(`{"success":"1"}`)
|
var successJSONBytes = []byte(`{"success":"1"}`)
|
||||||
|
|
||||||
func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit string) common.RouteError {
|
func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit string) common.RouteError {
|
||||||
var err error
|
|
||||||
var replyList []common.ReplyUser
|
|
||||||
page, _ := strconv.Atoi(r.FormValue("page"))
|
page, _ := strconv.Atoi(r.FormValue("page"))
|
||||||
|
|
||||||
// SEO URLs...
|
// SEO URLs...
|
||||||
|
@ -110,82 +108,80 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit
|
||||||
|
|
||||||
// Calculate the offset
|
// Calculate the offset
|
||||||
offset, page, lastPage := common.PageOffset(topic.PostCount, page, common.Config.ItemsPerPage)
|
offset, page, lastPage := common.PageOffset(topic.PostCount, page, common.Config.ItemsPerPage)
|
||||||
tpage := common.TopicPage{topic.Title, user, headerVars, replyList, topic, poll, page, lastPage}
|
tpage := common.TopicPage{topic.Title, user, headerVars, []common.ReplyUser{}, topic, poll, page, lastPage}
|
||||||
|
|
||||||
// Get the replies..
|
// Get the replies if we have any...
|
||||||
rows, err := topicStmts.getReplies.Query(topic.ID, offset, common.Config.ItemsPerPage)
|
if topic.PostCount > 0 {
|
||||||
if err == sql.ErrNoRows {
|
rows, err := topicStmts.getReplies.Query(topic.ID, offset, common.Config.ItemsPerPage)
|
||||||
return common.LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.", w, r, user)
|
if err == sql.ErrNoRows {
|
||||||
} else if err != nil {
|
return common.LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.", w, r, user)
|
||||||
return common.InternalError(err, w, r)
|
} else if err != nil {
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
replyItem := common.ReplyUser{ClassName: ""}
|
|
||||||
for rows.Next() {
|
|
||||||
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &replyItem.Group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IPAddress, &replyItem.LikeCount, &replyItem.ActionType)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
return common.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
replyItem.UserLink = common.BuildProfileURL(common.NameToSlug(replyItem.CreatedByName), replyItem.CreatedBy)
|
replyItem := common.ReplyUser{ClassName: ""}
|
||||||
replyItem.ParentID = topic.ID
|
for rows.Next() {
|
||||||
replyItem.ContentHtml = common.ParseMessage(replyItem.Content, topic.ParentID, "forums")
|
err := rows.Scan(&replyItem.ID, &replyItem.Content, &replyItem.CreatedBy, &replyItem.CreatedAt, &replyItem.LastEdit, &replyItem.LastEditBy, &replyItem.Avatar, &replyItem.CreatedByName, &replyItem.Group, &replyItem.URLPrefix, &replyItem.URLName, &replyItem.Level, &replyItem.IPAddress, &replyItem.LikeCount, &replyItem.ActionType)
|
||||||
replyItem.ContentLines = strings.Count(replyItem.Content, "\n")
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
postGroup, err = common.Groups.Get(replyItem.Group)
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
if postGroup.IsMod || postGroup.IsAdmin {
|
|
||||||
replyItem.ClassName = common.Config.StaffCSS
|
|
||||||
} else {
|
|
||||||
replyItem.ClassName = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make a function for this? Build a more sophisticated noavatar handling system? Do bulk user loads and let the common.UserStore initialise this?
|
|
||||||
replyItem.Avatar = common.BuildAvatar(replyItem.CreatedBy, replyItem.Avatar)
|
|
||||||
replyItem.Tag = postGroup.Tag
|
|
||||||
replyItem.RelativeCreatedAt = common.RelativeTime(replyItem.CreatedAt)
|
|
||||||
|
|
||||||
// We really shouldn't have inline HTML, we should do something about this...
|
|
||||||
if replyItem.ActionType != "" {
|
|
||||||
switch replyItem.ActionType {
|
|
||||||
case "lock":
|
|
||||||
replyItem.ActionType = "This topic has been locked by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
|
||||||
replyItem.ActionIcon = "🔒︎"
|
|
||||||
case "unlock":
|
|
||||||
replyItem.ActionType = "This topic has been reopened by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
|
||||||
replyItem.ActionIcon = "🔓︎"
|
|
||||||
case "stick":
|
|
||||||
replyItem.ActionType = "This topic has been pinned by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
|
||||||
replyItem.ActionIcon = "📌︎"
|
|
||||||
case "unstick":
|
|
||||||
replyItem.ActionType = "This topic has been unpinned by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
|
||||||
replyItem.ActionIcon = "📌︎"
|
|
||||||
case "move":
|
|
||||||
replyItem.ActionType = "This topic has been moved by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
|
||||||
default:
|
|
||||||
replyItem.ActionType = replyItem.ActionType + " has happened"
|
|
||||||
replyItem.ActionIcon = ""
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
replyItem.Liked = false
|
|
||||||
|
|
||||||
if common.Vhooks["topic_reply_row_assign"] != nil {
|
replyItem.UserLink = common.BuildProfileURL(common.NameToSlug(replyItem.CreatedByName), replyItem.CreatedBy)
|
||||||
|
replyItem.ParentID = topic.ID
|
||||||
|
replyItem.ContentHtml = common.ParseMessage(replyItem.Content, topic.ParentID, "forums")
|
||||||
|
replyItem.ContentLines = strings.Count(replyItem.Content, "\n")
|
||||||
|
|
||||||
|
postGroup, err = common.Groups.Get(replyItem.Group)
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if postGroup.IsMod || postGroup.IsAdmin {
|
||||||
|
replyItem.ClassName = common.Config.StaffCSS
|
||||||
|
} else {
|
||||||
|
replyItem.ClassName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Make a function for this? Build a more sophisticated noavatar handling system? Do bulk user loads and let the common.UserStore initialise this?
|
||||||
|
replyItem.Avatar = common.BuildAvatar(replyItem.CreatedBy, replyItem.Avatar)
|
||||||
|
replyItem.Tag = postGroup.Tag
|
||||||
|
replyItem.RelativeCreatedAt = common.RelativeTime(replyItem.CreatedAt)
|
||||||
|
|
||||||
|
// We really shouldn't have inline HTML, we should do something about this...
|
||||||
|
if replyItem.ActionType != "" {
|
||||||
|
switch replyItem.ActionType {
|
||||||
|
case "lock":
|
||||||
|
replyItem.ActionType = "This topic has been locked by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
||||||
|
replyItem.ActionIcon = "🔒︎"
|
||||||
|
case "unlock":
|
||||||
|
replyItem.ActionType = "This topic has been reopened by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
||||||
|
replyItem.ActionIcon = "🔓︎"
|
||||||
|
case "stick":
|
||||||
|
replyItem.ActionType = "This topic has been pinned by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
||||||
|
replyItem.ActionIcon = "📌︎"
|
||||||
|
case "unstick":
|
||||||
|
replyItem.ActionType = "This topic has been unpinned by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
||||||
|
replyItem.ActionIcon = "📌︎"
|
||||||
|
case "move":
|
||||||
|
replyItem.ActionType = "This topic has been moved by <a href='" + replyItem.UserLink + "'>" + replyItem.CreatedByName + "</a>"
|
||||||
|
default:
|
||||||
|
replyItem.ActionType = replyItem.ActionType + " has happened"
|
||||||
|
replyItem.ActionIcon = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
replyItem.Liked = false
|
||||||
|
|
||||||
common.RunVhook("topic_reply_row_assign", &tpage, &replyItem)
|
common.RunVhook("topic_reply_row_assign", &tpage, &replyItem)
|
||||||
|
// TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis?
|
||||||
|
tpage.ItemList = append(tpage.ItemList, replyItem)
|
||||||
|
}
|
||||||
|
err = rows.Err()
|
||||||
|
if err != nil {
|
||||||
|
return common.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
//replyList = append(replyList, replyItem)
|
|
||||||
// TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis?
|
|
||||||
tpage.ItemList = append(tpage.ItemList, replyItem)
|
|
||||||
}
|
|
||||||
err = rows.Err()
|
|
||||||
if err != nil {
|
|
||||||
return common.InternalError(err, w, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//tpage.ItemList = replyList
|
|
||||||
if common.PreRenderHooks["pre_render_view_topic"] != nil {
|
if common.PreRenderHooks["pre_render_view_topic"] != nil {
|
||||||
if common.RunPreRenderHook("pre_render_view_topic", w, r, &user, &tpage) {
|
if common.RunPreRenderHook("pre_render_view_topic", w, r, &user, &tpage) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -195,7 +191,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user common.User, urlBit
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.InternalError(err, w, r)
|
return common.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
common.TopicViewCounter.Bump(topic.ID) // TODO Move this into the router?
|
common.TopicViewCounter.Bump(topic.ID) // TODO: Move this into the router?
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,9 +224,7 @@ func CreateTopic(w http.ResponseWriter, r *http.Request, user common.User, sfid
|
||||||
// Lock this to the forum being linked?
|
// Lock this to the forum being linked?
|
||||||
// Should we always put it in strictmode when it's linked from another forum? Well, the user might end up changing their mind on what forum they want to post in and it would be a hassle, if they had to switch pages, even if it is a single click for many (exc. mobile)
|
// Should we always put it in strictmode when it's linked from another forum? Well, the user might end up changing their mind on what forum they want to post in and it would be a hassle, if they had to switch pages, even if it is a single click for many (exc. mobile)
|
||||||
var strictmode bool
|
var strictmode bool
|
||||||
if common.Vhooks["topic_create_pre_loop"] != nil {
|
common.RunVhook("topic_create_pre_loop", w, r, fid, &headerVars, &user, &strictmode)
|
||||||
common.RunVhook("topic_create_pre_loop", w, r, fid, &headerVars, &user, &strictmode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Re-add support for plugin_guilds
|
// TODO: Re-add support for plugin_guilds
|
||||||
var forumList []common.Forum
|
var forumList []common.Forum
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
// Code generated by Gosora. More below:
|
// 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. */
|
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
|
||||||
package main
|
package main
|
||||||
import "strconv"
|
|
||||||
import "net/http"
|
import "net/http"
|
||||||
import "./common"
|
import "./common"
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -93,118 +93,142 @@ w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||||
w.Write(forum_4)
|
w.Write(forum_4)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page + 1)))
|
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page + 1)))
|
||||||
w.Write(forum_5)
|
w.Write(forum_5)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
}
|
||||||
w.Write(forum_6)
|
w.Write(forum_6)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page + 1)))
|
if tmpl_forum_vars.CurrentUser.ID != 0 {
|
||||||
w.Write(forum_7)
|
w.Write(forum_7)
|
||||||
}
|
}
|
||||||
w.Write(forum_8)
|
w.Write(forum_8)
|
||||||
if tmpl_forum_vars.CurrentUser.ID != 0 {
|
|
||||||
w.Write(forum_9)
|
|
||||||
}
|
|
||||||
w.Write(forum_10)
|
|
||||||
w.Write([]byte(tmpl_forum_vars.Title))
|
w.Write([]byte(tmpl_forum_vars.Title))
|
||||||
|
w.Write(forum_9)
|
||||||
|
if tmpl_forum_vars.CurrentUser.ID != 0 {
|
||||||
|
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
||||||
|
w.Write(forum_10)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||||
w.Write(forum_11)
|
w.Write(forum_11)
|
||||||
if tmpl_forum_vars.CurrentUser.ID != 0 {
|
|
||||||
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
|
||||||
w.Write(forum_12)
|
w.Write(forum_12)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
|
||||||
w.Write(forum_13)
|
|
||||||
w.Write(forum_14)
|
|
||||||
} else {
|
} else {
|
||||||
|
w.Write(forum_13)
|
||||||
|
}
|
||||||
|
w.Write(forum_14)
|
||||||
|
}
|
||||||
w.Write(forum_15)
|
w.Write(forum_15)
|
||||||
}
|
|
||||||
w.Write(forum_16)
|
|
||||||
}
|
|
||||||
w.Write(forum_17)
|
|
||||||
if tmpl_forum_vars.CurrentUser.ID != 0 {
|
if tmpl_forum_vars.CurrentUser.ID != 0 {
|
||||||
w.Write(forum_18)
|
w.Write(forum_16)
|
||||||
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
||||||
w.Write(forum_19)
|
w.Write(forum_17)
|
||||||
w.Write([]byte(tmpl_forum_vars.CurrentUser.Avatar))
|
w.Write([]byte(tmpl_forum_vars.CurrentUser.Avatar))
|
||||||
w.Write(forum_20)
|
w.Write(forum_18)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||||
w.Write(forum_21)
|
w.Write(forum_19)
|
||||||
if tmpl_forum_vars.CurrentUser.Perms.UploadFiles {
|
if tmpl_forum_vars.CurrentUser.Perms.UploadFiles {
|
||||||
|
w.Write(forum_20)
|
||||||
|
}
|
||||||
|
w.Write(forum_21)
|
||||||
|
}
|
||||||
|
}
|
||||||
w.Write(forum_22)
|
w.Write(forum_22)
|
||||||
}
|
|
||||||
w.Write(forum_23)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.Write(forum_24)
|
|
||||||
if len(tmpl_forum_vars.ItemList) != 0 {
|
if len(tmpl_forum_vars.ItemList) != 0 {
|
||||||
for _, item := range tmpl_forum_vars.ItemList {
|
for _, item := range tmpl_forum_vars.ItemList {
|
||||||
w.Write(forum_25)
|
w.Write(forum_23)
|
||||||
w.Write([]byte(strconv.Itoa(item.ID)))
|
w.Write([]byte(strconv.Itoa(item.ID)))
|
||||||
|
w.Write(forum_24)
|
||||||
|
if item.Sticky {
|
||||||
|
w.Write(forum_25)
|
||||||
|
} else {
|
||||||
|
if item.IsClosed {
|
||||||
w.Write(forum_26)
|
w.Write(forum_26)
|
||||||
if item.Sticky {
|
}
|
||||||
|
}
|
||||||
w.Write(forum_27)
|
w.Write(forum_27)
|
||||||
} else {
|
w.Write([]byte(item.Creator.Link))
|
||||||
if item.IsClosed {
|
|
||||||
w.Write(forum_28)
|
w.Write(forum_28)
|
||||||
}
|
|
||||||
}
|
|
||||||
w.Write(forum_29)
|
|
||||||
w.Write([]byte(item.Creator.Link))
|
|
||||||
w.Write(forum_30)
|
|
||||||
w.Write([]byte(item.Creator.Avatar))
|
w.Write([]byte(item.Creator.Avatar))
|
||||||
|
w.Write(forum_29)
|
||||||
|
w.Write([]byte(item.Creator.Name))
|
||||||
|
w.Write(forum_30)
|
||||||
|
w.Write([]byte(item.Creator.Name))
|
||||||
w.Write(forum_31)
|
w.Write(forum_31)
|
||||||
w.Write([]byte(item.Creator.Name))
|
|
||||||
w.Write(forum_32)
|
|
||||||
w.Write([]byte(item.Creator.Name))
|
|
||||||
w.Write(forum_33)
|
|
||||||
w.Write([]byte(item.Link))
|
w.Write([]byte(item.Link))
|
||||||
w.Write(forum_34)
|
w.Write(forum_32)
|
||||||
w.Write([]byte(item.Title))
|
w.Write([]byte(item.Title))
|
||||||
w.Write(forum_35)
|
w.Write(forum_33)
|
||||||
w.Write([]byte(item.Creator.Link))
|
w.Write([]byte(item.Creator.Link))
|
||||||
w.Write(forum_36)
|
w.Write(forum_34)
|
||||||
w.Write([]byte(item.Creator.Name))
|
w.Write([]byte(item.Creator.Name))
|
||||||
w.Write(forum_37)
|
w.Write(forum_35)
|
||||||
if item.IsClosed {
|
if item.IsClosed {
|
||||||
|
w.Write(forum_36)
|
||||||
|
}
|
||||||
|
if item.Sticky {
|
||||||
|
w.Write(forum_37)
|
||||||
|
}
|
||||||
w.Write(forum_38)
|
w.Write(forum_38)
|
||||||
}
|
|
||||||
if item.Sticky {
|
|
||||||
w.Write(forum_39)
|
|
||||||
}
|
|
||||||
w.Write(forum_40)
|
|
||||||
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
w.Write([]byte(strconv.Itoa(item.PostCount)))
|
||||||
w.Write(forum_41)
|
w.Write(forum_39)
|
||||||
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
w.Write([]byte(strconv.Itoa(item.LikeCount)))
|
||||||
w.Write(forum_42)
|
w.Write(forum_40)
|
||||||
if item.Sticky {
|
if item.Sticky {
|
||||||
w.Write(forum_43)
|
w.Write(forum_41)
|
||||||
} else {
|
} else {
|
||||||
if item.IsClosed {
|
if item.IsClosed {
|
||||||
w.Write(forum_44)
|
w.Write(forum_42)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Write(forum_45)
|
w.Write(forum_43)
|
||||||
w.Write([]byte(item.LastUser.Link))
|
w.Write([]byte(item.LastUser.Link))
|
||||||
w.Write(forum_46)
|
w.Write(forum_44)
|
||||||
w.Write([]byte(item.LastUser.Avatar))
|
w.Write([]byte(item.LastUser.Avatar))
|
||||||
w.Write(forum_47)
|
w.Write(forum_45)
|
||||||
w.Write([]byte(item.LastUser.Name))
|
w.Write([]byte(item.LastUser.Name))
|
||||||
|
w.Write(forum_46)
|
||||||
|
w.Write([]byte(item.LastUser.Name))
|
||||||
|
w.Write(forum_47)
|
||||||
|
w.Write([]byte(item.LastUser.Link))
|
||||||
w.Write(forum_48)
|
w.Write(forum_48)
|
||||||
w.Write([]byte(item.LastUser.Name))
|
w.Write([]byte(item.LastUser.Name))
|
||||||
w.Write(forum_49)
|
w.Write(forum_49)
|
||||||
w.Write([]byte(item.LastUser.Link))
|
|
||||||
w.Write(forum_50)
|
|
||||||
w.Write([]byte(item.LastUser.Name))
|
|
||||||
w.Write(forum_51)
|
|
||||||
w.Write([]byte(item.RelativeLastReplyAt))
|
w.Write([]byte(item.RelativeLastReplyAt))
|
||||||
w.Write(forum_52)
|
w.Write(forum_50)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.Write(forum_53)
|
w.Write(forum_51)
|
||||||
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
if tmpl_forum_vars.CurrentUser.Perms.CreateTopic {
|
||||||
w.Write(forum_54)
|
w.Write(forum_52)
|
||||||
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Forum.ID)))
|
||||||
|
w.Write(forum_53)
|
||||||
|
}
|
||||||
|
w.Write(forum_54)
|
||||||
|
}
|
||||||
w.Write(forum_55)
|
w.Write(forum_55)
|
||||||
}
|
if tmpl_forum_vars.LastPage > 1 {
|
||||||
w.Write(forum_56)
|
w.Write(forum_56)
|
||||||
}
|
if tmpl_forum_vars.Page > 1 {
|
||||||
w.Write(forum_57)
|
w.Write(forum_57)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page - 1)))
|
||||||
|
w.Write(forum_58)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page - 1)))
|
||||||
|
w.Write(forum_59)
|
||||||
|
}
|
||||||
|
if len(tmpl_forum_vars.PageList) != 0 {
|
||||||
|
for _, item := range tmpl_forum_vars.PageList {
|
||||||
|
w.Write(forum_60)
|
||||||
|
w.Write([]byte(strconv.Itoa(item)))
|
||||||
|
w.Write(forum_61)
|
||||||
|
w.Write([]byte(strconv.Itoa(item)))
|
||||||
|
w.Write(forum_62)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tmpl_forum_vars.LastPage != tmpl_forum_vars.Page {
|
||||||
|
w.Write(forum_63)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page + 1)))
|
||||||
|
w.Write(forum_64)
|
||||||
|
w.Write([]byte(strconv.Itoa(tmpl_forum_vars.Page + 1)))
|
||||||
|
w.Write(forum_65)
|
||||||
|
}
|
||||||
|
w.Write(forum_66)
|
||||||
|
}
|
||||||
|
w.Write(forum_67)
|
||||||
w.Write(footer_0)
|
w.Write(footer_0)
|
||||||
w.Write([]byte(common.BuildWidget("footer",tmpl_forum_vars.Header)))
|
w.Write([]byte(common.BuildWidget("footer",tmpl_forum_vars.Header)))
|
||||||
w.Write(footer_1)
|
w.Write(footer_1)
|
||||||
|
|
138
template_list.go
138
template_list.go
|
@ -1114,11 +1114,10 @@ var topics_62 = []byte(`
|
||||||
var topics_63 = []byte(`
|
var topics_63 = []byte(`
|
||||||
<div class="pageset">
|
<div class="pageset">
|
||||||
`)
|
`)
|
||||||
var topics_64 = []byte(`
|
var topics_64 = []byte(`<div class="pageitem"><a href="?page=`)
|
||||||
|
var topics_65 = []byte(`" rel="prev" aria-label="Go to the previous page">Prev</a></div>
|
||||||
<link rel="prev" href="?page=`)
|
<link rel="prev" href="?page=`)
|
||||||
var topics_65 = []byte(`" />
|
var topics_66 = []byte(`" />`)
|
||||||
<div class="pageitem"><a href="?page=`)
|
|
||||||
var topics_66 = []byte(`" rel="prev" aria-label="Go to the previous page">Prev</a></div>`)
|
|
||||||
var topics_67 = []byte(`
|
var topics_67 = []byte(`
|
||||||
<div class="pageitem"><a href="?page=`)
|
<div class="pageitem"><a href="?page=`)
|
||||||
var topics_68 = []byte(`">`)
|
var topics_68 = []byte(`">`)
|
||||||
|
@ -1139,41 +1138,38 @@ var topics_74 = []byte(`
|
||||||
var forum_0 = []byte(`<div id="prevFloat" class="prev_button"><a class="prev_link" aria-label="Go to the previous page" rel="prev" href="/forum/`)
|
var forum_0 = []byte(`<div id="prevFloat" class="prev_button"><a class="prev_link" aria-label="Go to the previous page" rel="prev" href="/forum/`)
|
||||||
var forum_1 = []byte(`?page=`)
|
var forum_1 = []byte(`?page=`)
|
||||||
var forum_2 = []byte(`"><</a></div>`)
|
var forum_2 = []byte(`"><</a></div>`)
|
||||||
var forum_3 = []byte(`<link rel="prerender" href="/forum/`)
|
var forum_3 = []byte(`<div id="nextFloat" class="next_button"><a class="next_link" aria-label="Go to the next page" rel="next" href="/forum/`)
|
||||||
var forum_4 = []byte(`?page=`)
|
var forum_4 = []byte(`?page=`)
|
||||||
var forum_5 = []byte(`" />
|
var forum_5 = []byte(`">></a></div>`)
|
||||||
<div id="nextFloat" class="next_button"><a class="next_link" aria-label="Go to the next page" rel="next" href="/forum/`)
|
var forum_6 = []byte(`
|
||||||
var forum_6 = []byte(`?page=`)
|
|
||||||
var forum_7 = []byte(`">></a></div>`)
|
|
||||||
var forum_8 = []byte(`
|
|
||||||
|
|
||||||
<main itemscope itemtype="http://schema.org/ItemList">
|
<main itemscope itemtype="http://schema.org/ItemList">
|
||||||
<div id="forum_head_block" class="rowblock rowhead topic_list_title_block">
|
<div id="forum_head_block" class="rowblock rowhead topic_list_title_block">
|
||||||
<div class="rowitem forum_title`)
|
<div class="rowitem forum_title`)
|
||||||
var forum_9 = []byte(` has_opt`)
|
var forum_7 = []byte(` has_opt`)
|
||||||
var forum_10 = []byte(`">
|
var forum_8 = []byte(`">
|
||||||
<h1 itemprop="name">`)
|
<h1 itemprop="name">`)
|
||||||
var forum_11 = []byte(`</h1>
|
var forum_9 = []byte(`</h1>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
var forum_12 = []byte(`
|
var forum_10 = []byte(`
|
||||||
<div class="pre_opt auto_hide"></div>
|
<div class="pre_opt auto_hide"></div>
|
||||||
<div class="opt create_topic_opt" title="Create Topic" aria-label="Create a topic"><a class="create_topic_link" href="/topics/create/`)
|
<div class="opt create_topic_opt" title="Create Topic" aria-label="Create a topic"><a class="create_topic_link" href="/topics/create/`)
|
||||||
var forum_13 = []byte(`"></a></div>
|
var forum_11 = []byte(`"></a></div>
|
||||||
`)
|
`)
|
||||||
var forum_14 = []byte(`
|
var forum_12 = []byte(`
|
||||||
<div class="opt mod_opt" title="Moderate">
|
<div class="opt mod_opt" title="Moderate">
|
||||||
<a class="moderate_link" href="#" aria-label="Moderate Posts"></a>
|
<a class="moderate_link" href="#" aria-label="Moderate Posts"></a>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
var forum_15 = []byte(`<div class="opt locked_opt" title="You don't have the permissions needed to create a topic" aria-label="You don't have the permissions needed to make a topic in this forum"><a></a></div>`)
|
var forum_13 = []byte(`<div class="opt locked_opt" title="You don't have the permissions needed to create a topic" aria-label="You don't have the permissions needed to make a topic in this forum"><a></a></div>`)
|
||||||
var forum_16 = []byte(`
|
var forum_14 = []byte(`
|
||||||
<div style="clear: both;"></div>
|
<div style="clear: both;"></div>
|
||||||
`)
|
`)
|
||||||
var forum_17 = []byte(`
|
var forum_15 = []byte(`
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
var forum_18 = []byte(`
|
var forum_16 = []byte(`
|
||||||
<div class="mod_floater auto_hide">
|
<div class="mod_floater auto_hide">
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div class="mod_floater_head">
|
<div class="mod_floater_head">
|
||||||
|
@ -1190,13 +1186,13 @@ var forum_18 = []byte(`
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
var forum_19 = []byte(`
|
var forum_17 = []byte(`
|
||||||
<div id="forum_topic_create_form" class="rowblock topic_create_form quick_create_form" style="display: none;" aria-label="Quick Topic Form">
|
<div id="forum_topic_create_form" class="rowblock topic_create_form quick_create_form" style="display: none;" aria-label="Quick Topic Form">
|
||||||
<form id="quick_post_form" enctype="multipart/form-data" action="/topic/create/submit/" method="post"></form>
|
<form id="quick_post_form" enctype="multipart/form-data" action="/topic/create/submit/" method="post"></form>
|
||||||
<img class="little_row_avatar" src="`)
|
<img class="little_row_avatar" src="`)
|
||||||
var forum_20 = []byte(`" height="64" alt="Your Avatar" title="Your Avatar" />
|
var forum_18 = []byte(`" height="64" alt="Your Avatar" title="Your Avatar" />
|
||||||
<input form="quick_post_form" id="topic_board_input" name="topic-board" value="`)
|
<input form="quick_post_form" id="topic_board_input" name="topic-board" value="`)
|
||||||
var forum_21 = []byte(`" type="hidden">
|
var forum_19 = []byte(`" type="hidden">
|
||||||
<div class="main_form">
|
<div class="main_form">
|
||||||
<div class="topic_meta">
|
<div class="topic_meta">
|
||||||
<div class="formrow topic_name_row real_first_child">
|
<div class="formrow topic_name_row real_first_child">
|
||||||
|
@ -1220,75 +1216,99 @@ var forum_21 = []byte(`" type="hidden">
|
||||||
<button form="quick_post_form" name="topic-button" class="formbutton">Create Topic</button>
|
<button form="quick_post_form" name="topic-button" class="formbutton">Create Topic</button>
|
||||||
<button form="quick_post_form" class="formbutton" id="add_poll_button">Add Poll</button>
|
<button form="quick_post_form" class="formbutton" id="add_poll_button">Add Poll</button>
|
||||||
`)
|
`)
|
||||||
var forum_22 = []byte(`
|
var forum_20 = []byte(`
|
||||||
<input name="upload_files" form="quick_post_form" id="upload_files" multiple type="file" style="display: none;" />
|
<input name="upload_files" form="quick_post_form" id="upload_files" multiple type="file" style="display: none;" />
|
||||||
<label for="upload_files" class="formbutton add_file_button">Add File</label>
|
<label for="upload_files" class="formbutton add_file_button">Add File</label>
|
||||||
<div id="upload_file_dock"></div>`)
|
<div id="upload_file_dock"></div>`)
|
||||||
var forum_23 = []byte(`
|
var forum_21 = []byte(`
|
||||||
<button class="formbutton close_form">Cancel</button>
|
<button class="formbutton close_form">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`)
|
`)
|
||||||
var forum_24 = []byte(`
|
var forum_22 = []byte(`
|
||||||
<div id="forum_topic_list" class="rowblock topic_list">
|
<div id="forum_topic_list" class="rowblock topic_list">
|
||||||
`)
|
`)
|
||||||
var forum_25 = []byte(`<div class="topic_row" data-tid="`)
|
var forum_23 = []byte(`<div class="topic_row" data-tid="`)
|
||||||
var forum_26 = []byte(`">
|
var forum_24 = []byte(`">
|
||||||
<div class="rowitem topic_left passive datarow `)
|
<div class="rowitem topic_left passive datarow `)
|
||||||
var forum_27 = []byte(`topic_sticky`)
|
var forum_25 = []byte(`topic_sticky`)
|
||||||
var forum_28 = []byte(`topic_closed`)
|
var forum_26 = []byte(`topic_closed`)
|
||||||
var forum_29 = []byte(`">
|
var forum_27 = []byte(`">
|
||||||
<span class="selector"></span>
|
<span class="selector"></span>
|
||||||
<a href="`)
|
<a href="`)
|
||||||
var forum_30 = []byte(`"><img src="`)
|
var forum_28 = []byte(`"><img src="`)
|
||||||
var forum_31 = []byte(`" height="64" alt="`)
|
var forum_29 = []byte(`" height="64" alt="`)
|
||||||
var forum_32 = []byte(`'s Avatar" title="`)
|
var forum_30 = []byte(`'s Avatar" title="`)
|
||||||
var forum_33 = []byte(`'s Avatar" /></a>
|
var forum_31 = []byte(`'s Avatar" /></a>
|
||||||
<span class="topic_inner_left">
|
<span class="topic_inner_left">
|
||||||
<a class="rowtopic" href="`)
|
<a class="rowtopic" href="`)
|
||||||
var forum_34 = []byte(`" itemprop="itemListElement"><span>`)
|
var forum_32 = []byte(`" itemprop="itemListElement"><span>`)
|
||||||
var forum_35 = []byte(`</span></a>
|
var forum_33 = []byte(`</span></a>
|
||||||
<br /><a class="rowsmall starter" href="`)
|
<br /><a class="rowsmall starter" href="`)
|
||||||
var forum_36 = []byte(`">`)
|
var forum_34 = []byte(`">`)
|
||||||
var forum_37 = []byte(`</a>
|
var forum_35 = []byte(`</a>
|
||||||
`)
|
`)
|
||||||
var forum_38 = []byte(`<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎</span>`)
|
var forum_36 = []byte(`<span class="rowsmall topic_status_e topic_status_closed" title="Status: Closed"> | 🔒︎</span>`)
|
||||||
var forum_39 = []byte(`<span class="rowsmall topic_status_e topic_status_sticky" title="Status: Pinned"> | 📍︎</span>`)
|
var forum_37 = []byte(`<span class="rowsmall topic_status_e topic_status_sticky" title="Status: Pinned"> | 📍︎</span>`)
|
||||||
var forum_40 = []byte(`
|
var forum_38 = []byte(`
|
||||||
</span>
|
</span>
|
||||||
<span class="topic_inner_right rowsmall" style="float: right;">
|
<span class="topic_inner_right rowsmall" style="float: right;">
|
||||||
<span class="replyCount">`)
|
<span class="replyCount">`)
|
||||||
var forum_41 = []byte(`</span><br />
|
var forum_39 = []byte(`</span><br />
|
||||||
<span class="likeCount">`)
|
<span class="likeCount">`)
|
||||||
var forum_42 = []byte(`</span>
|
var forum_40 = []byte(`</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="rowitem topic_right passive datarow `)
|
<div class="rowitem topic_right passive datarow `)
|
||||||
var forum_43 = []byte(`topic_sticky`)
|
var forum_41 = []byte(`topic_sticky`)
|
||||||
var forum_44 = []byte(`topic_closed`)
|
var forum_42 = []byte(`topic_closed`)
|
||||||
var forum_45 = []byte(`">
|
var forum_43 = []byte(`">
|
||||||
<a href="`)
|
<a href="`)
|
||||||
var forum_46 = []byte(`"><img src="`)
|
var forum_44 = []byte(`"><img src="`)
|
||||||
var forum_47 = []byte(`" height="64" alt="`)
|
var forum_45 = []byte(`" height="64" alt="`)
|
||||||
var forum_48 = []byte(`'s Avatar" title="`)
|
var forum_46 = []byte(`'s Avatar" title="`)
|
||||||
var forum_49 = []byte(`'s Avatar" /></a>
|
var forum_47 = []byte(`'s Avatar" /></a>
|
||||||
<span>
|
<span>
|
||||||
<a href="`)
|
<a href="`)
|
||||||
var forum_50 = []byte(`" class="lastName" style="font-size: 14px;">`)
|
var forum_48 = []byte(`" class="lastName" style="font-size: 14px;">`)
|
||||||
var forum_51 = []byte(`</a><br>
|
var forum_49 = []byte(`</a><br>
|
||||||
<span class="rowsmall lastReplyAt">`)
|
<span class="rowsmall lastReplyAt">`)
|
||||||
var forum_52 = []byte(`</span>
|
var forum_50 = []byte(`</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>`)
|
</div>`)
|
||||||
var forum_53 = []byte(`<div class="rowitem passive">There aren't any topics in this forum yet.`)
|
var forum_51 = []byte(`<div class="rowitem passive">There aren't any topics in this forum yet.`)
|
||||||
var forum_54 = []byte(` <a href="/topics/create/`)
|
var forum_52 = []byte(` <a href="/topics/create/`)
|
||||||
var forum_55 = []byte(`">Start one?</a>`)
|
var forum_53 = []byte(`">Start one?</a>`)
|
||||||
var forum_56 = []byte(`</div>`)
|
var forum_54 = []byte(`</div>`)
|
||||||
var forum_57 = []byte(`
|
var forum_55 = []byte(`
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
`)
|
||||||
|
var forum_56 = []byte(`
|
||||||
|
<div class="pageset">
|
||||||
|
`)
|
||||||
|
var forum_57 = []byte(`<div class="pageitem"><a href="?page=`)
|
||||||
|
var forum_58 = []byte(`" rel="prev" aria-label="Go to the previous page">Prev</a></div>
|
||||||
|
<link rel="prev" href="?page=`)
|
||||||
|
var forum_59 = []byte(`" />`)
|
||||||
|
var forum_60 = []byte(`
|
||||||
|
<div class="pageitem"><a href="?page=`)
|
||||||
|
var forum_61 = []byte(`">`)
|
||||||
|
var forum_62 = []byte(`</a></div>
|
||||||
|
`)
|
||||||
|
var forum_63 = []byte(`
|
||||||
|
<link rel="next" href="?page=`)
|
||||||
|
var forum_64 = []byte(`" />
|
||||||
|
<div class="pageitem"><a href="?page=`)
|
||||||
|
var forum_65 = []byte(`" rel="next" aria-label="Go to the next page">Next</a></div>`)
|
||||||
|
var forum_66 = []byte(`
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
var forum_67 = []byte(`
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
`)
|
`)
|
||||||
var guilds_guild_list_0 = []byte(`
|
var guilds_guild_list_0 = []byte(`
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
{{template "header.html" . }}
|
{{template "header.html" . }}
|
||||||
|
|
||||||
{{if gt .Page 1}}<div id="prevFloat" class="prev_button"><a class="prev_link" aria-label="Go to the previous page" rel="prev" href="/forum/{{.Forum.ID}}?page={{subtract .Page 1}}"><</a></div>{{end}}
|
{{if gt .Page 1}}<div id="prevFloat" class="prev_button"><a class="prev_link" aria-label="Go to the previous page" rel="prev" href="/forum/{{.Forum.ID}}?page={{subtract .Page 1}}"><</a></div>{{end}}
|
||||||
{{if ne .LastPage .Page}}<link rel="prerender" href="/forum/{{.Forum.ID}}?page={{add .Page 1}}" />
|
{{if ne .LastPage .Page}}<div id="nextFloat" class="next_button"><a class="next_link" aria-label="Go to the next page" rel="next" href="/forum/{{.Forum.ID}}?page={{add .Page 1}}">></a></div>{{end}}
|
||||||
<div id="nextFloat" class="next_button"><a class="next_link" aria-label="Go to the next page" rel="next" href="/forum/{{.Forum.ID}}?page={{add .Page 1}}">></a></div>{{end}}
|
|
||||||
|
|
||||||
<main itemscope itemtype="http://schema.org/ItemList">
|
<main itemscope itemtype="http://schema.org/ItemList">
|
||||||
<div id="forum_head_block" class="rowblock rowhead topic_list_title_block">
|
<div id="forum_head_block" class="rowblock rowhead topic_list_title_block">
|
||||||
|
@ -101,5 +100,19 @@
|
||||||
</div>
|
</div>
|
||||||
</div>{{else}}<div class="rowitem passive">There aren't any topics in this forum yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/{{.Forum.ID}}">Start one?</a>{{end}}</div>{{end}}
|
</div>{{else}}<div class="rowitem passive">There aren't any topics in this forum yet.{{if .CurrentUser.Perms.CreateTopic}} <a href="/topics/create/{{.Forum.ID}}">Start one?</a>{{end}}</div>{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{if gt .LastPage 1}}
|
||||||
|
<div class="pageset">
|
||||||
|
{{if gt .Page 1}}<div class="pageitem"><a href="?page={{subtract .Page 1}}" rel="prev" aria-label="Go to the previous page">Prev</a></div>
|
||||||
|
<link rel="prev" href="?page={{subtract .Page 1}}" />{{end}}
|
||||||
|
{{range .PageList}}
|
||||||
|
<div class="pageitem"><a href="?page={{.}}">{{.}}</a></div>
|
||||||
|
{{end}}
|
||||||
|
{{if ne .LastPage .Page}}
|
||||||
|
<link rel="next" href="?page={{add .Page 1}}" />
|
||||||
|
<div class="pageitem"><a href="?page={{add .Page 1}}" rel="next" aria-label="Go to the next page">Next</a></div>{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
{{template "footer.html" . }}
|
{{template "footer.html" . }}
|
||||||
|
|
|
@ -128,9 +128,8 @@
|
||||||
|
|
||||||
{{if gt .LastPage 1}}
|
{{if gt .LastPage 1}}
|
||||||
<div class="pageset">
|
<div class="pageset">
|
||||||
{{if gt .Page 1}}
|
{{if gt .Page 1}}<div class="pageitem"><a href="?page={{subtract .Page 1}}" rel="prev" aria-label="Go to the previous page">Prev</a></div>
|
||||||
<link rel="prev" href="?page={{subtract .Page 1}}" />
|
<link rel="prev" href="?page={{subtract .Page 1}}" />{{end}}
|
||||||
<div class="pageitem"><a href="?page={{subtract .Page 1}}" rel="prev" aria-label="Go to the previous page">Prev</a></div>{{end}}
|
|
||||||
{{range .PageList}}
|
{{range .PageList}}
|
||||||
<div class="pageitem"><a href="?page={{.}}">{{.}}</a></div>
|
<div class="pageitem"><a href="?page={{.}}">{{.}}</a></div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -484,7 +484,7 @@ textarea.large {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
width: calc(100% - 16px);
|
width: calc(100% - 16px);
|
||||||
}
|
}
|
||||||
.formitem select {
|
select {
|
||||||
background-color: var(--input-background-color);
|
background-color: var(--input-background-color);
|
||||||
border: 1px solid var(--input-border-color);
|
border: 1px solid var(--input-border-color);
|
||||||
color: var(--input-text-color);
|
color: var(--input-text-color);
|
||||||
|
@ -613,6 +613,13 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||||
margin-left: 3px;
|
margin-left: 3px;
|
||||||
background: var(--bright-input-border-color);
|
background: var(--bright-input-border-color);
|
||||||
}
|
}
|
||||||
|
.pollinput {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.quick_create_form .pollinputlabel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/*#poll_option_text_0 {
|
/*#poll_option_text_0 {
|
||||||
color: hsl(359,98%,43%);
|
color: hsl(359,98%,43%);
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timeRangeSelector {
|
||||||
|
padding: 2px;
|
||||||
|
margin-top: -3px;
|
||||||
|
margin-bottom: -3px;
|
||||||
|
}
|
||||||
.panel_floater {
|
.panel_floater {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -488,24 +488,24 @@ li a {
|
||||||
.little_row_avatar {
|
.little_row_avatar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.topic_create_form .topic_button_row .formitem {
|
.quick_create_form .quick_button_row .formitem {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.topic_create_form .formbutton:first-child {
|
.quick_create_form .formbutton:first-child {
|
||||||
margin-left: 0px;
|
margin-left: 0px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
.topic_create_form .formbutton:not(:first-child) {
|
.quick_create_form .formbutton:not(:first-child) {
|
||||||
margin-left: 0px;
|
margin-left: 0px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
.topic_create_form .formbutton:last-child {
|
.quick_create_form .formbutton:last-child {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
.topic_create_form .upload_file_dock {
|
.quick_create_form .upload_file_dock {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
.topic_create_form .uploadItem {
|
.quick_create_form .uploadItem {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
@ -765,6 +765,51 @@ button.username {
|
||||||
border-bottom: 1.5px inset var(--main-border-color);
|
border-bottom: 1.5px inset var(--main-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Show the avatar next to the reply form */
|
||||||
|
.topic_reply_container .userinfo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=checkbox] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
input[type=checkbox] + label {
|
||||||
|
display: inline-block;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
margin-bottom: -2px;
|
||||||
|
border: 1px solid hsl(0, 0%, 80%);
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:checked + label .sel {
|
||||||
|
display: inline-block;
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
input[type=checkbox] + label.poll_option_label {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin-right: 2px;
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid hsl(0, 0%, 70%);
|
||||||
|
color: #505050;
|
||||||
|
}
|
||||||
|
input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||||
|
display: inline-block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-left: 3px;
|
||||||
|
background: hsl(0,0%,70%);
|
||||||
|
}
|
||||||
|
.poll_option {
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick_create_form .pollinputlabel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.simple {
|
.simple {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
@ -945,7 +990,7 @@ button.username {
|
||||||
.pageset {
|
.pageset {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
margin-top: -5px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.pageitem {
|
.pageitem {
|
||||||
border: 1px solid var(--main-border-color);
|
border: 1px solid var(--main-border-color);
|
||||||
|
@ -958,6 +1003,9 @@ button.username {
|
||||||
color: black;
|
color: black;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
.colstack_right .pageset {
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Firefox specific CSS */
|
/* Firefox specific CSS */
|
||||||
@supports (-moz-appearance: none) {
|
@supports (-moz-appearance: none) {
|
||||||
|
|
|
@ -372,8 +372,18 @@ li a {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input, select {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
/* Mostly for textareas */
|
/* Mostly for textareas */
|
||||||
.formitem:only-child { width: 100%; }
|
.formitem:only-child {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.formitem:only-child select {
|
||||||
|
padding: 1px;
|
||||||
|
margin-top: -1px;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
}
|
||||||
.formitem textarea {
|
.formitem textarea {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
|
@ -383,9 +393,6 @@ li a {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
.formitem:not(:only-child) input, .formitem:not(:only-child) select {
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
.formitem:not(:only-child).formlabel {
|
.formitem:not(:only-child).formlabel {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
|
@ -417,6 +424,9 @@ li a {
|
||||||
|
|
||||||
/* Topics */
|
/* Topics */
|
||||||
|
|
||||||
|
.topic_list {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
.topic_list .topic_row {
|
.topic_list .topic_row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: calc(100% - 204px) 204px;
|
grid-template-columns: calc(100% - 204px) 204px;
|
||||||
|
@ -737,6 +747,10 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.quick_create_form .pollinputlabel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
@ -869,7 +883,7 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||||
.pageset {
|
.pageset {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
margin-top: -5px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.pageitem {
|
.pageitem {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
@ -882,5 +896,8 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
||||||
color: black;
|
color: black;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
.colstack_right .pageset {
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
{{template "media.partial.css" }}
|
{{template "media.partial.css" }}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
/* Control Panel */
|
.submenu a {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.edit_button:before {
|
.edit_button:before {
|
||||||
content: "Edit";
|
content: "Edit";
|
||||||
|
@ -125,4 +127,14 @@
|
||||||
content: " || ";
|
content: " || ";
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
.ct_chart {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-top: 14px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
padding-right: 10px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid hsl(0,0%,85%);
|
||||||
}
|
}
|
Loading…
Reference in New Issue