From 100303173e1f879cda357b5f955408323d872cb4 Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Sat, 25 Jan 2014 16:34:20 +0100 Subject: [PATCH] Added comment editing support In other news, editing a post doesn't reload page anymore (yay for editing tags for Youtube posts) --- data/config.ini | 2 + public_html/media/css/comment-edit.css | 12 ++ public_html/media/css/comment-small.css | 4 + public_html/media/css/post-view.css | 14 +- public_html/media/js/comment-edit.js | 105 ++++++++++++++ public_html/media/js/post-view.js | 180 ++++++++---------------- src/Controllers/CommentController.php | 34 +++++ src/Controllers/PostController.php | 2 + src/Helpers/TextHelper.php | 7 + src/Models/Enums/Privilege.php | 1 + src/Views/comment-add.phtml | 16 +++ src/Views/comment-edit.phtml | 16 +++ src/Views/comment-list.phtml | 68 ++++----- src/Views/comment-small.phtml | 8 ++ src/Views/post-edit.phtml | 2 +- src/Views/post-view.phtml | 23 +-- 16 files changed, 310 insertions(+), 184 deletions(-) create mode 100644 public_html/media/css/comment-edit.css create mode 100644 public_html/media/js/comment-edit.js create mode 100644 src/Views/comment-add.phtml create mode 100644 src/Views/comment-edit.phtml diff --git a/data/config.ini b/data/config.ini index a4178091..58850975 100644 --- a/data/config.ini +++ b/data/config.ini @@ -117,6 +117,8 @@ listComments=anonymous addComment=registered deleteComment.own=registered deleteComment.all=moderator +editComment.own=registered +editComment.all=admin listTags=anonymous mergeTags=moderator diff --git a/public_html/media/css/comment-edit.css b/public_html/media/css/comment-edit.css new file mode 100644 index 00000000..9baef1ba --- /dev/null +++ b/public_html/media/css/comment-edit.css @@ -0,0 +1,12 @@ +.preview { + border: 1px solid yellow; + background: url('../img/preview.png') lemonchiffon; + padding: 0.5em; + display: none; +} + +form.edit-comment textarea, +form.add-comment textarea { + width: 50em; + height: 8em; +} diff --git a/public_html/media/css/comment-small.css b/public_html/media/css/comment-small.css index 1f5d3227..11069cad 100644 --- a/public_html/media/css/comment-small.css +++ b/public_html/media/css/comment-small.css @@ -31,18 +31,22 @@ } .comment .date, +.comment .edit, .comment .delete { font-size: small; } +.comment .edit:before, .comment .delete:before { margin-left: 0.2em; content: ' ['; color: silver; } +.comment .edit:after, .comment .delete:after { content: ']'; color: silver; } +.comment .edit a, .comment .delete a { color: silver; } diff --git a/public_html/media/css/post-view.css b/public_html/media/css/post-view.css index 7abed60e..a7cc1039 100644 --- a/public_html/media/css/post-view.css +++ b/public_html/media/css/post-view.css @@ -133,7 +133,7 @@ i.icon-dl { margin: 2px; } -form.edit-post { +.unit.edit-post { display: none; } form.edit-post .safety label:not(.left) { @@ -145,15 +145,3 @@ ul.tagit { margin: 0; font-size: 1em; } - -.preview { - border: 1px solid yellow; - background: url('../img/preview.png') lemonchiffon; - padding: 0.5em; - display: none; -} - -form.add-comment textarea { - width: 50em; - height: 8em; -} diff --git a/public_html/media/js/comment-edit.js b/public_html/media/js/comment-edit.js new file mode 100644 index 00000000..c1b00133 --- /dev/null +++ b/public_html/media/js/comment-edit.js @@ -0,0 +1,105 @@ +$(function() +{ + function onDomUpdate() + { + $('form.edit-comment, form.add-comment').submit(function(e) + { + e.preventDefault(); + rememberLastSearchQuery(); + + var formDom = $(this); + if (formDom.hasClass('inactive')) + return; + formDom.addClass('inactive'); + formDom.find(':input').attr('readonly', true); + + var url = formDom.attr('action') + '?json'; + var fd = new FormData(formDom[0]); + + var preview = false; + $.each(formDom.serializeArray(), function(i, x) + { + if (x.name == 'sender' && x.value == 'preview') + preview = true; + }); + + var ajaxData = + { + url: url, + data: fd, + processData: false, + contentType: false, + type: 'POST', + + success: function(data) + { + if (data['success']) + { + if (preview) + { + formDom.find('.preview').html(data['textPreview']).show(); + } + else + { + formDom.find('.preview').hide(); + var cb = function() + { + $.get(window.location.href, function(data) + { + $('.comments-wrapper').replaceWith($(data).find('.comments-wrapper')); + $('body').trigger('dom-update'); + }); + } + if (formDom.hasClass('add-comment')) + { + cb(); + formDom.find('textarea').val(''); + } + else + { + formDom.slideUp(function() + { + cb(); + $(this).remove(); + }); + } + } + formDom.find(':input').attr('readonly', false); + formDom.removeClass('inactive'); + } + else + { + alert(data['message']); + formDom.find(':input').attr('readonly', false); + formDom.removeClass('inactive'); + } + }, + error: function() + { + alert('Fatal error'); + formDom.find(':input').attr('readonly', false); + formDom.removeClass('inactive'); + } + }; + + $.ajax(ajaxData); + }); + + $('.comment .edit a').click(function(e) + { + e.preventDefault(); + var commentDom = $(this).parents('.comment'); + $.get($(this).attr('href'), function(data) + { + commentDom.find('form.edit-comment').remove(); + var otherForm = $(data).find('form.edit-comment'); + otherForm.hide(); + commentDom.find('.body').append(otherForm); + otherForm.slideDown(); + $('body').trigger('dom-update'); + }); + }); + } + + $('body').bind('dom-update', onDomUpdate); +}); diff --git a/public_html/media/js/post-view.js b/public_html/media/js/post-view.js index 0dfebb4d..aa09dc74 100644 --- a/public_html/media/js/post-view.js +++ b/public_html/media/js/post-view.js @@ -1,56 +1,58 @@ -function onDomUpdate() -{ - $('li.edit a').click(function(e) - { - e.preventDefault(); - - var aDom = $(this); - if (aDom.hasClass('inactive')) - return; - aDom.addClass('inactive'); - - var tags = []; - $.getJSON('/tags?json', {filter: 'order:popularity,desc'}, function(data) - { - aDom.removeClass('inactive'); - var formDom = $('form.edit-post'); - tags = data['tags']; - - if (!$(formDom).is(':visible')) - { - var tagItOptions = getTagItOptions(); - tagItOptions.availableTags = tags; - tagItOptions.placeholderText = $('.tags input').attr('placeholder'); - $('.tags input').tagit(tagItOptions); - formDom.show().css('height', formDom.height()).hide().slideDown(); - } - - formDom.find('input[type=text]:visible:eq(0)').focus(); - $('html, body').animate({ scrollTop: $(formDom).offset().top + 'px' }, 'fast'); - }); - }); - - $('.comments.unit a.simple-action').data('callback', function() - { - $.get(window.location.href, function(data) - { - $('.comments-wrapper').replaceWith($(data).find('.comments-wrapper')); - $('body').trigger('dom-update'); - }); - }); - - $('#sidebar a.simple-action').data('callback', function() - { - $.get(window.location.href, function(data) - { - $('#sidebar').replaceWith($(data).find('#sidebar')); - $('body').trigger('dom-update'); - }); - }); -} - $(function() { + function onDomUpdate() + { + $('#sidebar .edit a').click(function(e) + { + e.preventDefault(); + + var aDom = $(this); + if (aDom.hasClass('inactive')) + return; + aDom.addClass('inactive'); + + var formDom = $('form.edit-post'); + if (formDom.find('.tagit').length == 0) + { + $.getJSON('/tags?json', {filter: 'order:popularity,desc'}, function(data) + { + aDom.removeClass('inactive'); + var tags = data['tags']; + + var tagItOptions = getTagItOptions(); + tagItOptions.availableTags = tags; + tagItOptions.placeholderText = $('.tags input').attr('placeholder'); + $('.tags input').tagit(tagItOptions); + }); + } + else + aDom.removeClass('inactive'); + + if (!$(formDom).is(':visible')) + formDom.parents('.unit').show().css('height', formDom.height()).hide().slideDown(); + $('html, body').animate({ scrollTop: $(formDom).offset().top + 'px' }, 'fast'); + formDom.find('input[type=text]:visible:eq(0)').focus(); + }); + + $('.comments.unit a.simple-action').data('callback', function() + { + $.get(window.location.href, function(data) + { + $('.comments-wrapper').replaceWith($(data).find('.comments-wrapper')); + $('body').trigger('dom-update'); + }); + }); + + $('#sidebar a.simple-action').data('callback', function() + { + $.get(window.location.href, function(data) + { + $('#sidebar').replaceWith($(data).find('#sidebar')); + $('body').trigger('dom-update'); + }); + }); + } + $('body').bind('dom-update', onDomUpdate); $('form.edit-post').submit(function(e) @@ -79,82 +81,20 @@ $(function() { if (data['success']) { - window.location.reload(); + $.get(window.location.href, function(data) + { + $('#sidebar').replaceWith($(data).find('#sidebar')); + $('#edit-token').replaceWith($(data).find('#edit-token')); + $('body').trigger('dom-update'); + }); + formDom.parents('.unit').hide(); } else { alert(data['message']); - formDom.find(':input').attr('readonly', false); - formDom.removeClass('inactive'); } - }, - error: function() - { - alert('Fatal error'); formDom.find(':input').attr('readonly', false); formDom.removeClass('inactive'); - } - }; - - $.ajax(ajaxData); - }); - - $('form.add-comment').submit(function(e) - { - e.preventDefault(); - rememberLastSearchQuery(); - - var formDom = $(this); - if (formDom.hasClass('inactive')) - return; - formDom.addClass('inactive'); - formDom.find(':input').attr('readonly', true); - - var url = formDom.attr('action') + '?json'; - var fd = new FormData(formDom[0]); - - var preview = false; - $.each(formDom.serializeArray(), function(i, x) - { - if (x.name == 'sender' && x.value == 'preview') - preview = true; - }); - - var ajaxData = - { - url: url, - data: fd, - processData: false, - contentType: false, - type: 'POST', - - success: function(data) - { - if (data['success']) - { - if (preview) - { - formDom.find('.preview').html(data['textPreview']).show(); - } - else - { - formDom.find('.preview').hide(); - $.get(window.location.href, function(data) - { - $('.comments-wrapper').replaceWith($(data).find('.comments-wrapper')); - $('body').trigger('dom-update'); - }); - formDom.find('textarea').val(''); - } - formDom.find(':input').attr('readonly', false); - formDom.removeClass('inactive'); - } - else - { - alert(data['message']); - formDom.find(':input').attr('readonly', false); - formDom.removeClass('inactive'); - } }, error: function() { diff --git a/src/Controllers/CommentController.php b/src/Controllers/CommentController.php index ad9822e8..18ae6ae4 100644 --- a/src/Controllers/CommentController.php +++ b/src/Controllers/CommentController.php @@ -11,9 +11,11 @@ class CommentController $this->context->stylesheets []= 'post-small.css'; $this->context->stylesheets []= 'comment-list.css'; $this->context->stylesheets []= 'comment-small.css'; + $this->context->stylesheets []= 'comment-edit.css'; $this->context->stylesheets []= 'paginator.css'; if ($this->context->user->hasEnabledEndlessScrolling()) $this->context->scripts []= 'paginator-endless.js'; + $this->context->scripts []= 'comment-edit.js'; $page = intval($page); $commentsPerPage = intval($this->config->comments->commentsPerPage); @@ -52,6 +54,7 @@ class CommentController PrivilegesHelper::confirmEmail($this->context->user); $post = PostModel::findById($postId); + $this->context->transport->post = $post; if (InputHelper::get('submit')) { @@ -66,6 +69,7 @@ class CommentController $comment->setCommenter(null); $comment->commentDate = time(); $comment->text = $text; + if (InputHelper::get('sender') != 'preview') { CommentModel::save($comment); @@ -78,6 +82,36 @@ class CommentController + /** + * @route /comment/{id}/edit + * @validate id [0-9]+ + */ + public function editAction($id) + { + $comment = CommentModel::findById($id); + $this->context->transport->comment = $comment; + + PrivilegesHelper::confirmWithException(Privilege::EditComment, PrivilegesHelper::getIdentitySubPrivilege($comment->getCommenter())); + + if (InputHelper::get('submit')) + { + $text = InputHelper::get('text'); + $text = CommentModel::validateText($text); + + $comment->text = $text; + + if (InputHelper::get('sender') != 'preview') + { + CommentModel::save($comment); + LogHelper::log('{user} has edited comment in {post}', ['post' => TextHelper::reprPost($comment->getPost())]); + } + $this->context->transport->textPreview = $comment->getText(); + StatusHelper::success(); + } + } + + + /** * @route /comment/{id}/delete * @validate id [0-9]+ diff --git a/src/Controllers/PostController.php b/src/Controllers/PostController.php index 561098b6..de9c6961 100644 --- a/src/Controllers/PostController.php +++ b/src/Controllers/PostController.php @@ -462,7 +462,9 @@ class PostController $this->context->pageThumb = \Chibi\UrlHelper::route('post', 'thumb', ['name' => $post->name]); $this->context->stylesheets []= 'post-view.css'; $this->context->stylesheets []= 'comment-small.css'; + $this->context->stylesheets []= 'comment-edit.css'; $this->context->scripts []= 'post-view.js'; + $this->context->scripts []= 'comment-edit.js'; $this->context->subTitle = 'showing ' . TextHelper::reprPost($post) . ' – ' . TextHelper::reprTags($post->getTags()); $this->context->favorite = $favorite; $this->context->score = $score; diff --git a/src/Helpers/TextHelper.php b/src/Helpers/TextHelper.php index 4612816e..b772321b 100644 --- a/src/Helpers/TextHelper.php +++ b/src/Helpers/TextHelper.php @@ -251,6 +251,13 @@ class TextHelper return $path; } + public static function secureWhitespace($text) + { + $text = str_replace(["\r\n", "\r", "\n"], ' ', $text); + $text = str_replace(' ', ' ', $text); + return $text; + } + const HTML_OPEN = 1; const HTML_CLOSE = 2; const HTML_LEAF = 3; diff --git a/src/Models/Enums/Privilege.php b/src/Models/Enums/Privilege.php index 30a8a92e..3fb7a4b0 100644 --- a/src/Models/Enums/Privilege.php +++ b/src/Models/Enums/Privilege.php @@ -34,6 +34,7 @@ class Privilege extends Enum const ListComments = 20; const AddComment = 23; const DeleteComment = 24; + const EditComment = 37; const ListTags = 21; const MergeTags = 27; diff --git a/src/Views/comment-add.phtml b/src/Views/comment-add.phtml new file mode 100644 index 00000000..121e8595 --- /dev/null +++ b/src/Views/comment-add.phtml @@ -0,0 +1,16 @@ +
+

