api, frontend: add comment editing

This commit is contained in:
Adhityaa Chandrasekar 2019-05-15 10:46:51 -07:00
parent ce19cb8842
commit cc1dfee017
4 changed files with 200 additions and 7 deletions

66
api/comment_edit.go Normal file
View File

@ -0,0 +1,66 @@
package main
import (
"net/http"
)
func commentEdit(commentHex string, markdown string) (string, error) {
if commentHex == "" {
return "", errorMissingField
}
html := markdownToHtml(markdown)
statement := `
UPDATE comments
SET markdown = $2, html = $3
WHERE commentHex=$1;
`
_, err := db.Exec(statement, commentHex, markdown, html)
if err != nil {
// TODO: make sure this is the error is actually non-existant commentHex
return "", errorNoSuchComment
}
return html, nil
}
func commentEditHandler(w http.ResponseWriter, r *http.Request) {
type request struct {
CommenterToken *string `json:"commenterToken"`
CommentHex *string `json:"commentHex"`
Markdown *string `json:"markdown"`
}
var x request
if err := bodyUnmarshal(r, &x); err != nil {
bodyMarshal(w, response{"success": false, "message": err.Error()})
return
}
c, err := commenterGetByCommenterToken(*x.CommenterToken)
if err != nil {
bodyMarshal(w, response{"success": false, "message": err.Error()})
return
}
cm, err := commentGetByCommentHex(*x.CommentHex)
if err != nil {
bodyMarshal(w, response{"success": false, "message": err.Error()})
return
}
if cm.CommenterHex != c.CommenterHex {
bodyMarshal(w, response{"success": false, "message": errorNotAuthorised.Error()})
return
}
html, err := commentEdit(*x.CommentHex, *x.Markdown)
if err != nil {
bodyMarshal(w, response{"success": false, "message": err.Error()})
return
}
bodyMarshal(w, response{"success": true, "html": html})
}

View File

