api, frontend, db: add comment sorting
Closes https://gitlab.com/commento/commento/issues/215
This commit is contained in:
parent
3101af8a5c
commit
3e1576d494
@ -191,6 +191,7 @@ func commentListHandler(w http.ResponseWriter, r *http.Request) {
|
||||
"requireIdentification": d.RequireIdentification,
|
||||
"isFrozen": d.State == "frozen",
|
||||
"isModerator": isModerator,
|
||||
"defaultSortPolicy": d.DefaultSortPolicy,
|
||||
"attributes": p,
|
||||
"configuredOauths": map[string]bool{
|
||||
"commento": d.CommentoProvider,
|
||||
|
@ -25,4 +25,5 @@ type domain struct {
|
||||
SsoProvider bool `json:"ssoProvider"`
|
||||
SsoSecret string `json:"ssoSecret"`
|
||||
SsoUrl string `json:"ssoUrl"`
|
||||
DefaultSortPolicy string `json:"defaultSortPolicy"`
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ func domainGet(dmn string) (domain, error) {
|
||||
gitlabProvider,
|
||||
ssoProvider,
|
||||
ssoSecret,
|
||||
ssoUrl
|
||||
ssoUrl,
|
||||
defaultSortPolicy
|
||||
FROM domains
|
||||
WHERE domain = $1;
|
||||
`
|
||||
@ -54,7 +55,8 @@ func domainGet(dmn string) (domain, error) {
|
||||
&d.GitlabProvider,
|
||||
&d.SsoProvider,
|
||||
&d.SsoSecret,
|
||||
&d.SsoUrl); err != nil {
|
||||
&d.SsoUrl,
|
||||
&d.DefaultSortPolicy); err != nil {
|
||||
return d, errorNoSuchDomain
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,8 @@ func domainList(ownerHex string) ([]domain, error) {
|
||||
gitlabProvider,
|
||||
ssoProvider,
|
||||
ssoSecret,
|
||||
ssoUrl
|
||||
ssoUrl,
|
||||
defaultSortPolicy
|
||||
FROM domains
|
||||
WHERE ownerHex=$1;
|
||||
`
|
||||
@ -62,7 +63,8 @@ func domainList(ownerHex string) ([]domain, error) {
|
||||
&d.GitlabProvider,
|
||||
&d.SsoProvider,
|
||||
&d.SsoSecret,
|
||||
&d.SsoUrl); err != nil {
|
||||
&d.SsoUrl,
|
||||
&d.DefaultSortPolicy); err != nil {
|
||||
logger.Errorf("cannot Scan domain: %v", err)
|
||||
return nil, errorInternal
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ func domainUpdate(d domain) error {
|
||||
githubProvider=$12,
|
||||
gitlabProvider=$13,
|
||||
ssoProvider=$14,
|
||||
ssoUrl=$15
|
||||
ssoUrl=$15,
|
||||
defaultSortPolicy=$16
|
||||
WHERE domain=$1;
|
||||
`
|
||||
|
||||
@ -44,7 +45,8 @@ func domainUpdate(d domain) error {
|
||||
d.GithubProvider,
|
||||
d.GitlabProvider,
|
||||
d.SsoProvider,
|
||||
d.SsoUrl)
|
||||
d.SsoUrl,
|
||||
d.DefaultSortPolicy)
|
||||
if err != nil {
|
||||
logger.Errorf("cannot update non-moderators: %v", err)
|
||||
return errorInternal
|
||||
|
10
db/20191204173000-sort-method.sql
Normal file
10
db/20191204173000-sort-method.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- Default sort policy for each domain
|
||||
|
||||
CREATE TYPE sortPolicy AS ENUM (
|
||||
'score-desc',
|
||||
'creationdate-desc',
|
||||
'creationdate-asc'
|
||||
);
|
||||
|
||||
ALTER TABLE domains
|
||||
ADD defaultSortPolicy sortPolicy NOT NULL DEFAULT 'score-desc';
|
@ -204,6 +204,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<div class="title">
|
||||
Comment Sorting
|
||||
</div>
|
||||
<div class="answer">
|
||||
<div class="row no-border commento-round-check">
|
||||
<input type="radio" id="defaultSortPolicy-score-desc" value="score-desc" v-model="domains[cd].defaultSortPolicy">
|
||||
<label for="defaultSortPolicy-score-desc">Most upvoted first</label>
|
||||
</div>
|
||||
<div class="row no-border commento-round-check">
|
||||
<input type="radio" id="defaultSortPolicy-creationdate-desc" value="creationdate-desc" v-model="domains[cd].defaultSortPolicy">
|
||||
<label for="defaultSortPolicy-creationdate-desc">Newest first</label>
|
||||
</div>
|
||||
<div class="row no-border commento-round-check">
|
||||
<input type="radio" id="defaultSortPolicy-creationdate-asc" value="creationdate-asc" v-model="domains[cd].defaultSortPolicy">
|
||||
<label for="defaultSortPolicy-creationdate-asc">Oldest first</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
<button id="save-general-button" onclick="window.commento.generalSaveHandler()" class="button">Save Changes</button>
|
||||
</div>
|
||||
@ -320,6 +340,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="question">
|
||||
<div class="title">
|
||||
Default Comment Sorting
|
||||
</div>
|
||||
<div class="answer">
|
||||
<div class="row no-border commento-round-check">
|
||||
<input type="radio" id="defaultSortPolicy-score-desc" value="score-desc" v-model="domains[cd].defaultSortPolicy">
|
||||
<label for="defaultSortPolicy-score-desc">Most upvoted first</label>
|
||||
</div>
|
||||
<div class="row no-border commento-round-check">
|
||||
<input type="radio" id="defaultSortPolicy-creationdate-desc" value="creationdate-desc" v-model="domains[cd].defaultSortPolicy">
|
||||
<label for="defaultSortPolicy-creationdate-desc">Newest first</label>
|
||||
</div>
|
||||
<div class="row no-border commento-round-check">
|
||||
<input type="radio" id="defaultSortPolicy-creationdate-asc" value="creationdate-asc" v-model="domains[cd].defaultSortPolicy">
|
||||
<label for="defaultSortPolicy-creationdate-asc">Oldest first</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
<button id="save-general-button" onclick="window.commento.generalSaveHandler()" class="button">Save Changes</button>
|
||||
</div>
|
||||
|
@ -34,11 +34,13 @@
|
||||
var ID_MOD_TOOLS_LOCK_BUTTON = "commento-mod-tools-lock-button";
|
||||
var ID_ERROR = "commento-error";
|
||||
var ID_LOGGED_CONTAINER = "commento-logged-container";
|
||||
var ID_PRE_COMMENTS_AREA = "commento-pre-comments-area";
|
||||
var ID_COMMENTS_AREA = "commento-comments-area";
|
||||
var ID_SUPER_CONTAINER = "commento-textarea-super-container-";
|
||||
var ID_TEXTAREA_CONTAINER = "commento-textarea-container-";
|
||||
var ID_TEXTAREA = "commento-textarea-";
|
||||
var ID_ANONYMOUS_CHECKBOX = "commento-anonymous-checkbox-";
|
||||
var ID_SORT_POLICY = "commento-sort-policy-";
|
||||
var ID_CARD = "commento-comment-card-";
|
||||
var ID_BODY = "commento-comment-body-";
|
||||
var ID_TEXT = "commento-comment-text-";
|
||||
@ -85,6 +87,7 @@
|
||||
var configuredOauths = {};
|
||||
var popupBoxType = "login";
|
||||
var oauthButtonsShown = false;
|
||||
var sortPolicy = "score-desc";
|
||||
var selfHex = undefined;
|
||||
var mobileView = null;
|
||||
|
||||
@ -388,6 +391,8 @@
|
||||
commenters = Object.assign({}, commenters, resp.commenters)
|
||||
configuredOauths = resp.configuredOauths;
|
||||
|
||||
sortPolicy = resp.defaultSortPolicy;
|
||||
|
||||
call(callback);
|
||||
});
|
||||
}
|
||||
@ -564,13 +569,62 @@
|
||||
}
|
||||
|
||||
|
||||
var sortPolicyNames = {
|
||||
"score-desc": "Upvotes",
|
||||
"creationdate-desc": "Newest",
|
||||
"creationdate-asc": "Oldest",
|
||||
};
|
||||
|
||||
|
||||
function sortPolicyApply(policy) {
|
||||
classRemove($(ID_SORT_POLICY + sortPolicy), "sort-policy-button-selected");
|
||||
|
||||
var commentsArea = $(ID_COMMENTS_AREA);
|
||||
commentsArea.innerHTML = "";
|
||||
sortPolicy = policy;
|
||||
var cards = commentsRecurse(parentMap(comments), "root");
|
||||
if (cards) {
|
||||
append(commentsArea, cards);
|
||||
}
|
||||
|
||||
classAdd($(ID_SORT_POLICY + policy), "sort-policy-button-selected");
|
||||
}
|
||||
|
||||
|
||||
function sortPolicyBox() {
|
||||
var sortPolicyButtonsContainer = create("div");
|
||||
var sortPolicyButtons = create("div");
|
||||
|
||||
classAdd(sortPolicyButtonsContainer, "sort-policy-buttons-container");
|
||||
classAdd(sortPolicyButtons, "sort-policy-buttons");
|
||||
|
||||
for (var sp in sortPolicyNames) {
|
||||
var sortPolicyButton = create("a");
|
||||
sortPolicyButton.id = ID_SORT_POLICY + sp;
|
||||
classAdd(sortPolicyButton, "sort-policy-button");
|
||||
if (sp === sortPolicy) {
|
||||
classAdd(sortPolicyButton, "sort-policy-button-selected");
|
||||
}
|
||||
sortPolicyButton.innerText = sortPolicyNames[sp];
|
||||
onclick(sortPolicyButton, sortPolicyApply, sp);
|
||||
append(sortPolicyButtons, sortPolicyButton)
|
||||
}
|
||||
|
||||
append(sortPolicyButtonsContainer, sortPolicyButtons);
|
||||
|
||||
return sortPolicyButtonsContainer
|
||||
}
|
||||
|
||||
|
||||
function rootCreate(callback) {
|
||||
var login = create("div");
|
||||
var loginText = create("div");
|
||||
var mainArea = $(ID_MAIN_AREA);
|
||||
var preCommentsArea = create("div");
|
||||
var commentsArea = create("div");
|
||||
|
||||
login.id = ID_LOGIN;
|
||||
preCommentsArea.id = ID_PRE_COMMENTS_AREA;
|
||||
commentsArea.id = ID_COMMENTS_AREA;
|
||||
|
||||
classAdd(login, "login");
|
||||
@ -601,6 +655,12 @@
|
||||
append(mainArea, textareaCreate("root"));
|
||||
}
|
||||
|
||||
if (comments.length > 0) {
|
||||
append(mainArea, sortPolicyBox());
|
||||
}
|
||||
|
||||
append(mainArea, preCommentsArea);
|
||||
|
||||
append(mainArea, commentsArea);
|
||||
append(root, mainArea);
|
||||
|
||||
@ -696,7 +756,7 @@
|
||||
onclick(replyButton, global.replyShow, id)
|
||||
} else {
|
||||
textarea.value = "";
|
||||
insertAfter(textareaSuperContainer, newCard);
|
||||
insertAfter($(ID_PRE_COMMENTS_AREA), newCard);
|
||||
}
|
||||
|
||||
call(callback);
|
||||
@ -762,6 +822,27 @@
|
||||
}
|
||||
|
||||
|
||||
var sortPolicyFunctions = {
|
||||
"score-desc": function(a, b) {
|
||||
return b.score - a.score;
|
||||
},
|
||||
"creationdate-desc": function(a, b) {
|
||||
if (a.creationDate < b.creationDate) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
"creationdate-asc": function(a, b) {
|
||||
if (a.creationDate < b.creationDate) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
function commentsRecurse(parentMap, parentHex) {
|
||||
var cur = parentMap[parentHex];
|
||||
if (!cur || !cur.length) {
|
||||
@ -775,15 +856,7 @@
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
if (a.score !== b.score) {
|
||||
return b.score - a.score;
|
||||
}
|
||||
|
||||
if (a.creationDate < b.creationDate) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
return sortPolicyFunctions[sortPolicy](a, b);
|
||||
});
|
||||
|
||||
var curTime = (new Date()).getTime();
|
||||
@ -1325,28 +1398,31 @@
|
||||
}
|
||||
|
||||
|
||||
function commentsRender() {
|
||||
var parentMap = {};
|
||||
var parentHex;
|
||||
|
||||
var commentsArea = $(ID_COMMENTS_AREA);
|
||||
|
||||
function parentMap(comments) {
|
||||
var m = {};
|
||||
comments.forEach(function(comment) {
|
||||
parentHex = comment.parentHex;
|
||||
if (!(parentHex in parentMap)) {
|
||||
parentMap[parentHex] = [];
|
||||
var parentHex = comment.parentHex;
|
||||
if (!(parentHex in m)) {
|
||||
m[parentHex] = [];
|
||||
}
|
||||
|
||||
comment.creationDate = new Date(comment.creationDate);
|
||||
|
||||
parentMap[parentHex].push(comment);
|
||||
console.log(m, parentHex);
|
||||
m[parentHex].push(comment);
|
||||
commentsMap[comment.commentHex] = {
|
||||
"html": comment.html,
|
||||
"markdown": comment.markdown,
|
||||
};
|
||||
});
|
||||
|
||||
var cards = commentsRecurse(parentMap, "root");
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
function commentsRender() {
|
||||
var commentsArea = $(ID_COMMENTS_AREA);
|
||||
var cards = commentsRecurse(parentMap(comments), "root");
|
||||
if (cards) {
|
||||
append(commentsArea, cards);
|
||||
}
|
||||
|
@ -57,6 +57,30 @@
|
||||
font-weight: 700;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.commento-sort-policy-buttons-container {
|
||||
padding: 12px 0px;
|
||||
font-weight: 400;
|
||||
|
||||
.commento-sort-policy-buttons {
|
||||
float: right;
|
||||
|
||||
.commento-sort-policy-button {
|
||||
color: $gray-6;
|
||||
font-size: 13px;
|
||||
padding: 0px 7px;
|
||||
}
|
||||
|
||||
.commento-sort-policy-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.commento-sort-policy-button-selected {
|
||||
color: $blue-8;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.commento-root-font {
|
||||
|
Loading…
Reference in New Issue
Block a user