frontend,api: open source comment sticky
This commit is contained in:
parent
cf0b394b05
commit
610b61831d
@ -7,4 +7,5 @@ type page struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
IsLocked bool `json:"isLocked"`
|
IsLocked bool `json:"isLocked"`
|
||||||
CommentCount int `json:"commentCount"`
|
CommentCount int `json:"commentCount"`
|
||||||
|
StickyCommentHex string `json:"stickyCommentHex"`
|
||||||
}
|
}
|
||||||
|
@ -11,20 +11,21 @@ func pageGet(domain string, path string) (page, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
statement := `
|
statement := `
|
||||||
SELECT isLocked, commentCount
|
SELECT isLocked, commentCount, stickyCommentHex
|
||||||
FROM pages
|
FROM pages
|
||||||
WHERE domain=$1 AND path=$2;
|
WHERE domain=$1 AND path=$2;
|
||||||
`
|
`
|
||||||
row := db.QueryRow(statement, domain, path)
|
row := db.QueryRow(statement, domain, path)
|
||||||
|
|
||||||
p := page{Domain: domain, Path: path}
|
p := page{Domain: domain, Path: path}
|
||||||
if err := row.Scan(&p.IsLocked, &p.CommentCount); err != nil {
|
if err := row.Scan(&p.IsLocked, &p.CommentCount, &p.StickyCommentHex); err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
// If there haven't been any comments, there won't be a record for this
|
// If there haven't been any comments, there won't be a record for this
|
||||||
// page. The sane thing to do is return defaults.
|
// page. The sane thing to do is return defaults.
|
||||||
// TODO: the defaults are hard-coded in two places: here and the schema
|
// TODO: the defaults are hard-coded in two places: here and the schema
|
||||||
p.IsLocked = false
|
p.IsLocked = false
|
||||||
p.CommentCount = 0
|
p.CommentCount = 0
|
||||||
|
p.StickyCommentHex = "none"
|
||||||
} else {
|
} else {
|
||||||
logger.Errorf("error scanning page: %v", err)
|
logger.Errorf("error scanning page: %v", err)
|
||||||
return page{}, errorInternal
|
return page{}, errorInternal
|
||||||
|
@ -13,12 +13,12 @@ func pageUpdate(p page) error {
|
|||||||
// commentCount
|
// commentCount
|
||||||
statement := `
|
statement := `
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
pages (domain, path, isLocked)
|
pages (domain, path, isLocked, stickyCommentHex)
|
||||||
VALUES ($1, $2, $3 )
|
VALUES ($1, $2, $3, $4 )
|
||||||
ON CONFLICT (domain, path) DO
|
ON CONFLICT (domain, path) DO
|
||||||
UPDATE SET isLocked = $3;
|
UPDATE SET isLocked = $3, stickyCommentHex = $4;
|
||||||
`
|
`
|
||||||
_, err := db.Exec(statement, p.Domain, p.Path, p.IsLocked)
|
_, err := db.Exec(statement, p.Domain, p.Path, p.IsLocked, p.StickyCommentHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("error setting page attributes: %v", err)
|
logger.Errorf("error setting page attributes: %v", err)
|
||||||
return errorInternal
|
return errorInternal
|
||||||
|
2
db/20181218183803-sticky-comments.sql
Normal file
2
db/20181218183803-sticky-comments.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE pages
|
||||||
|
ADD stickyCommentHex TEXT NOT NULL DEFAULT 'none';
|
@ -47,6 +47,7 @@
|
|||||||
var ID_DOWNVOTE = "commento-comment-downvote-";
|
var ID_DOWNVOTE = "commento-comment-downvote-";
|
||||||
var ID_APPROVE = "commento-comment-approve-";
|
var ID_APPROVE = "commento-comment-approve-";
|
||||||
var ID_REMOVE = "commento-comment-remove-";
|
var ID_REMOVE = "commento-comment-remove-";
|
||||||
|
var ID_STICKY = "commento-comment-sticky-";
|
||||||
var ID_CONTENTS = "commento-comment-contents-";
|
var ID_CONTENTS = "commento-comment-contents-";
|
||||||
var ID_SUBMIT_BUTTON = "commento-submit-button-";
|
var ID_SUBMIT_BUTTON = "commento-submit-button-";
|
||||||
var ID_FOOTER = "commento-footer";
|
var ID_FOOTER = "commento-footer";
|
||||||
@ -67,6 +68,7 @@
|
|||||||
var shownSubmitButton = {"root": false};
|
var shownSubmitButton = {"root": false};
|
||||||
var chosenAnonymous = false;
|
var chosenAnonymous = false;
|
||||||
var isLocked = false;
|
var isLocked = false;
|
||||||
|
var stickyCommentHex = "none";
|
||||||
var shownReply = {};
|
var shownReply = {};
|
||||||
var configuredOauths = [];
|
var configuredOauths = [];
|
||||||
var loginBoxType = "signup";
|
var loginBoxType = "signup";
|
||||||
@ -341,6 +343,7 @@
|
|||||||
isFrozen = resp.isFrozen;
|
isFrozen = resp.isFrozen;
|
||||||
|
|
||||||
isLocked = resp.attributes.isLocked;
|
isLocked = resp.attributes.isLocked;
|
||||||
|
stickyCommentHex = resp.attributes.stickyCommentHex;
|
||||||
|
|
||||||
comments = resp.comments;
|
comments = resp.comments;
|
||||||
commenters = resp.commenters;
|
commenters = resp.commenters;
|
||||||
@ -449,10 +452,14 @@
|
|||||||
|
|
||||||
commentsArea.innerHTML = "";
|
commentsArea.innerHTML = "";
|
||||||
|
|
||||||
if (!isLocked)
|
if (isLocked) {
|
||||||
append(mainArea, textareaCreate("root"));
|
if (isAuthenticated)
|
||||||
|
append(mainArea, messageCreate("This thread is locked. You cannot add new comments."));
|
||||||
else
|
else
|
||||||
append(mainArea, messageCreate("This thread is locked. You cannot create new comments."));
|
append(mainArea, textareaCreate("root"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
append(mainArea, textareaCreate("root"));
|
||||||
|
|
||||||
append(mainArea, commentsArea);
|
append(mainArea, commentsArea);
|
||||||
append(root, mainArea);
|
append(root, mainArea);
|
||||||
@ -588,6 +595,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
cur.sort(function(a, b) {
|
cur.sort(function(a, b) {
|
||||||
|
if (a.commentHex == stickyCommentHex)
|
||||||
|
return -Infinity;
|
||||||
|
if (b.commentHex == stickyCommentHex)
|
||||||
|
return Infinity;
|
||||||
return b.score - a.score;
|
return b.score - a.score;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -608,6 +619,7 @@
|
|||||||
var downvote = create("button");
|
var downvote = create("button");
|
||||||
var approve = create("button");
|
var approve = create("button");
|
||||||
var remove = create("button");
|
var remove = create("button");
|
||||||
|
var sticky = create("button");
|
||||||
var children = commentsRecurse(parentMap, comment.commentHex);
|
var children = commentsRecurse(parentMap, comment.commentHex);
|
||||||
var contents = create("div");
|
var contents = create("div");
|
||||||
var color = colorGet(commenter.name);
|
var color = colorGet(commenter.name);
|
||||||
@ -629,6 +641,7 @@
|
|||||||
downvote.id = ID_DOWNVOTE + comment.commentHex;
|
downvote.id = ID_DOWNVOTE + comment.commentHex;
|
||||||
approve.id = ID_APPROVE + comment.commentHex;
|
approve.id = ID_APPROVE + comment.commentHex;
|
||||||
remove.id = ID_REMOVE + comment.commentHex;
|
remove.id = ID_REMOVE + comment.commentHex;
|
||||||
|
sticky.id = ID_STICKY + comment.commentHex;
|
||||||
contents.id = ID_CONTENTS + comment.commentHex;
|
contents.id = ID_CONTENTS + comment.commentHex;
|
||||||
|
|
||||||
collapse.title = "Collapse";
|
collapse.title = "Collapse";
|
||||||
@ -638,6 +651,14 @@
|
|||||||
reply.title = "Reply";
|
reply.title = "Reply";
|
||||||
approve.title = "Approve";
|
approve.title = "Approve";
|
||||||
remove.title = "Remove";
|
remove.title = "Remove";
|
||||||
|
if (stickyCommentHex == comment.commentHex) {
|
||||||
|
if (isModerator)
|
||||||
|
sticky.title = "Unsticky";
|
||||||
|
else
|
||||||
|
sticky.title = "This comment has been stickied";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sticky.title = "Sticky";
|
||||||
|
|
||||||
card.style["borderLeft"] = "2px solid " + color;
|
card.style["borderLeft"] = "2px solid " + color;
|
||||||
name.innerText = commenter.name;
|
name.innerText = commenter.name;
|
||||||
@ -684,6 +705,11 @@
|
|||||||
classAdd(approve, "option-approve");
|
classAdd(approve, "option-approve");
|
||||||
classAdd(remove, "option-button");
|
classAdd(remove, "option-button");
|
||||||
classAdd(remove, "option-remove");
|
classAdd(remove, "option-remove");
|
||||||
|
classAdd(sticky, "option-button");
|
||||||
|
if (stickyCommentHex == comment.commentHex)
|
||||||
|
classAdd(sticky, "option-unsticky");
|
||||||
|
else
|
||||||
|
classAdd(sticky, "option-sticky");
|
||||||
|
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
if (comment.direction > 0)
|
if (comment.direction > 0)
|
||||||
@ -696,6 +722,7 @@
|
|||||||
attrSet(collapse, "onclick", "commentCollapse('" + comment.commentHex + "')");
|
attrSet(collapse, "onclick", "commentCollapse('" + comment.commentHex + "')");
|
||||||
attrSet(approve, "onclick", "commentApprove('" + comment.commentHex + "')");
|
attrSet(approve, "onclick", "commentApprove('" + comment.commentHex + "')");
|
||||||
attrSet(remove, "onclick", "commentDelete('" + comment.commentHex + "')");
|
attrSet(remove, "onclick", "commentDelete('" + comment.commentHex + "')");
|
||||||
|
attrSet(sticky, "onclick", "commentSticky('" + comment.commentHex + "')");
|
||||||
|
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
if (comment.direction > 0) {
|
if (comment.direction > 0) {
|
||||||
@ -730,14 +757,19 @@
|
|||||||
append(options, downvote);
|
append(options, downvote);
|
||||||
append(options, upvote);
|
append(options, upvote);
|
||||||
|
|
||||||
if (!isLocked)
|
|
||||||
append(options, reply);
|
append(options, reply);
|
||||||
|
|
||||||
if (isModerator) {
|
if (isModerator) {
|
||||||
|
if (parentHex == "root")
|
||||||
|
append(options, sticky);
|
||||||
append(options, remove);
|
append(options, remove);
|
||||||
if (comment.state == "unapproved")
|
if (comment.state == "unapproved")
|
||||||
append(options, approve);
|
append(options, approve);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (stickyCommentHex == comment.commentHex)
|
||||||
|
append(options, sticky);
|
||||||
|
}
|
||||||
|
|
||||||
attrSet(options, "style", "width: " + ((options.childNodes.length+1)*32) + "px;");
|
attrSet(options, "style", "width: " + ((options.childNodes.length+1)*32) + "px;");
|
||||||
for (var i = 0; i < options.childNodes.length; i++)
|
for (var i = 0; i < options.childNodes.length; i++)
|
||||||
@ -1278,6 +1310,7 @@
|
|||||||
function pageUpdate(callback) {
|
function pageUpdate(callback) {
|
||||||
var attributes = {
|
var attributes = {
|
||||||
"isLocked": isLocked,
|
"isLocked": isLocked,
|
||||||
|
"stickyCommentHex": stickyCommentHex,
|
||||||
};
|
};
|
||||||
|
|
||||||
var json = {
|
var json = {
|
||||||
@ -1314,6 +1347,32 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
global.commentSticky = function(commentHex) {
|
||||||
|
if (stickyCommentHex != "none") {
|
||||||
|
var sticky = $(ID_STICKY + stickyCommentHex);
|
||||||
|
classRemove(sticky, "option-unsticky");
|
||||||
|
classAdd(sticky, "option-sticky");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stickyCommentHex == commentHex)
|
||||||
|
stickyCommentHex = "none";
|
||||||
|
else
|
||||||
|
stickyCommentHex = commentHex;
|
||||||
|
|
||||||
|
pageUpdate(function(success) {
|
||||||
|
var sticky = $(ID_STICKY + commentHex);
|
||||||
|
if (stickyCommentHex == commentHex) {
|
||||||
|
classRemove(sticky, "option-sticky");
|
||||||
|
classAdd(sticky, "option-unsticky");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
classRemove(sticky, "option-unsticky");
|
||||||
|
classAdd(sticky, "option-sticky");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function mainAreaCreate() {
|
function mainAreaCreate() {
|
||||||
var mainArea = create("div");
|
var mainArea = create("div");
|
||||||
|
|
||||||
|
@ -83,6 +83,20 @@
|
|||||||
background: $green-7;
|
background: $green-7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.commento-option-sticky,
|
||||||
|
.commento-option-unsticky {
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
@include mask-image('data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8"?><svg enable-background="new 0 0 487.222 487.222" version="1.1" viewBox="0 0 487.22 487.22" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m486.55 186.81c-1.6-4.9-5.8-8.4-10.9-9.2l-152-21.6-68.4-137.5c-2.3-4.6-7-7.5-12.1-7.5s-9.8 2.9-12.1 7.6l-67.5 137.9-152 22.6c-5.1 0.8-9.3 4.3-10.9 9.2s-0.2 10.3 3.5 13.8l110.3 106.9-25.5 151.4c-0.9 5.1 1.2 10.2 5.4 13.2 2.3 1.7 5.1 2.6 7.9 2.6 2.2 0 4.3-0.5 6.3-1.6l135.7-71.9 136.1 71.1c2 1 4.1 1.5 6.2 1.5 7.4 0 13.5-6.1 13.5-13.5 0-1.1-0.1-2.1-0.4-3.1l-26.3-150.5 109.6-107.5c3.9-3.6 5.2-9 3.6-13.9zm-137 107.1c-3.2 3.1-4.6 7.6-3.8 12l22.9 131.3-118.2-61.7c-3.9-2.1-8.6-2-12.6 0l-117.8 62.4 22.1-131.5c0.7-4.4-0.7-8.8-3.9-11.9l-95.6-92.8 131.9-19.6c4.4-0.7 8.2-3.4 10.1-7.4l58.6-119.7 59.4 119.4c2 4 5.8 6.7 10.2 7.4l132 18.8-95.3 93.3z" fill="%231e2127"/></svg>');
|
||||||
|
margin: 12px 6px 12px 6px;
|
||||||
|
background: $gray-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.commento-option-unsticky {
|
||||||
|
@include mask-image('data:image/svg+xml;utf8,<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 487.22 487.22" xmlns="http://www.w3.org/2000/svg"><g><title>background</title><rect x="-1" y="-1" fill="none"/></g><g><title>Layer 1</title><path d="m486.55 186.81c-1.6-4.9-5.8-8.4-10.9-9.2l-152-21.6-68.4-137.5c-2.3-4.6-7-7.5-12.1-7.5s-9.8 2.9-12.1 7.6l-67.5 137.9-152 22.6c-5.1 0.8-9.3 4.3-10.9 9.2s-0.2 10.3 3.5 13.8l110.3 106.9-25.5 151.4c-0.9 5.1 1.2 10.2 5.4 13.2 2.3 1.7 5.1 2.6 7.9 2.6 2.2 0 4.3-0.5 6.3-1.6l135.7-71.9 136.1 71.1c2 1 4.1 1.5 6.2 1.5 7.4 0 13.5-6.1 13.5-13.5 0-1.1-0.1-2.1-0.4-3.1l-26.3-150.5 109.6-107.5c3.9-3.6 5.2-9 3.6-13.9z" fill="%231e2127"/></g></svg>');
|
||||||
|
background: $yellow-7;
|
||||||
|
}
|
||||||
|
|
||||||
.commento-option-button:focus {
|
.commento-option-button:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user