@ -51,6 +51,7 @@ func apiRouterInit(router *mux.Router) error {
router.HandleFunc("/api/oauth/sso/callback", ssoCallbackHandler).Methods("GET") router.HandleFunc("/api/oauth/sso/callback", ssoCallbackHandler).Methods("GET")
router.HandleFunc("/api/comment/new", commentNewHandler).Methods("POST") router.HandleFunc("/api/comment/new", commentNewHandler).Methods("POST")
router.HandleFunc("/api/comment/edit", commentEditHandler).Methods("POST")
router.HandleFunc("/api/comment/list", commentListHandler).Methods("POST") router.HandleFunc("/api/comment/list", commentListHandler).Methods("POST")
router.HandleFunc("/api/comment/count", commentCountHandler).Methods("POST") router.HandleFunc("/api/comment/count", commentCountHandler).Methods("POST")
router.HandleFunc("/api/comment/vote", commentVoteHandler).Methods("POST") router.HandleFunc("/api/comment/vote", commentVoteHandler).Methods("POST")

View File

@ -68,6 +68,7 @@
var autoInit; var autoInit;
var isAuthenticated = false; var isAuthenticated = false;
var comments = []; var comments = [];
var commentsMap = {};
var commenters = {}; var commenters = {};
var requireIdentification = true; var requireIdentification = true;
var isModerator = false; var isModerator = false;
@ -76,6 +77,7 @@
var isLocked = false; var isLocked = false;
var stickyCommentHex = "none"; var stickyCommentHex = "none";
var shownReply = {}; var shownReply = {};
var shownEdit = {};
var configuredOauths = {}; var configuredOauths = {};
var popupBoxType = "login"; var popupBoxType = "login";
var oauthButtonsShown = false; var oauthButtonsShown = false;
@ -499,7 +501,7 @@
} }
function textareaCreate(id) { function textareaCreate(id, edit) {
var textareaSuperContainer = create("div"); var textareaSuperContainer = create("div");
var textareaContainer = create("div"); var textareaContainer = create("div");
var textarea = create("textarea"); var textarea = create("textarea");
@ -529,11 +531,19 @@
attrSet(anonymousCheckboxLabel, "for", ID_ANONYMOUS_CHECKBOX + id); attrSet(anonymousCheckboxLabel, "for", ID_ANONYMOUS_CHECKBOX + id);
anonymousCheckboxLabel.innerText = "Comment anonymously"; anonymousCheckboxLabel.innerText = "Comment anonymously";
submitButton.innerText = "Add Comment"; if (edit === true) {
submitButton.innerText = "Save Changes";
} else {
submitButton.innerText = "Add Comment";
}
markdownButton.innerHTML = "<b>M &#8595;</b> &nbsp; Markdown"; markdownButton.innerHTML = "<b>M &#8595;</b> &nbsp; Markdown";
textarea.oninput = autoExpander(textarea); textarea.oninput = autoExpander(textarea);
onclick(submitButton, submitAccountDecide, id); if (edit === true) {
onclick(submitButton, commentEdit, id);
} else {
onclick(submitButton, submitAccountDecide, id);
}
onclick(markdownButton, markdownHelpShow, id); onclick(markdownButton, markdownHelpShow, id);
append(textareaContainer, textarea); append(textareaContainer, textarea);
@ -541,7 +551,7 @@
append(anonymousCheckboxContainer, anonymousCheckbox); append(anonymousCheckboxContainer, anonymousCheckbox);
append(anonymousCheckboxContainer, anonymousCheckboxLabel); append(anonymousCheckboxContainer, anonymousCheckboxLabel);
append(textareaSuperContainer, submitButton); append(textareaSuperContainer, submitButton);
if (!requireIdentification) { if (!requireIdentification && edit !== true) {
append(textareaSuperContainer, anonymousCheckboxContainer); append(textareaSuperContainer, anonymousCheckboxContainer);
} }
append(textareaSuperContainer, markdownButton); append(textareaSuperContainer, markdownButton);
@ -911,6 +921,7 @@
} }
} }
onclick(edit, global.editShow, comment.commentHex);
onclick(collapse, global.commentCollapse, comment.commentHex); onclick(collapse, global.commentCollapse, comment.commentHex);
onclick(approve, global.commentApprove, comment.commentHex); onclick(approve, global.commentApprove, comment.commentHex);
onclick(remove, global.commentDelete, comment.commentHex); onclick(remove, global.commentDelete, comment.commentHex);
@ -933,11 +944,14 @@
append(options, collapse); append(options, collapse);
// append(options, edit); // uncomment when implemented
append(options, downvote); append(options, downvote);
append(options, upvote); append(options, upvote);
append(options, reply); if (comment.commenterHex === selfHex) {
append(options, edit);
} else {
append(options, reply);
}
if (isModerator && parentHex === "root") { if (isModerator && parentHex === "root") {
append(options, sticky); append(options, sticky);
@ -1109,6 +1123,106 @@
} }
function commentEdit(id) {
var textarea = $(ID_TEXTAREA + id);
var markdown = textarea.value;
if (markdown === "") {
classAdd(textarea, "red-border");
return;
} else {
classRemove(textarea, "red-border");
}
var json = {
"commenterToken": commenterTokenGet(),
"commentHex": id,
"markdown": markdown,
};
post(origin + "/api/comment/edit", json, function(resp) {
if (!resp.success) {
errorShow(resp.message);
return;
} else {
errorHide();
}
commentsMap[id].markdown = markdown;
commentsMap[id].html = resp.html;
var editButton = $(ID_EDIT + id);
var textarea = $(ID_SUPER_CONTAINER + id);
textarea.innerHTML = commentsMap[id].html;
textarea.id = ID_TEXT + id;
delete shownEdit[id];
classAdd(editButton, "option-edit");
classRemove(editButton, "option-cancel");
editButton.title = "Edit comment";
editButton = removeAllEventListeners(editButton);
onclick(editButton, global.editShow, id)
var message = "";
if (resp.state === "unapproved") {
message = "Your comment is under moderation.";
} else if (resp.state === "flagged") {
message = "Your comment was flagged as spam and is under moderation.";
}
if (message !== "") {
prepend($(ID_SUPER_CONTAINER + id), messageCreate(message));
}
});
}
global.editShow = function(id) {
if (id in shownEdit && shownEdit[id]) {
return;
}
var text = $(ID_TEXT + id);
shownEdit[id] = true;
text.replaceWith(textareaCreate(id, true));
var textarea = $(ID_TEXTAREA + id);
textarea.innerText = commentsMap[id].markdown;
var editButton = $(ID_EDIT + id);
classRemove(editButton, "option-edit");
classAdd(editButton, "option-cancel");
editButton.title = "Cancel edit";
editButton = removeAllEventListeners(editButton);
onclick(editButton, global.editCollapse, id);
};
global.editCollapse = function(id) {
var editButton = $(ID_EDIT + id);
var textarea = $(ID_SUPER_CONTAINER + id);
textarea.innerHTML = commentsMap[id].html;
textarea.id = ID_TEXT + id;
delete shownEdit[id];
classAdd(editButton, "option-edit");
classRemove(editButton, "option-cancel");
editButton.title = "Edit comment";
editButton = removeAllEventListeners(editButton);
onclick(editButton, global.editShow, id)
}
global.replyShow = function(id) { global.replyShow = function(id) {
if (id in shownReply && shownReply[id]) { if (id in shownReply && shownReply[id]) {
return; return;
@ -1135,7 +1249,7 @@
var el = $(ID_SUPER_CONTAINER + id); var el = $(ID_SUPER_CONTAINER + id);
el.remove(); el.remove();
shownReply[id] = false; delete shownReply[id];
classAdd(replyButton, "option-reply"); classAdd(replyButton, "option-reply");
classRemove(replyButton, "option-cancel"); classRemove(replyButton, "option-cancel");
@ -1198,6 +1312,10 @@
comment.creationDate = new Date(comment.creationDate); comment.creationDate = new Date(comment.creationDate);
parentMap[parentHex].push(comment); parentMap[parentHex].push(comment);
commentsMap[comment.commentHex] = {
"html": comment.html,
"markdown": comment.markdown,
};
}); });
var cards = commentsRecurse(parentMap, "root"); var cards = commentsRecurse(parentMap, "root");

View File

@ -67,6 +67,14 @@
background: $indigo-6; background: $indigo-6;
} }
.commento-option-edit {
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 528.899 528.899" version="1.1" viewBox="0 0 528.899 528.899" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m328.88 89.125l107.59 107.59-272.34 272.34-107.53-107.59 272.28-272.34zm189.23-25.948l-47.981-47.981c-18.543-18.543-48.653-18.543-67.259 0l-45.961 45.961 107.59 107.59 53.611-53.611c14.382-14.383 14.382-37.577 0-51.959zm-517.81 449.51c-1.958 8.812 5.998 16.708 14.811 14.565l119.89-29.069-107.53-107.59-27.173 122.09z"/></svg>');
margin: 12px 6px 12px 6px;
background: $gray-5;
}
.commento-option-remove { .commento-option-remove {
height: 14px; height: 14px;
width: 14px; width: 14px;