add comment

+ +
+ +
+
+
+ + + +
+   + +
+
diff --git a/src/Views/comment-edit.phtml b/src/Views/comment-edit.phtml new file mode 100644 index 00000000..bc46c0e6 --- /dev/null +++ b/src/Views/comment-edit.phtml @@ -0,0 +1,16 @@ +
+

edit comment

+ +
+ +
+
+
+ + + +
+   + +
+
diff --git a/src/Views/comment-list.phtml b/src/Views/comment-list.phtml index 03bbddcc..0e92cb74 100644 --- a/src/Views/comment-list.phtml +++ b/src/Views/comment-list.phtml @@ -1,41 +1,43 @@ context->transport->comments)): ?>

No comments to show.

-
- context->transport->comments as $comment) - { - if ($comment->postId != $currentGroupPostId) +
+
+ context->transport->comments as $comment) { - unset($currentGroup); - $currentGroup = []; - $currentGroupPostId = $comment->postId; - $posts[$comment->postId] = $comment->getPost(); - $groups[] = &$currentGroup; + if ($comment->postId != $currentGroupPostId) + { + unset($currentGroup); + $currentGroup = []; + $currentGroupPostId = $comment->postId; + $posts[$comment->postId] = $comment->getPost(); + $groups[] = &$currentGroup; + } + $currentGroup []= $comment; } - $currentGroup []= $comment; - } - ?> - -
-
- context->post = $posts[reset($group)->postId] ?> - renderFile('post-small') ?> + ?> + +
+
+ context->post = $posts[reset($group)->postId] ?> + renderFile('post-small') ?> +
+
+ + context->comment = $comment ?> + renderFile('comment-small') ?> + +
+
-
- - context->comment = $comment ?> - renderFile('comment-small') ?> - -
-
-
- -
+ +
- renderFile('paginator') ?> + renderFile('paginator') ?> +
diff --git a/src/Views/comment-small.phtml b/src/Views/comment-small.phtml index 2ee5a09a..debe3293 100644 --- a/src/Views/comment-small.phtml +++ b/src/Views/comment-small.phtml @@ -26,6 +26,14 @@ context->comment->commentDate) ?> + + + + edit + + + + diff --git a/src/Views/post-edit.phtml b/src/Views/post-edit.phtml index 25b88b4b..75dd80ea 100644 --- a/src/Views/post-edit.phtml +++ b/src/Views/post-edit.phtml @@ -1,4 +1,4 @@ -
+

edit post

context->transport->post->getUploader()))): ?>
diff --git a/src/Views/post-view.phtml b/src/Views/post-view.phtml index ec91a4fe..8001a851 100644 --- a/src/Views/post-view.phtml +++ b/src/Views/post-view.phtml @@ -312,7 +312,9 @@
- renderFile('post-edit') ?> +
+ renderFile('post-edit') ?> +
@@ -330,21 +332,8 @@
- -

add comment

- -
- -
-
-
- - - -
-   - -
-
+
+ renderFile('comment-add') ?> +