new modtools ux
- don't allow users to select things they shouldn't be able to - hide mod options the user doesn't have access to - highlight options which can be selected - stop counting topics twice when they're clicked on multiple times fix modtools not opening in some cases fix command orders in batch files fix global.js's getExt() reduce boilerplate
This commit is contained in:
parent
6260dbced7
commit
be609b47ce
|
@ -202,20 +202,25 @@ type TopicListSort struct {
|
|||
Ascending bool
|
||||
}
|
||||
|
||||
type QuickTools struct {
|
||||
CanDelete bool
|
||||
CanLock bool
|
||||
CanMove bool
|
||||
}
|
||||
|
||||
type TopicListPage struct {
|
||||
*Header
|
||||
TopicList []*TopicsRow
|
||||
TopicList []TopicsRowMut
|
||||
ForumList []Forum
|
||||
DefaultForum int
|
||||
Sort TopicListSort
|
||||
CanLock bool
|
||||
CanMove bool
|
||||
QuickTools
|
||||
Paginator
|
||||
}
|
||||
|
||||
type ForumPage struct {
|
||||
*Header
|
||||
ItemList []*TopicsRow
|
||||
ItemList []TopicsRowMut
|
||||
Forum *Forum
|
||||
CanLock bool
|
||||
CanMove bool
|
||||
|
|
|
@ -226,9 +226,9 @@ func compileCommons(c *tmpl.CTemplateSet, head, head2 *Header, forumList []Forum
|
|||
return head2
|
||||
}*/
|
||||
|
||||
var topicsList []*TopicsRow
|
||||
topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, 0, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil})
|
||||
topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, false, false, Paginator{[]int{1}, 1, 1}}
|
||||
var topicsList []TopicsRowMut
|
||||
topicsList = append(topicsList, TopicsRowMut{&TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 1, 0, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil}, false})
|
||||
topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, QuickTools{false, false, false}, Paginator{[]int{1}, 1, 1}}
|
||||
o.Add("topics", "c.TopicListPage", topicListPage)
|
||||
o.Add("topics_mini", "c.TopicListPage", topicListPage)
|
||||
|
||||
|
@ -309,9 +309,9 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
|||
ppage := ProfilePage{htitle("User 526"), replyList, *user, 0, 0, false, false, false, false} // TODO: Use the score from user to generate the currentScore and nextScore
|
||||
t.Add("profile", "c.ProfilePage", ppage)
|
||||
|
||||
var topicsList []*TopicsRow
|
||||
topicsList = append(topicsList, &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "127.0.0.1", 1, 0, 1, 1, 0, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil})
|
||||
topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, false, false, Paginator{[]int{1}, 1, 1}}
|
||||
var topicsList []TopicsRowMut
|
||||
topicsList = append(topicsList, TopicsRowMut{&TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "127.0.0.1", 1, 0, 1, 1, 0, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil}, false})
|
||||
topicListPage := TopicListPage{htitle("Topic List"), topicsList, forumList, Config.DefaultForum, TopicListSort{"lastupdated", false}, QuickTools{false, false, false}, Paginator{[]int{1}, 1, 1}}
|
||||
|
||||
forumItem := BlankForum(1, "general-forum.1", "General Forum", "Where the general stuff happens", true, "all", 0, "", 0)
|
||||
forumPage := ForumPage{htitle("General Forum"), topicsList, forumItem, false, false, Paginator{[]int{1}, 1, 1}}
|
||||
|
@ -538,8 +538,8 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
|
|||
|
||||
t := TItemHold(make(map[string]TItem))
|
||||
|
||||
topicsRow := &TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 0, 1, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil}
|
||||
t.AddStd("topics_topic", "c.TopicsRow", topicsRow)
|
||||
topicsRow := TopicsRowMut{&TopicsRow{1, "topic-title", "Topic Title", "The topic content.", 1, false, false, now, now, user3.ID, 1, 1, "", "::1", 1, 0, 1, 0, 1, "classname", 0, "", user2, "", 0, user3, "General", "/forum/general.2", nil}, false}
|
||||
t.AddStd("topics_topic", "c.TopicsRowMut", topicsRow)
|
||||
|
||||
poll := Poll{ID: 1, Type: 0, Options: map[int]string{0: "Nothing", 1: "Something"}, Results: map[int]int{0: 5, 1: 2}, QuickOptions: []PollOption{
|
||||
PollOption{0, "Nothing"},
|
||||
|
|
|
@ -94,6 +94,11 @@ type TopicUser struct {
|
|||
Deletable bool
|
||||
}
|
||||
|
||||
type TopicsRowMut struct {
|
||||
*TopicsRow
|
||||
CanMod bool
|
||||
}
|
||||
|
||||
// TODO: Embed TopicUser to simplify this structure and it's related logic?
|
||||
type TopicsRow struct {
|
||||
ID int
|
||||
|
@ -151,11 +156,17 @@ type WsTopicsRow struct {
|
|||
LastUser *WsJSONUser
|
||||
ForumName string
|
||||
ForumLink string
|
||||
CanMod bool
|
||||
}
|
||||
|
||||
// TODO: Can we get the client side to render the relative times instead?
|
||||
func (r *TopicsRow) WebSockets() *WsTopicsRow {
|
||||
return &WsTopicsRow{r.ID, r.Link, r.Title, r.CreatedBy, r.IsClosed, r.Sticky, r.CreatedAt, r.LastReplyAt, RelativeTime(r.LastReplyAt), r.LastReplyBy, r.LastReplyID, r.ParentID, r.ViewCount, r.PostCount, r.LikeCount, r.AttachCount, r.ClassName, r.Creator.WebSockets(), r.LastUser.WebSockets(), r.ForumName, r.ForumLink}
|
||||
return &WsTopicsRow{r.ID, r.Link, r.Title, r.CreatedBy, r.IsClosed, r.Sticky, r.CreatedAt, r.LastReplyAt, RelativeTime(r.LastReplyAt), r.LastReplyBy, r.LastReplyID, r.ParentID, r.ViewCount, r.PostCount, r.LikeCount, r.AttachCount, r.ClassName, r.Creator.WebSockets(), r.LastUser.WebSockets(), r.ForumName, r.ForumLink, false}
|
||||
}
|
||||
|
||||
// TODO: Can we get the client side to render the relative times instead?
|
||||
func (r *TopicsRow) WebSockets2(canMod bool) *WsTopicsRow {
|
||||
return &WsTopicsRow{r.ID, r.Link, r.Title, r.CreatedBy, r.IsClosed, r.Sticky, r.CreatedAt, r.LastReplyAt, RelativeTime(r.LastReplyAt), r.LastReplyBy, r.LastReplyID, r.ParentID, r.ViewCount, r.PostCount, r.LikeCount, r.AttachCount, r.ClassName, r.Creator.WebSockets(), r.LastUser.WebSockets(), r.ForumName, r.ForumLink, canMod}
|
||||
}
|
||||
|
||||
// TODO: Stop relying on so many struct types?
|
||||
|
|
|
@ -151,6 +151,7 @@ func wsTopicListTick(h *WsHubImpl) error {
|
|||
}
|
||||
|
||||
canSeeRenders := make(map[string][]byte)
|
||||
canSeeLists := make(map[string][]*WsTopicsRow)
|
||||
for name, canSee := range canSeeMap {
|
||||
topicList, forumList, _, err := TopicList.GetListByCanSee(canSee, 1, 0, nil)
|
||||
if err != nil {
|
||||
|
@ -180,6 +181,7 @@ func wsTopicListTick(h *WsHubImpl) error {
|
|||
for i, topicRow := range topicList {
|
||||
wsTopicList[i] = topicRow.WebSockets()
|
||||
}
|
||||
canSeeLists[name] = wsTopicList
|
||||
|
||||
outBytes, err := json.Marshal(&WsTopicList{wsTopicList, 0, tickStart.Unix()})
|
||||
if err != nil {
|
||||
|
@ -191,17 +193,94 @@ func wsTopicListTick(h *WsHubImpl) error {
|
|||
// TODO: Use MessagePack for additional speed?
|
||||
//fmt.Println("writing to the clients")
|
||||
for _, wsUser := range currentWatchers {
|
||||
group := groups[wsUser.User.Group]
|
||||
u := wsUser.User
|
||||
group := groups[u.Group]
|
||||
canSee := make([]byte, len(group.CanSee))
|
||||
for i, item := range group.CanSee {
|
||||
canSee[i] = byte(item)
|
||||
}
|
||||
sCanSee := string(canSee)
|
||||
l := canSeeLists[sCanSee]
|
||||
|
||||
// TODO: Optimise this away for guests?
|
||||
anyMod, anyLock, anyMove, allMod := false, false, false, true
|
||||
var modSet map[int]int
|
||||
if u.IsSuperAdmin {
|
||||
anyMod = true
|
||||
anyLock = true
|
||||
anyMove = true
|
||||
} else {
|
||||
modSet = make(map[int]int, len(l))
|
||||
for i, t := range l {
|
||||
// TODO: Abstract this?
|
||||
fp, err := FPStore.Get(t.ParentID, u.Group)
|
||||
if err == ErrNoRows {
|
||||
fp = BlankForumPerms()
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
var ccanMod, ccanLock, ccanMove bool
|
||||
if fp.Overrides {
|
||||
ccanLock = fp.CloseTopic
|
||||
ccanMove = fp.MoveTopic
|
||||
ccanMod = t.CreatedBy == u.ID || fp.DeleteTopic || ccanLock || ccanMove
|
||||
} else {
|
||||
ccanLock = u.Perms.CloseTopic
|
||||
ccanMove = u.Perms.MoveTopic
|
||||
ccanMod = t.CreatedBy == u.ID || u.Perms.DeleteTopic || ccanLock || ccanMove
|
||||
}
|
||||
if ccanLock {
|
||||
anyLock = true
|
||||
}
|
||||
if ccanMove {
|
||||
anyMove = true
|
||||
}
|
||||
if ccanMod {
|
||||
anyMod = true
|
||||
} else {
|
||||
allMod = false
|
||||
}
|
||||
var v int
|
||||
if ccanMod {
|
||||
v = 1
|
||||
}
|
||||
modSet[i] = v
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Println("writing to user #", wsUser.User.ID)
|
||||
outBytes := canSeeRenders[string(canSee)]
|
||||
outBytes := canSeeRenders[sCanSee]
|
||||
//fmt.Println("outBytes: ", string(outBytes))
|
||||
err := wsUser.WriteToPageBytes(outBytes, "/topics/")
|
||||
if err == ErrNoneOnPage {
|
||||
//fmt.Println("outBytes[:len(outBytes)-1]: ", string(outBytes[:len(outBytes)-1]))
|
||||
//e := wsUser.WriteToPageBytes(outBytes, "/topics/")
|
||||
//e := wsUser.WriteToPageBytesMulti([][]byte{outBytes[:len(outBytes)-1], []byte(`,"mod":1}`)}, "/topics/")
|
||||
var e error
|
||||
if !anyMod {
|
||||
e = wsUser.WriteToPageBytes(outBytes, "/topics/")
|
||||
} else {
|
||||
var lm []byte
|
||||
if anyLock && anyMove {
|
||||
lm = []byte(`,"lock":1,"move":1}`)
|
||||
} else if anyLock {
|
||||
lm = []byte(`,"lock":1}`)
|
||||
} else if anyMove {
|
||||
lm = []byte(`,"move":1}`)
|
||||
} else {
|
||||
lm = []byte("}")
|
||||
}
|
||||
if allMod {
|
||||
e = wsUser.WriteToPageBytesMulti([][]byte{outBytes[:len(outBytes)-1], []byte(`,"mod":1`), lm}, "/topics/")
|
||||
} else {
|
||||
// TODO: Temporary and inefficient
|
||||
mBytes, err := json.Marshal(modSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e = wsUser.WriteToPageBytesMulti([][]byte{outBytes[:len(outBytes)-1], []byte(`,"mod":`), mBytes, lm}, "/topics/")
|
||||
}
|
||||
}
|
||||
|
||||
if e == ErrNoneOnPage {
|
||||
//fmt.Printf("werr for #%d: %s\n", wsUser.User.ID, err)
|
||||
wsUser.FinalizePage("/topics/", func() {
|
||||
topicListMutex.Lock()
|
||||
|
|
|
@ -221,8 +221,8 @@ function runWebSockets(resume=false) {
|
|||
if(window.location.protocol == "https:") s = "s";
|
||||
conn = new WebSocket("ws"+s+"://" + document.location.host + "/ws/");
|
||||
|
||||
conn.onerror = err => {
|
||||
console.log(err);
|
||||
conn.onerror = e => {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
// TODO: Sync alerts, topic list, etc.
|
||||
|
@ -297,11 +297,26 @@ function runWebSockets(resume=false) {
|
|||
} else if("Topics" in data) {
|
||||
console.log("topic in data");
|
||||
console.log("data",data);
|
||||
// TODO: Handle desyncs more gracefully?
|
||||
// TODO: Send less unneccessary data?
|
||||
let topic = data.Topics[0];
|
||||
if(topic===undefined){
|
||||
console.log("empty topic list");
|
||||
return;
|
||||
}
|
||||
if("mod" in data) {
|
||||
topic.CanMod = data.mod==1 || data.mod[0]==1;
|
||||
if(data.lock==1) {
|
||||
$(".val_lock").each(function(){
|
||||
this.classList.remove("auto_hide");
|
||||
});
|
||||
}
|
||||
if(data.move==1) {
|
||||
$(".val_move").each(function(){
|
||||
this.classList.remove("auto_hide");
|
||||
});
|
||||
}
|
||||
}
|
||||
// TODO: Fix the data race where the function hasn't been loaded yet
|
||||
let renTopic = Tmpl_topics_topic(topic);
|
||||
$(".topic_row[data-tid='"+topic.ID+"']").addClass("ajax_topic_dupe");
|
||||
|
@ -313,7 +328,7 @@ function runWebSockets(resume=false) {
|
|||
moreTopicCount++;
|
||||
|
||||
let blocks = document.getElementsByClassName("more_topic_block_initial");
|
||||
for(let i=0; i < blocks.length; i++) {
|
||||
for(let i=0; i<blocks.length; i++) {
|
||||
let block = blocks[i];
|
||||
block.classList.remove("more_topic_block_initial");
|
||||
block.classList.add("more_topic_block_active");
|
||||
|
@ -347,7 +362,7 @@ function runWebSockets(resume=false) {
|
|||
|
||||
// TODO: Surely, there's a prettier and more elegant way of doing this?
|
||||
function getExt(name) {
|
||||
if(!name.indexOf('.' > -1)) throw("This file doesn't have an extension");
|
||||
if(!name.indexOf('.') > -1) throw("This file doesn't have an extension");
|
||||
return name.split('.').pop();
|
||||
}
|
||||
|
||||
|
@ -439,9 +454,9 @@ function mainInit(){
|
|||
ev.preventDefault();
|
||||
let blocks = document.getElementsByClassName("more_topic_block_active");
|
||||
for(let i=0; i<blocks.length; i++) {
|
||||
let block = blocks[i];
|
||||
block.classList.remove("more_topic_block_active");
|
||||
block.classList.add("more_topic_block_initial");
|
||||
let bl = blocks[i];
|
||||
bl.classList.remove("more_topic_block_active");
|
||||
bl.classList.add("more_topic_block_initial");
|
||||
}
|
||||
$(".ajax_topic_dupe").fadeOut("slow", function(){
|
||||
$(this).remove();
|
||||
|
@ -646,6 +661,7 @@ function mainInit(){
|
|||
});
|
||||
|
||||
bindPage();
|
||||
runInitHook("after_init_bind_page");
|
||||
|
||||
$(".edit_field").click(function(ev) {
|
||||
ev.preventDefault();
|
||||
|
@ -927,6 +943,7 @@ function bindPage() {
|
|||
});
|
||||
|
||||
bindTopic();
|
||||
runHook("end_bind_page")
|
||||
}
|
||||
|
||||
function unbindPage() {
|
||||
|
|
153
public/member.js
153
public/member.js
|
@ -151,16 +151,16 @@ var imageExts = ["png","jpg","jpe","jpeg","jif","jfi","jfif","svg","bmp","gif","
|
|||
addInitHook("start_init", () => {
|
||||
addHook("end_bind_topic", () => {
|
||||
|
||||
let changeListener = (files,handler) => {
|
||||
if(files!=null) {
|
||||
files.removeEventListener("change", handler, false);
|
||||
files.addEventListener("change", handler, false);
|
||||
}
|
||||
};
|
||||
let uploadFiles = document.getElementById("upload_files");
|
||||
if(uploadFiles!=null) {
|
||||
uploadFiles.removeEventListener("change", uploadAttachHandler, false);
|
||||
uploadFiles.addEventListener("change", uploadAttachHandler, false);
|
||||
}
|
||||
changeListener(uploadFiles,uploadAttachHandler);
|
||||
let uploadFilesOp = document.getElementById("upload_files_op");
|
||||
if(uploadFilesOp!=null) {
|
||||
uploadFilesOp.removeEventListener("change", uploadAttachHandler2, false);
|
||||
uploadFilesOp.addEventListener("change", uploadAttachHandler2, false);
|
||||
}
|
||||
changeListener(uploadFilesOp,uploadAttachHandler2);
|
||||
bindAttachManager();
|
||||
|
||||
function bindAttachItems() {
|
||||
|
@ -213,73 +213,6 @@ var imageExts = ["png","jpg","jpe","jpeg","jif","jfi","jfif","svg","bmp","gif","
|
|||
bindAttachManager();
|
||||
});
|
||||
|
||||
$(".moderate_link").unbind("click");
|
||||
$(".mod_floater_submit").unbind("click");
|
||||
$(".moderate_link").click(ev => {
|
||||
ev.preventDefault();
|
||||
$(".pre_opt").removeClass("auto_hide");
|
||||
$(".moderate_link").addClass("moderate_open");
|
||||
$("#topicsItemList,#forumItemList").addClass("topics_moderate");
|
||||
$(".topic_row").each(function(){
|
||||
$(this).click(function(){
|
||||
selectedTopics.push(parseInt($(this).attr("data-tid"),10));
|
||||
if(selectedTopics.length==1) {
|
||||
var msg = phraseBox["topic_list"]["topic_list.what_to_do_single"];
|
||||
} else {
|
||||
var msg = "What do you want to do with these "+selectedTopics.length+" topics?";
|
||||
}
|
||||
$(".mod_floater_head span").html(msg);
|
||||
$(this).addClass("topic_selected");
|
||||
$(".mod_floater").removeClass("auto_hide");
|
||||
});
|
||||
});
|
||||
|
||||
let bulkActionSender = (action,selectedTopics,fragBit) => {
|
||||
$.ajax({
|
||||
url: "/topic/"+action+"/submit/"+fragBit+"?s="+me.User.S,
|
||||
type: "POST",
|
||||
data: JSON.stringify(selectedTopics),
|
||||
contentType: "application/json",
|
||||
error: ajaxError,
|
||||
success: () => {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
// TODO: Should we unbind this here to avoid binding multiple listeners to this accidentally?
|
||||
$(".mod_floater_submit").click(function(ev){
|
||||
ev.preventDefault();
|
||||
let selectNode = this.form.querySelector(".mod_floater_options");
|
||||
let optionNode = selectNode.options[selectNode.selectedIndex];
|
||||
let action = optionNode.getAttribute("value");
|
||||
|
||||
// Handle these specially
|
||||
switch(action) {
|
||||
case "move":
|
||||
console.log("move action");
|
||||
let modTopicMover = $("#mod_topic_mover");
|
||||
$("#mod_topic_mover").removeClass("auto_hide");
|
||||
$("#mod_topic_mover .pane_row").click(function(){
|
||||
modTopicMover.find(".pane_row").removeClass("pane_selected");
|
||||
let fid = this.getAttribute("data-fid");
|
||||
if(fid==null) return;
|
||||
this.classList.add("pane_selected");
|
||||
console.log("fid",fid);
|
||||
forumToMoveTo = fid;
|
||||
|
||||
$("#mover_submit").unbind("click");
|
||||
$("#mover_submit").click(ev => {
|
||||
ev.preventDefault();
|
||||
bulkActionSender("move",selectedTopics,forumToMoveTo);
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
bulkActionSender(action,selectedTopics,"");
|
||||
});
|
||||
});
|
||||
|
||||
function addPollInput() {
|
||||
console.log("clicked on pollinputinput");
|
||||
let dataPollInput = $(this).parent().attr("data-pollinput");
|
||||
|
@ -306,4 +239,74 @@ var imageExts = ["png","jpg","jpe","jpeg","jif","jfi","jfif","svg","bmp","gif","
|
|||
});
|
||||
});
|
||||
});
|
||||
//addInitHook("after_init_bind_page", () => {
|
||||
addHook("end_bind_page", () => {
|
||||
$(".moderate_link").unbind("click");
|
||||
$(".mod_floater_submit").unbind("click");
|
||||
$(".moderate_link").click(ev => {
|
||||
ev.preventDefault();
|
||||
$(".pre_opt").removeClass("auto_hide");
|
||||
$(".moderate_link").addClass("moderate_open");
|
||||
$("#topicsItemList,#forumItemList").addClass("topics_moderate");
|
||||
$(".topic_row").each(function(){
|
||||
$(this).click(function(){
|
||||
if(!this.classList.contains("can_mod") || this.classList.contains("topic_selected")) return;
|
||||
selectedTopics.push(parseInt($(this).attr("data-tid"),10));
|
||||
if(selectedTopics.length==1) {
|
||||
var msg = phraseBox["topic_list"]["topic_list.what_to_do_single"];
|
||||
} else {
|
||||
var msg = "What do you want to do with these "+selectedTopics.length+" topics?";
|
||||
}
|
||||
$(".mod_floater_head span").html(msg);
|
||||
$(this).addClass("topic_selected");
|
||||
$(".mod_floater").removeClass("auto_hide");
|
||||
});
|
||||
});
|
||||
|
||||
let bulkActionSender = (action,selectedTopics,fragBit) => {
|
||||
$.ajax({
|
||||
url: "/topic/"+action+"/submit/"+fragBit+"?s="+me.User.S,
|
||||
type: "POST",
|
||||
data: JSON.stringify(selectedTopics),
|
||||
contentType: "application/json",
|
||||
error: ajaxError,
|
||||
success: () => {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
};
|
||||
// TODO: Should we unbind this here to avoid binding multiple listeners to this accidentally?
|
||||
$(".mod_floater_submit").click(function(ev){
|
||||
ev.preventDefault();
|
||||
let selectNode = this.form.querySelector(".mod_floater_options");
|
||||
let optionNode = selectNode.options[selectNode.selectedIndex];
|
||||
let action = optionNode.getAttribute("value");
|
||||
|
||||
// Handle these specially
|
||||
switch(action) {
|
||||
case "move":
|
||||
console.log("move action");
|
||||
let modTopicMover = $("#mod_topic_mover");
|
||||
$("#mod_topic_mover").removeClass("auto_hide");
|
||||
$("#mod_topic_mover .pane_row").click(function(){
|
||||
modTopicMover.find(".pane_row").removeClass("pane_selected");
|
||||
let fid = this.getAttribute("data-fid");
|
||||
if(fid==null) return;
|
||||
this.classList.add("pane_selected");
|
||||
console.log("fid",fid);
|
||||
forumToMoveTo = fid;
|
||||
|
||||
$("#mover_submit").unbind("click");
|
||||
$("#mover_submit").click(ev => {
|
||||
ev.preventDefault();
|
||||
bulkActionSender("move",selectedTopics,forumToMoveTo);
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
bulkActionSender(action,selectedTopics,"");
|
||||
});
|
||||
});
|
||||
});
|
||||
})()
|
|
@ -54,8 +54,14 @@ func ViewForum(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header, s
|
|||
return nil
|
||||
}
|
||||
|
||||
topicList2 := make([]c.TopicsRowMut, len(topicList))
|
||||
canMod := u.Perms.CloseTopic || u.Perms.MoveTopic
|
||||
for i, t := range topicList {
|
||||
topicList2[i] = c.TopicsRowMut{t, t.CreatedBy == u.ID || canMod}
|
||||
}
|
||||
|
||||
//pageList := c.Paginate(page, lastPage, 5)
|
||||
pi := c.ForumPage{h, topicList, forum, u.Perms.CloseTopic, u.Perms.MoveTopic, pagi}
|
||||
pi := c.ForumPage{h, topicList2, forum, u.Perms.CloseTopic, u.Perms.MoveTopic, pagi}
|
||||
tmpl := forum.Tmpl
|
||||
if tmpl == "" {
|
||||
ferr = renderTemplate("forum", w, r, h, pi)
|
||||
|
|
|
@ -8,12 +8,12 @@ import (
|
|||
"github.com/Azareal/Gosora/common/phrases"
|
||||
)
|
||||
|
||||
func ForumList(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header) c.RouteError {
|
||||
/*skip, rerr := h.Hooks.VhookSkippable("route_forum_list_start", w, r, user, h)
|
||||
func ForumList(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
|
||||
/*skip, rerr := h.Hooks.VhookSkippable("route_forum_list_start", w, r, u, h)
|
||||
if skip || rerr != nil {
|
||||
return rerr
|
||||
}*/
|
||||
skip, rerr := c.H_route_forum_list_start_hook(h.Hooks, w, r, user, h)
|
||||
skip, rerr := c.H_route_forum_list_start_hook(h.Hooks, w, r, u, h)
|
||||
if skip || rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
|
@ -24,18 +24,18 @@ func ForumList(w http.ResponseWriter, r *http.Request, user *c.User, h *c.Header
|
|||
|
||||
var err error
|
||||
var canSee []int
|
||||
if user.IsSuperAdmin {
|
||||
if u.IsSuperAdmin {
|
||||
canSee, err = c.Forums.GetAllVisibleIDs()
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
} else {
|
||||
group, err := c.Groups.Get(user.Group)
|
||||
g, err := c.Groups.Get(u.Group)
|
||||
if err != nil {
|
||||
log.Printf("Group #%d doesn't exist despite being used by c.User #%d", user.Group, user.ID)
|
||||
return c.LocalError("Something weird happened", w, r, user)
|
||||
log.Printf("Group #%d doesn't exist despite being used by c.User #%d", u.Group, u.ID)
|
||||
return c.LocalError("Something weird happened", w, r, u)
|
||||
}
|
||||
canSee = group.CanSee
|
||||
canSee = g.CanSee
|
||||
}
|
||||
|
||||
var forumList []c.Forum
|
||||
|
|
|
@ -11,13 +11,13 @@ import (
|
|||
p "github.com/Azareal/Gosora/common/phrases"
|
||||
)
|
||||
|
||||
func Forums(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, user, "forums", "forums")
|
||||
func Forums(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, u, "forums", "forums")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
basePage.Header.AddScript("Sortable-1.4.0/Sortable.min.js")
|
||||
basePage.Header.AddScriptAsync("panel_forums.js")
|
||||
|
@ -52,26 +52,26 @@ func Forums(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
|||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_forums", &pi})
|
||||
}
|
||||
|
||||
func ForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ForumsCreateSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
fname := r.PostFormValue("name")
|
||||
fdesc := r.PostFormValue("desc")
|
||||
fpreset := c.StripInvalidPreset(r.PostFormValue("preset"))
|
||||
name := r.PostFormValue("name")
|
||||
desc := r.PostFormValue("desc")
|
||||
preset := c.StripInvalidPreset(r.PostFormValue("preset"))
|
||||
factive := r.PostFormValue("active")
|
||||
active := (factive == "on" || factive == "1")
|
||||
|
||||
fid, err := c.Forums.Create(fname, fdesc, active, fpreset)
|
||||
fid, err := c.Forums.Create(name, desc, active, preset)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.AdminLogs.Create("create", fid, "forum", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("create", fid, "forum", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -81,22 +81,22 @@ func ForumsCreateSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.
|
|||
}
|
||||
|
||||
// TODO: Revamp this
|
||||
func ForumsDelete(w http.ResponseWriter, r *http.Request, user *c.User, sfid string) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, user, "delete_forum", "forums")
|
||||
func ForumsDelete(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, u, "delete_forum", "forums")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
fid, err := strconv.Atoi(sfid)
|
||||
if err != nil {
|
||||
return c.LocalError("The provided Forum ID is not a valid number.", w, r, user)
|
||||
return c.LocalError("The provided Forum ID is not a valid number.", w, r, u)
|
||||
}
|
||||
forum, err := c.Forums.Get(fid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The forum you're trying to delete doesn't exist.", w, r, user)
|
||||
return c.LocalError("The forum you're trying to delete doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -105,32 +105,32 @@ func ForumsDelete(w http.ResponseWriter, r *http.Request, user *c.User, sfid str
|
|||
youSure := c.AreYouSure{"/panel/forums/delete/submit/" + strconv.Itoa(fid), confirmMsg}
|
||||
|
||||
pi := c.PanelPage{basePage, tList, youSure}
|
||||
if c.RunPreRenderHook("pre_render_panel_delete_forum", w, r, user, &pi) {
|
||||
if c.RunPreRenderHook("pre_render_panel_delete_forum", w, r, u, &pi) {
|
||||
return nil
|
||||
}
|
||||
return renderTemplate("panel_are_you_sure", w, r, basePage.Header, &pi)
|
||||
}
|
||||
|
||||
func ForumsDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.User, sfid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ForumsDeleteSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
fid, err := strconv.Atoi(sfid)
|
||||
if err != nil {
|
||||
return c.LocalError("The provided Forum ID is not a valid number.", w, r, user)
|
||||
return c.LocalError("The provided Forum ID is not a valid number.", w, r, u)
|
||||
}
|
||||
err = c.Forums.Delete(fid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The forum you're trying to delete doesn't exist.", w, r, user)
|
||||
return c.LocalError("The forum you're trying to delete doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
err = c.AdminLogs.Create("delete", fid, "forum", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("delete", fid, "forum", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -139,14 +139,14 @@ func ForumsDeleteSubmit(w http.ResponseWriter, r *http.Request, user *c.User, sf
|
|||
return nil
|
||||
}
|
||||
|
||||
func ForumsOrderSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ForumsOrderSubmit(w http.ResponseWriter, r *http.Request, u *c.User) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissionsJSQ(w, r, user, js)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissionsJSQ(w, r, u, js)
|
||||
}
|
||||
sitems := strings.TrimSuffix(strings.TrimPrefix(r.PostFormValue("items"), "{"), "}")
|
||||
//fmt.Printf("sitems: %+v\n", sitems)
|
||||
|
@ -155,13 +155,13 @@ func ForumsOrderSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.R
|
|||
for index, sfid := range strings.Split(sitems, ",") {
|
||||
fid, err := strconv.Atoi(sfid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ("Invalid integer in forum list", w, r, user, js)
|
||||
return c.LocalErrorJSQ("Invalid integer in forum list", w, r, u, js)
|
||||
}
|
||||
updateMap[fid] = index
|
||||
}
|
||||
c.Forums.UpdateOrder(updateMap)
|
||||
|
||||
err := c.AdminLogs.Create("reorder", 0, "forum", user.GetIP(), user.ID)
|
||||
err := c.AdminLogs.Create("reorder", 0, "forum", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
@ -169,13 +169,13 @@ func ForumsOrderSubmit(w http.ResponseWriter, r *http.Request, user *c.User) c.R
|
|||
return successRedirect("/panel/forums/", w, r, js)
|
||||
}
|
||||
|
||||
func ForumsEdit(w http.ResponseWriter, r *http.Request, user *c.User, sfid string) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, user, "edit_forum", "forums")
|
||||
func ForumsEdit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, u, "edit_forum", "forums")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
fid, err := strconv.Atoi(sfid)
|
||||
|
@ -186,7 +186,7 @@ func ForumsEdit(w http.ResponseWriter, r *http.Request, user *c.User, sfid strin
|
|||
|
||||
forum, err := c.Forums.Get(fid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, user)
|
||||
return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -222,30 +222,30 @@ func ForumsEdit(w http.ResponseWriter, r *http.Request, user *c.User, sfid strin
|
|||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_forum_edit", &pi})
|
||||
}
|
||||
|
||||
func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, sfid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
|
||||
fid, err := strconv.Atoi(sfid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, user, js)
|
||||
return c.LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, u, js)
|
||||
}
|
||||
forum, err := c.Forums.Get(fid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalErrorJSQ("The forum you're trying to edit doesn't exist.", w, r, user, js)
|
||||
return c.LocalErrorJSQ("The forum you're trying to edit doesn't exist.", w, r, u, js)
|
||||
} else if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
||||
fname := r.PostFormValue("forum_name")
|
||||
fdesc := r.PostFormValue("forum_desc")
|
||||
fpreset := c.StripInvalidPreset(r.PostFormValue("forum_preset"))
|
||||
name := r.PostFormValue("forum_name")
|
||||
desc := r.PostFormValue("forum_desc")
|
||||
preset := c.StripInvalidPreset(r.PostFormValue("forum_preset"))
|
||||
factive := r.PostFormValue("forum_active")
|
||||
|
||||
active := false
|
||||
|
@ -255,11 +255,11 @@ func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, sfid
|
|||
active = true
|
||||
}
|
||||
|
||||
err = forum.Update(fname, fdesc, active, fpreset)
|
||||
err = forum.Update(name, desc, active, preset)
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
err = c.AdminLogs.Create("edit", fid, "forum", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("edit", fid, "forum", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -268,29 +268,28 @@ func ForumsEditSubmit(w http.ResponseWriter, r *http.Request, user *c.User, sfid
|
|||
return successRedirect("/panel/forums/", w, r, js)
|
||||
}
|
||||
|
||||
func ForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user *c.User, sfid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, u *c.User, sfid string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
|
||||
fid, err := strconv.Atoi(sfid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, user, js)
|
||||
return c.LocalErrorJSQ("The provided Forum ID is not a valid number.", w, r, u, js)
|
||||
}
|
||||
|
||||
gid, err := strconv.Atoi(r.PostFormValue("gid"))
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ("Invalid Group ID", w, r, user, js)
|
||||
return c.LocalErrorJSQ("Invalid Group ID", w, r, u, js)
|
||||
}
|
||||
|
||||
forum, err := c.Forums.Get(fid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalErrorJSQ("This forum doesn't exist", w, r, user, js)
|
||||
return c.LocalErrorJSQ("This forum doesn't exist", w, r, u, js)
|
||||
} else if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
@ -298,9 +297,9 @@ func ForumsEditPermsSubmit(w http.ResponseWriter, r *http.Request, user *c.User,
|
|||
permPreset := c.StripInvalidGroupForumPreset(r.PostFormValue("perm_preset"))
|
||||
err = forum.SetPreset(permPreset, gid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(err.Error(), w, r, user, js)
|
||||
return c.LocalErrorJSQ(err.Error(), w, r, u, js)
|
||||
}
|
||||
err = c.AdminLogs.Create("edit", fid, "forum", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("edit", fid, "forum", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -328,23 +327,23 @@ func forumPermsExtractDash(paramList string) (fid, gid int, err error) {
|
|||
return fid, gid, err
|
||||
}
|
||||
|
||||
func ForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, user *c.User, paramList string) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, user, "edit_forum", "forums")
|
||||
func ForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, u *c.User, paramList string) c.RouteError {
|
||||
basePage, ferr := buildBasePage(w, r, u, "edit_forum", "forums")
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
|
||||
fid, gid, err := forumPermsExtractDash(paramList)
|
||||
if err != nil {
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
return c.LocalError(err.Error(), w, r, u)
|
||||
}
|
||||
|
||||
f, err := c.Forums.Get(fid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, user)
|
||||
return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -386,24 +385,24 @@ func ForumsEditPermsAdvance(w http.ResponseWriter, r *http.Request, user *c.User
|
|||
return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "", "", "panel_forum_edit_perms", &pi})
|
||||
}
|
||||
|
||||
func ForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, user *c.User, paramList string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, user)
|
||||
func ForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, u *c.User, paramList string) c.RouteError {
|
||||
_, ferr := c.SimplePanelUserCheck(w, r, u)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
if !user.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, user)
|
||||
if !u.Perms.ManageForums {
|
||||
return c.NoPermissions(w, r, u)
|
||||
}
|
||||
js := r.PostFormValue("js") == "1"
|
||||
|
||||
fid, gid, err := forumPermsExtractDash(paramList)
|
||||
if err != nil {
|
||||
return c.LocalError(err.Error(), w, r, user)
|
||||
return c.LocalError(err.Error(), w, r, u)
|
||||
}
|
||||
|
||||
forum, err := c.Forums.Get(fid)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, user)
|
||||
return c.LocalError("The forum you're trying to edit doesn't exist.", w, r, u)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -435,9 +434,9 @@ func ForumsEditPermsAdvanceSubmit(w http.ResponseWriter, r *http.Request, user *
|
|||
|
||||
err = forum.SetPerms(&fp, "custom", gid)
|
||||
if err != nil {
|
||||
return c.LocalErrorJSQ(err.Error(), w, r, user, js)
|
||||
return c.LocalErrorJSQ(err.Error(), w, r, u, js)
|
||||
}
|
||||
err = c.AdminLogs.Create("edit", fid, "forum", user.GetIP(), user.ID)
|
||||
err = c.AdminLogs.Create("edit", fid, "forum", u.GetIP(), u.ID)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,21 @@ func wsTopicList(topicList []*c.TopicsRow, lastPage int) *c.WsTopicList {
|
|||
return &c.WsTopicList{wsTopicList, lastPage, 0}
|
||||
}
|
||||
|
||||
func wsTopicList2(topicList []*c.TopicsRow, u *c.User, fps map[int]c.QuickTools, lastPage int) *c.WsTopicList {
|
||||
wsTopicList := make([]*c.WsTopicsRow, len(topicList))
|
||||
for i, t := range topicList {
|
||||
var canMod bool
|
||||
if fps == nil {
|
||||
canMod = true
|
||||
} else {
|
||||
quickTools := fps[t.ParentID]
|
||||
canMod = t.CreatedBy == u.ID || quickTools.CanDelete || quickTools.CanLock || quickTools.CanMove
|
||||
}
|
||||
wsTopicList[i] = t.WebSockets2(canMod)
|
||||
}
|
||||
return &c.WsTopicList{wsTopicList, lastPage, 0}
|
||||
}
|
||||
|
||||
func TopicList(w http.ResponseWriter, r *http.Request, u *c.User, h *c.Header) c.RouteError {
|
||||
/*skip, rerr := h.Hooks.VhookSkippable("route_topic_list_start", w, r, u, h)
|
||||
if skip || rerr != nil {
|
||||
|
@ -79,7 +94,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c.
|
|||
var topicList []*c.TopicsRow
|
||||
var forumList []c.Forum
|
||||
var pagi c.Paginator
|
||||
var canLock, ccanLock, canMove, ccanMove bool
|
||||
var canDelete, ccanDelete, canLock, ccanLock, canMove, ccanMove bool
|
||||
q := r.FormValue("q")
|
||||
if q != "" && c.RepliesSearch != nil {
|
||||
var canSee []int
|
||||
|
@ -152,34 +167,45 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c.
|
|||
|
||||
// TODO: De-dupe this logic in common/topic_list.go?
|
||||
//var sb strings.Builder
|
||||
fps := make(map[int]c.QuickTools)
|
||||
for _, t := range topicList {
|
||||
//c.BuildTopicURLSb(&sb, c.NameToSlug(t.Title), t.ID)
|
||||
//t.Link = sb.String()
|
||||
//sb.Reset()
|
||||
t.Link = c.BuildTopicURL(c.NameToSlug(t.Title), t.ID)
|
||||
// TODO: Pass forum to something like t.Forum and use that instead of these two properties? Could be more flexible.
|
||||
forum := c.Forums.DirtyGet(t.ParentID)
|
||||
t.ForumName = forum.Name
|
||||
t.ForumLink = forum.Link
|
||||
f := c.Forums.DirtyGet(t.ParentID)
|
||||
t.ForumName = f.Name
|
||||
t.ForumLink = f.Link
|
||||
|
||||
fp, err := c.FPStore.Get(forum.ID, user.Group)
|
||||
if err == c.ErrNoRows {
|
||||
fp = c.BlankForumPerms()
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if fp.Overrides && !user.IsSuperAdmin {
|
||||
ccanLock = fp.CloseTopic
|
||||
ccanMove = fp.MoveTopic
|
||||
} else {
|
||||
ccanLock = user.Perms.CloseTopic
|
||||
ccanMove = user.Perms.MoveTopic
|
||||
}
|
||||
if ccanLock {
|
||||
canLock = true
|
||||
}
|
||||
if ccanMove {
|
||||
canMove = true
|
||||
_, ok := fps[f.ID]
|
||||
if !ok {
|
||||
// TODO: Abstract this?
|
||||
fp, err := c.FPStore.Get(f.ID, user.Group)
|
||||
if err == c.ErrNoRows {
|
||||
fp = c.BlankForumPerms()
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if fp.Overrides && !user.IsSuperAdmin {
|
||||
ccanDelete = fp.DeleteTopic
|
||||
ccanLock = fp.CloseTopic
|
||||
ccanMove = fp.MoveTopic
|
||||
} else {
|
||||
ccanDelete = user.Perms.DeleteTopic
|
||||
ccanLock = user.Perms.CloseTopic
|
||||
ccanMove = user.Perms.MoveTopic
|
||||
}
|
||||
if ccanDelete {
|
||||
canDelete = true
|
||||
}
|
||||
if ccanLock {
|
||||
canLock = true
|
||||
}
|
||||
if ccanMove {
|
||||
canMove = true
|
||||
}
|
||||
fps[f.ID] = c.QuickTools{ccanDelete, ccanLock, ccanMove}
|
||||
}
|
||||
|
||||
// TODO: Create a specialised function with a bit less overhead for getting the last page for a post count
|
||||
|
@ -192,7 +218,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c.
|
|||
|
||||
// TODO: Reduce the amount of boilerplate here
|
||||
if r.FormValue("js") == "1" {
|
||||
outBytes, err := wsTopicList(topicList, pagi.LastPage).MarshalJSON()
|
||||
outBytes, err := wsTopicList2(topicList, user, fps, pagi.LastPage).MarshalJSON()
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -200,37 +226,57 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c.
|
|||
return nil
|
||||
}
|
||||
|
||||
topicList2 := make([]c.TopicsRowMut, len(topicList))
|
||||
for i, t := range topicList {
|
||||
var canMod bool
|
||||
if fps == nil {
|
||||
canMod = true
|
||||
} else {
|
||||
quickTools := fps[t.ParentID]
|
||||
canMod = t.CreatedBy == user.ID || quickTools.CanDelete || quickTools.CanLock || quickTools.CanMove
|
||||
}
|
||||
topicList2[i] = c.TopicsRowMut{t, canMod}
|
||||
}
|
||||
|
||||
h.Title = phrases.GetTitlePhrase("topics_search")
|
||||
pi := c.TopicListPage{h, topicList, forumList, c.Config.DefaultForum, c.TopicListSort{torder, false}, canLock, canMove, pagi}
|
||||
pi := c.TopicListPage{h, topicList2, forumList, c.Config.DefaultForum, c.TopicListSort{torder, false}, c.QuickTools{canDelete, canLock, canMove}, pagi}
|
||||
return renderTemplate("topics", w, r, h, pi)
|
||||
}
|
||||
|
||||
// TODO: Pass a struct back rather than passing back so many variables
|
||||
var fps map[int]c.QuickTools
|
||||
if user.IsSuperAdmin {
|
||||
topicList, forumList, pagi, err = c.TopicList.GetList(page, tsorder, fids)
|
||||
canLock, canMove = true, true
|
||||
} else {
|
||||
topicList, forumList, pagi, err = c.TopicList.GetListByGroup(group, page, tsorder, fids)
|
||||
for _, forum := range forumList {
|
||||
fp, err := c.FPStore.Get(forum.ID, user.Group)
|
||||
fps = make(map[int]c.QuickTools)
|
||||
for _, f := range forumList {
|
||||
fp, err := c.FPStore.Get(f.ID, user.Group)
|
||||
if err == c.ErrNoRows {
|
||||
fp = c.BlankForumPerms()
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if fp.Overrides {
|
||||
ccanDelete = fp.DeleteTopic
|
||||
ccanLock = fp.CloseTopic
|
||||
ccanMove = fp.MoveTopic
|
||||
} else {
|
||||
ccanDelete = user.Perms.DeleteTopic
|
||||
ccanLock = user.Perms.CloseTopic
|
||||
ccanMove = user.Perms.MoveTopic
|
||||
}
|
||||
if ccanDelete {
|
||||
canDelete = true
|
||||
}
|
||||
if ccanLock {
|
||||
canLock = true
|
||||
}
|
||||
if ccanMove {
|
||||
canMove = true
|
||||
}
|
||||
fps[f.ID] = c.QuickTools{ccanDelete, ccanLock, ccanMove}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -239,7 +285,7 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c.
|
|||
|
||||
// TODO: Reduce the amount of boilerplate here
|
||||
if r.FormValue("js") == "1" {
|
||||
outBytes, err := wsTopicList(topicList, pagi.LastPage).MarshalJSON()
|
||||
outBytes, err := wsTopicList2(topicList, user, fps, pagi.LastPage).MarshalJSON()
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -247,7 +293,19 @@ func TopicListCommon(w http.ResponseWriter, r *http.Request, user *c.User, h *c.
|
|||
return nil
|
||||
}
|
||||
|
||||
pi := c.TopicListPage{h, topicList, forumList, c.Config.DefaultForum, c.TopicListSort{torder, false}, canLock, canMove, pagi}
|
||||
topicList2 := make([]c.TopicsRowMut, len(topicList))
|
||||
for i, t := range topicList {
|
||||
var canMod bool
|
||||
if fps == nil {
|
||||
canMod = true
|
||||
} else {
|
||||
quickTools := fps[t.ParentID]
|
||||
canMod = t.CreatedBy == user.ID || quickTools.CanDelete || quickTools.CanLock || quickTools.CanMove
|
||||
}
|
||||
topicList2[i] = c.TopicsRowMut{t, canMod}
|
||||
}
|
||||
|
||||
pi := c.TopicListPage{h, topicList2, forumList, c.Config.DefaultForum, c.TopicListSort{torder, false}, c.QuickTools{canDelete, canLock, canMove}, pagi}
|
||||
if r.FormValue("i") == "1" {
|
||||
return renderTemplate("topics_mini", w, r, h, pi)
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Generating the JSON handlers
|
||||
easyjson -pkg common
|
||||
|
||||
echo Building the hook generator
|
||||
go build -tags hookgen -ldflags="-s -w" "./cmd/hook_gen"
|
||||
if %errorlevel% neq 0 (
|
||||
|
@ -54,9 +57,6 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Generating the JSON handlers
|
||||
easyjson -pkg common
|
||||
|
||||
echo Building the query generator
|
||||
go build -ldflags="-s -w" "./cmd/query_gen"
|
||||
if %errorlevel% neq 0 (
|
||||
|
|
|
@ -41,6 +41,9 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Generating the JSON handlers
|
||||
easyjson -pkg common
|
||||
|
||||
echo Building the hook generator
|
||||
go build -tags hookgen -ldflags="-s -w" "./cmd/hook_gen"
|
||||
if %errorlevel% neq 0 (
|
||||
|
@ -54,9 +57,6 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Generating the JSON handlers
|
||||
easyjson -pkg common
|
||||
|
||||
echo Building the query generator
|
||||
go build -ldflags="-s -w" "./cmd/query_gen"
|
||||
if %errorlevel% neq 0 (
|
||||
|
|
|
@ -41,6 +41,9 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Generating the JSON handlers
|
||||
easyjson -pkg common
|
||||
|
||||
echo Building the hook generator
|
||||
go build -tags hookgen -ldflags="-s -w" "./cmd/hook_gen"
|
||||
if %errorlevel% neq 0 (
|
||||
|
@ -54,9 +57,6 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Generating the JSON handlers
|
||||
easyjson -pkg common
|
||||
|
||||
echo Building the query generator
|
||||
go build -ldflags="-s -w" "./cmd/query_gen"
|
||||
if %errorlevel% neq 0 (
|
||||
|
|
|
@ -41,6 +41,9 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Generating the JSON handlers
|
||||
easyjson -pkg common
|
||||
|
||||
echo Building the hook generator
|
||||
go build -tags hookgen -ldflags="-s -w" "./cmd/hook_gen"
|
||||
if %errorlevel% neq 0 (
|
||||
|
@ -54,9 +57,6 @@ if %errorlevel% neq 0 (
|
|||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Generating the JSON handlers
|
||||
easyjson -pkg common
|
||||
|
||||
echo Building the query generator
|
||||
go build -ldflags="-s -w" "./cmd/query_gen"
|
||||
if %errorlevel% neq 0 (
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
{{end}}
|
||||
{{end}}
|
||||
<div id="forum_topic_list"class="rowblock topic_list single_forum"aria-label="{{lang "forum_list_aria"}}">
|
||||
{{range .ItemList}}<div class="topic_row{{if .Sticky}} topic_sticky{{else if .IsClosed}} topic_closed{{end}}"data-tid="{{.ID}}">
|
||||
{{range .ItemList}}<div class="topic_row{{if .Sticky}} topic_sticky{{else if .IsClosed}} topic_closed{{end}}{{if .CanMod}} can_mod{{end}}"data-tid="{{.ID}}">
|
||||
<div class="rowitem topic_left passive datarow">
|
||||
<span class="selector"></span>
|
||||
<a href="{{.Creator.Link}}"><img src="{{.Creator.MicroAvatar}}"height=64 alt="Avatar"title="{{.Creator.Name}}'s Avatar"aria-hidden="true"></a>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>{{lang "panel_pages_head"}}</h1></div>
|
||||
</div>
|
||||
<div id="panel_pages" class="colstack_item rowlist">
|
||||
<div id="panel_pages"class="colstack_item rowlist">
|
||||
{{range .ItemList}}
|
||||
<div class="rowitem panel_compactrow">
|
||||
<a href="/panel/pages/edit/{{.ID}}" class="panel_upshift">{{.Title}}</a> <a href="/pages/{{.Name}}">[{{.Name}}]</a>
|
||||
<a href="/panel/pages/edit/{{.ID}}"class="panel_upshift">{{.Title}}</a> <a href="/pages/{{.Name}}">[{{.Name}}]</a>
|
||||
<span class="panel_buttons">
|
||||
<a href="/panel/pages/edit/{{.ID}}" class="panel_tag panel_right_button edit_button" aria-label="{{lang "panel_pages_edit_button_aria"}}"></a>
|
||||
<a href="/panel/pages/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}" class="panel_tag panel_right_button delete_button" aria-label="{{lang "panel_pages_delete_button_aria"}}"></a>
|
||||
<a href="/panel/pages/edit/{{.ID}}"class="panel_tag panel_right_button edit_button"aria-label="{{lang "panel_pages_edit_button_aria"}}"></a>
|
||||
<a href="/panel/pages/delete/submit/{{.ID}}?s={{$.CurrentUser.Session}}"class="panel_tag panel_right_button delete_button"aria-label="{{lang "panel_pages_delete_button_aria"}}"></a>
|
||||
</span>
|
||||
</div>
|
||||
{{else}}
|
||||
|
@ -21,22 +21,22 @@
|
|||
<div class="rowitem"><h1>{{lang "panel_pages_create_head"}}</h1></div>
|
||||
</div>
|
||||
<div class="colstack_item the_form">
|
||||
<form action="/panel/pages/create/submit/?s={{.CurrentUser.Session}}" method="post">
|
||||
<form action="/panel/pages/create/submit/?s={{.CurrentUser.Session}}"method="post">
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_pages_create_name"}}</a></div>
|
||||
<div class="formitem"><input name="name" type="text" placeholder="{{lang "panel_pages_create_name_placeholder"}}"></div>
|
||||
<div class="formitem"><input name="name"type="text"placeholder="{{lang "panel_pages_create_name_placeholder"}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_pages_create_title"}}</a></div>
|
||||
<div class="formitem"><input name="title" type="text" placeholder="{{lang "panel_pages_create_title_placeholder"}}"></div>
|
||||
<div class="formitem"><input name="title"type="text"placeholder="{{lang "panel_pages_create_title_placeholder"}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem">
|
||||
<textarea name="body" placeholder="{{lang "panel_pages_create_body_placeholder"}}"></textarea>
|
||||
<textarea name="body"placeholder="{{lang "panel_pages_create_body_placeholder"}}"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="panel-button" class="formbutton form_middle_button">{{lang "panel_pages_create_button"}}</button></div>
|
||||
<div class="formitem"><button name="panel-button"class="formbutton form_middle_button">{{lang "panel_pages_create_button"}}</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
|
@ -3,20 +3,20 @@
|
|||
<div class="colstack_item colstack_head">
|
||||
<div class="rowitem"><h1>{{lang "panel_themes_menus_edit_head"}}</h1></div>
|
||||
</div>
|
||||
<form action="/panel/themes/menus/item/edit/submit/{{.Item.ID}}?s={{.CurrentUser.Session}}" method="post">
|
||||
<div id="panel_themes_menu_item_edit" class="colstack_item the_form">
|
||||
<form action="/panel/themes/menus/item/edit/submit/{{.Item.ID}}?s={{.CurrentUser.Session}}"method="post">
|
||||
<div id="panel_themes_menu_item_edit"class="colstack_item the_form">
|
||||
{{/** TODO: Let an admin move a menu item from one menu to another? **/}}
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_name"}}</a></div>
|
||||
<div class="formitem"><input name="item-name" type="text" value="{{.Item.Name}}"></div>
|
||||
<div class="formitem"><input name="item-name"type="text"value="{{.Item.Name}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_htmlid"}}</a></div>
|
||||
<div class="formitem"><input name="item-htmlid" type="text" value="{{.Item.HTMLID}}"></div>
|
||||
<div class="formitem"><input name="item-htmlid"type="text"value="{{.Item.HTMLID}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_cssclass"}}</a></div>
|
||||
<div class="formitem"><input name="item-cssclass" type="text" value="{{.Item.CSSClass}}"></div>
|
||||
<div class="formitem"><input name="item-cssclass"type="text"value="{{.Item.CSSClass}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_position"}}</a></div>
|
||||
|
@ -29,19 +29,19 @@
|
|||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_path"}}</a></div>
|
||||
<div class="formitem"><input name="item-path" type="text" value="{{.Item.Path}}"></div>
|
||||
<div class="formitem"><input name="item-path"type="text"value="{{.Item.Path}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_aria"}}</a></div>
|
||||
<div class="formitem"><input name="item-aria" type="text" value="{{.Item.Aria}}"></div>
|
||||
<div class="formitem"><input name="item-aria"type="text"value="{{.Item.Aria}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_tooltip"}}</a></div>
|
||||
<div class="formitem"><input name="item-tooltip" type="text" value="{{.Item.Tooltip}}"></div>
|
||||
<div class="formitem"><input name="item-tooltip"type="text"value="{{.Item.Tooltip}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_tmplname"}}</a></div>
|
||||
<div class="formitem"><input name="item-tmplname" type="text" value="{{.Item.TmplName}}"></div>
|
||||
<div class="formitem"><input name="item-tmplname"type="text"value="{{.Item.TmplName}}"></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>{{lang "panel_themes_menus_permissions"}}</a></div>
|
||||
|
@ -55,7 +55,7 @@
|
|||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem">
|
||||
<button name="panel-button" class="formbutton">{{lang "panel_themes_menus_edit_update_button"}}</button>
|
||||
<button name="panel-button"class="formbutton">{{lang "panel_themes_menus_edit_update_button"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
</div>
|
||||
|
||||
{{if .CurrentUser.Loggedin}}
|
||||
{{template "topics_mod_floater.html" .}}
|
||||
{{template "topics_mod_floater.html" . }}
|
||||
|
||||
{{if .ForumList}}
|
||||
{{/** TODO: Have a seperate forum list for moving topics? Maybe an AJAX forum search compatible with plugin_guilds? **/}}
|
||||
|
@ -52,7 +52,7 @@
|
|||
</form>
|
||||
</div>
|
||||
<div class="rowblock topic_create_form quick_create_form auto_hide"aria-label="{{lang "quick_topic.aria"}}">
|
||||
<form name="topic_create_form_form"id="quick_post_form"enctype="multipart/form-data"action="/topic/create/submit/?s={{.CurrentUser.Session}}" method="post"></form>
|
||||
<form name="topic_create_form_form"id="quick_post_form"enctype="multipart/form-data"action="/topic/create/submit/?s={{.CurrentUser.Session}}"method="post"></form>
|
||||
<img class="little_row_avatar"src="{{.CurrentUser.MicroAvatar}}"height=64 alt="{{lang "quick_topic.avatar_alt"}}"title="{{lang "quick_topic.avatar_tooltip"}}">
|
||||
<div class="main_form">
|
||||
<div class="topic_meta">
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
</div>
|
||||
<div class="mod_floater_body">
|
||||
<select class="mod_floater_options">
|
||||
<option value="delete">{{lang "topic_list.moderate_delete"}}</option>
|
||||
{{if .CanLock}}<option value="lock">{{lang "topic_list.moderate_lock"}}</option>{{end}}
|
||||
{{if .CanMove}}<option value="move">{{lang "topic_list.moderate_move"}}</option>{{end}}
|
||||
<option class="val_delete" value="delete">{{lang "topic_list.moderate_delete"}}</option>
|
||||
<option class="val_lock{{if not .CanLock}} auto_hide{{end}}" value="lock">{{lang "topic_list.moderate_lock"}}</option>
|
||||
<option class="val_move{{if not .CanMove}} auto_hide{{end}}" value="move">{{lang "topic_list.moderate_move"}}</option>
|
||||
</select>
|
||||
<button class="mod_floater_submit">{{lang "topic_list.moderate_run"}}</button>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="topic_row{{if .Sticky}} topic_sticky{{else if .IsClosed}} topic_closed{{end}}" data-tid="{{.ID}}">
|
||||
<div class="topic_row{{if .Sticky}} topic_sticky{{else if .IsClosed}} topic_closed{{end}}{{if .CanMod}} can_mod{{end}}" data-tid="{{.ID}}">
|
||||
<div class="rowitem topic_left passive datarow">
|
||||
<span class="selector"></span>
|
||||
<a href="{{.Creator.Link}}"><img src="{{.Creator.MicroAvatar}}"height=64 alt="Avatar"title="{{.Creator.Name}}'s Avatar"aria-hidden="true"></a>
|
||||
|
|
|
@ -907,7 +907,11 @@ textarea {
|
|||
.topic_sticky .topic_left, .topic_sticky .topic_right {
|
||||
border-bottom: 2px solid hsl(51, 60%, 70%);
|
||||
}
|
||||
.topics_moderate .topic_row:hover .topic_left, .topics_moderate .topic_row:hover .topic_right {
|
||||
.topics_moderate .topic_row:not(.can_mod) .topic_left,
|
||||
.topics_moderate .topic_row:not(.can_mod) .topic_right {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
.topics_moderate .can_mod:hover .topic_left, .topics_moderate .can_mod:hover .topic_right {
|
||||
background-color: hsl(81, 60%, 97%);
|
||||
}
|
||||
.topic_selected .topic_left, .topic_selected .topic_right {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="topic_row{{if .Sticky}} topic_sticky{{else if .IsClosed}} topic_closed{{end}}"data-tid={{.ID}}>
|
||||
<div class="topic_row{{if .Sticky}} topic_sticky{{else if .IsClosed}} topic_closed{{end}}{{if .CanMod}} can_mod{{end}}"data-tid={{.ID}}>
|
||||
<div class="rowitem topic_left passive datarow">
|
||||
<a href="{{.Creator.Link}}"><img src="{{.Creator.MicroAvatar}}"height=64 alt="Avatar"title="{{.Creator.Name}}'s Avatar"aria-hidden="true"></a>
|
||||
<span class="topic_inner_left">
|
||||
|
|
|
@ -228,7 +228,10 @@ li a {
|
|||
.sidebar .rowblock:not(.topic_list):not(.rowhead):not(.opthead) .rowitem, .sidebar .search {
|
||||
margin-left: 12px;
|
||||
}
|
||||
.topics_moderate .topic_row:hover {
|
||||
.topics_moderate .can_mod {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
.topics_moderate .can_mod:hover {
|
||||
background-color: rgb(78, 78, 98);
|
||||
}
|
||||
.widget_search:first-child {
|
||||
|
@ -552,7 +555,7 @@ h2 {
|
|||
.topic_closed {
|
||||
background-color: #4b4b4b;
|
||||
}
|
||||
.topic_selected {
|
||||
.topic_row.topic_selected {
|
||||
background-color: rgb(68, 68, 88);
|
||||
}
|
||||
.new_item .topic_left {
|
||||
|
|
|
@ -855,12 +855,18 @@ input[type=checkbox]:checked + label.poll_option_label .sel {
|
|||
.topic_list .topic_row {
|
||||
display: flex;
|
||||
}
|
||||
.topics_moderate .topic_row:hover .rowitem {
|
||||
background-color: hsla(0, 0%, 27%, 1);
|
||||
.topics_moderate .topic_row:not(.can_mod) .rowitem {
|
||||
background-color: hsla(0, 0%, 22%, 1);
|
||||
}
|
||||
.topic_selected .rowitem {
|
||||
.topics_moderate .can_mod .rowitem {
|
||||
background-color: hsla(0, 0%, 25%, 1);
|
||||
}
|
||||
.topics_moderate .can_mod:hover .rowitem {
|
||||
background-color: hsla(0, 0%, 29%, 1);
|
||||
}
|
||||
.topic_row.topic_selected .rowitem {
|
||||
background-color: hsla(0, 0%, 31%, 1);
|
||||
}
|
||||
/* Temporary hack, so that I don't break the topic lists of the other themes */
|
||||
.topic_list .topic_inner_right {
|
||||
display: none;
|
||||
|
|
Loading…
Reference in New Issue