diff --git a/wire/modules/Process/ProcessCommentsManager/ProcessCommentsManager.css b/wire/modules/Process/ProcessCommentsManager/ProcessCommentsManager.css index 296cc324..fe239f34 100644 --- a/wire/modules/Process/ProcessCommentsManager/ProcessCommentsManager.css +++ b/wire/modules/Process/ProcessCommentsManager/ProcessCommentsManager.css @@ -1 +1,279 @@ -#CommentListHeader{padding-top:.5em;padding-bottom:.5em}#CommentListHeader>p{line-height:2.25em;padding-right:1em;margin-top:.25em;margin-bottom:.25em}#CommentListHeader .MarkupPagerNav{margin-top:0;margin-bottom:.5em}#CommentListHeader .CommentLimitSelect{float:left}#CommentListHeader .CommentCheckAll{display:block;float:left;padding-left:.75em}#CommentListHeader .CommentActions{float:left}#CommentListHeader .CommentSorts{float:left}.CommentItems{clear:both;border-bottom:1px solid #777}.CommentItems+button.ui-button{margin-top:1em}.CommentItem{clear:both;border-top:1px solid #777;padding:.75em 0;margin:0;width:100%}.CommentItem.CommentChecked{background-color:#eee}.CommentItem.CommentChecked th{color:#999}.CommentItem table{width:45%;float:left}.CommentItem table th,.CommentItem table td{padding:4px 10px 4px 0;border-bottom:1px solid #ddd;vertical-align:top;line-height:1.8}.CommentItem table th{font-weight:bold;white-space:nowrap;text-align:left;padding-left:.75em !important}.CommentItem table th:first-child{width:80px}.CommentItem table tr:last-child td,.CommentItem table tr:last-child th{border-bottom:none}.CommentItem .CommentTitle th,.CommentItem .CommentTitle td{padding-top:0}.CommentItem .CommentInput{max-width:80%}.CommentItem .CommentChangedIcon{display:none}.CommentItem.CommentItemChanged .CommentChangedIcon{display:inline;float:right;opacity:.3}.CommentItem input[type=number]{width:4em}.CommentItem .CommentVotes label{margin-right:5px}.CommentItem .CommentVotes .CommentUpvotes span{font-weight:bold;color:green;margin-right:2px}.CommentItem .CommentVotes .CommentDownvotes span{font-weight:bold;color:red;margin-right:2px}.CommentItem .CommentID{font-weight:normal;color:#333}.CommentItem .CommentWhere small{margin-right:2px}.CommentItem .CommentWhere input{width:80px}.CommentItem .CommentStars>span{display:inline;cursor:pointer;padding-right:3px}.CommentItem .CommentStars>span i.fa{font-size:18px !important}.CommentItem .CommentContent{float:left;width:55%;padding-left:1em;border:none}.CommentItem .CommentContent .CommentChildrenInfo{margin-top:.5em}.CommentItem .CommentContent .CommentReplyInfo{margin-bottom:0}.CommentItem .CommentContent .CommentText{cursor:pointer;padding-right:1em}.CommentItem .CommentContent .CommentText textarea{font-size:1em;width:100%;min-height:18em;margin-top:1em;margin-bottom:1em}.CommentItem .CommentContent .CommentText .CommentTextEdit{white-space:nowrap}.CommentItem .CommentContent .CommentTextOverflow{overflow-y:scroll;max-height:18em}.CommentItem .CommentContent.CommentContentLarge .CommentTextOverflow{max-height:24em}.CommentItem label.CommentStatus{white-space:nowrap;display:inline-block}.CommentItem.CommentItemStatus999{display:none}.CommentCheckAll label .detail,.CommentItem .CommentTitle th label .detail{font-weight:bold;color:#444}.pw-content .MarkupPagerNav{padding-top:.5em;float:right}.pw-content .MarkupPagerNav+button{margin-top:1em}.AdminThemeReno .pw-content .MarkupPagerNav li a,.AdminThemeReno .pw-content .MarkupPagerNav li:first-child a,.AdminThemeReno .pw-content .MarkupPagerNav li.MarkupPagerNavOn a{border-color:#fff !important;border:none !important;border-left:1px solid #fff !important}.AdminThemeReno .pw-content .MarkupPagerNav li{margin-bottom:1px}.AdminThemeReno .pw-content #CommentListHeader{border-top:1px solid #eee}.AdminThemeReno .pw-content #CommentListHeader .MarkupPagerNav{margin-top:.5em}@media only screen and (max-width: 960px){.pw-content .MarkupPagerNav{float:none}#CommentListHeader{padding-bottom:1em;padding-top:1em}#CommentListHeader .MarkupPagerNav{float:none}#CommentListHeader p{margin-top:0;margin-bottom:0;padding-right:1em;padding-left:0 !important}#CommentListHeader .CommentCheckAll{width:auto}}@media only screen and (max-width: 768px){.CommentItem table{width:100%;float:none}.CommentItem table th{padding-left:0 !important}.CommentItem .CommentContent{width:100%;float:none;padding-left:0}.CommentItem .CommentContent .CommentText{padding-right:0}.CommentItem .CommentContent .CommentTextOverflow{overflow-y:auto;max-height:inherit}}.WireTabs{opacity:0} +#CommentListHeader { + padding-top: 0.5em; + padding-bottom: 0.5em; +} +#CommentListHeader > p { + line-height: 2.25em; + padding-right: 1em; + margin-top: 0.25em; + margin-bottom: 0.25em; +} +#CommentListHeader .MarkupPagerNav { + margin-top: 0; + margin-bottom: 0.5em; +} +#CommentListHeader .CommentLimitSelect { + float: left; +} +#CommentListHeader .CommentCheckAll { + display: block; + float: left; + padding-left: 0.75em; +} +#CommentListHeader .CommentActions { + float: left; +} +#CommentListHeader .CommentSorts { + float: left; +} + +.CommentItems { + clear: both; + border-bottom: 1px solid #777; +} +.CommentItems + button.ui-button { + margin-top: 1em; +} + +.CommentItem { + clear: both; + border-top: 1px solid #777; + padding: 0.75em 0; + margin: 0; + width: 100%; + /* + &.CommentItemStatus-2 .CommentText { + background: #ffffcc; + } + + &.CommentItemStatus0 .CommentText { + background: #ffffdd; + } + */ +} +.CommentItem.CommentChecked { + background-color: #eee; +} +.CommentItem.CommentChecked th { + color: #999; +} +.CommentItem table { + /* + margin-top: 0.7em; + margin-bottom: 0.7em; + */ + width: 45%; + float: left; +} +.CommentItem table th, +.CommentItem table td { + padding: 4px 10px 4px 0; + border-bottom: 1px solid #ddd; + vertical-align: top; + line-height: 1.8; +} +.CommentItem table th { + font-weight: bold; + white-space: nowrap; + text-align: left; + padding-left: 0.75em !important; +} +.CommentItem table th:first-child { + width: 80px; +} +.CommentItem table tr:last-child td, .CommentItem table tr:last-child th { + border-bottom: none; +} +.CommentItem .CommentTitle th, +.CommentItem .CommentTitle td { + padding-top: 0; +} +.CommentItem .CommentInput { + max-width: 80%; +} +.CommentItem .CommentChangedIcon { + display: none; +} +.CommentItem.CommentItemChanged .CommentChangedIcon { + display: inline; + float: right; + opacity: 0.3; +} +.CommentItem input[type=number] { + width: 4em; +} +.CommentItem .CommentVotes label { + margin-right: 5px; +} +.CommentItem .CommentVotes .CommentUpvotes span { + font-weight: bold; + color: green; + margin-right: 2px; +} +.CommentItem .CommentVotes .CommentDownvotes span { + font-weight: bold; + color: red; + margin-right: 2px; +} +.CommentItem .CommentID { + font-weight: normal; + color: #333; +} +.CommentItem .CommentWhere small { + margin-right: 2px; +} +.CommentItem .CommentWhere input { + width: 80px; +} +.CommentItem .CommentContent { + float: left; + width: 55%; + padding-left: 1em; + border: none; +} +.CommentItem .CommentContent .CommentChildrenInfo { + margin-top: 0.5em; +} +.CommentItem .CommentContent .CommentReplyInfo { + margin-bottom: 0; +} +.CommentItem .CommentContent .CommentText { + cursor: pointer; + padding-right: 1em; +} +.CommentItem .CommentContent .CommentText textarea { + font-size: 1em; + width: 100%; + min-height: 18em; + margin-top: 1em; + margin-bottom: 1em; +} +.CommentItem .CommentContent .CommentText .CommentTextEdit { + white-space: nowrap; +} +.CommentItem .CommentContent .CommentText .CommentTextEditable { + /* + p { + margin: 1em 0; + } + & > p:first-child { + margin-top: 0; + } + */ +} +.CommentItem .CommentContent .CommentTextOverflow { + overflow-y: scroll; + max-height: 18em; +} +.CommentItem .CommentContent.CommentContentLarge .CommentTextOverflow { + max-height: 24em; +} +.CommentItem label.CommentStatus { + white-space: nowrap; + display: inline-block; +} +.CommentItem select.CommentStatus { + width: auto; +} +.CommentItem select.CommentStatus.uk-select { + padding-right: 30px; +} +.CommentItem.CommentItemStatus999 { + display: none; +} + +.CommentCheckAll label .detail, +.CommentItem .CommentTitle th label .detail { + font-weight: bold; + color: #444; +} + +.pw-content .MarkupPagerNav { + padding-top: 0.5em; + float: right; +} +.pw-content .MarkupPagerNav + button { + margin-top: 1em; +} + +.AdminThemeReno .pw-content .MarkupPagerNav li a, +.AdminThemeReno .pw-content .MarkupPagerNav li:first-child a, +.AdminThemeReno .pw-content .MarkupPagerNav li.MarkupPagerNavOn a { + border-color: #fff !important; + border: none !important; + border-left: 1px solid #fff !important; +} +.AdminThemeReno .pw-content .MarkupPagerNav li { + margin-bottom: 1px; +} +.AdminThemeReno .pw-content #CommentListHeader { + border-top: 1px solid #eee; +} +.AdminThemeReno .pw-content #CommentListHeader .MarkupPagerNav { + margin-top: 0.5em; +} + +@media only screen and (max-width: 960px) { + .pw-content .MarkupPagerNav { + float: none; + } + + #CommentListHeader { + padding-bottom: 1em; + padding-top: 1em; + } + #CommentListHeader .MarkupPagerNav { + float: none; + } + #CommentListHeader p { + margin-top: 0; + margin-bottom: 0; + padding-right: 1em; + padding-left: 0 !important; + } + #CommentListHeader .CommentCheckAll { + width: auto; + } +} +@media only screen and (max-width: 768px) { + .CommentItem table { + width: 100%; + float: none; + } + .CommentItem table th { + padding-left: 0 !important; + } + .CommentItem .CommentContent { + width: 100%; + float: none; + padding-left: 0; + } + .CommentItem .CommentContent .CommentText { + padding-right: 0; + } + .CommentItem .CommentContent .CommentTextOverflow { + overflow-y: auto; + max-height: inherit; + } +} +.CommentItem .CommentStars > span, +.InputfieldForm .CommentStars > span { + display: inline; + cursor: pointer; + padding-right: 3px; +} +.CommentItem .CommentStars > span i.fa, +.InputfieldForm .CommentStars > span i.fa { + font-size: 18px !important; +} + +.WireTabs { + opacity: 0; +} + +blockquote { + padding-left: 30px; + border-left: 3px solid #ccc; + color: #777; +} + diff --git a/wire/modules/Process/ProcessCommentsManager/ProcessCommentsManager.module b/wire/modules/Process/ProcessCommentsManager/ProcessCommentsManager.module index f1af27b6..57762288 100644 --- a/wire/modules/Process/ProcessCommentsManager/ProcessCommentsManager.module +++ b/wire/modules/Process/ProcessCommentsManager/ProcessCommentsManager.module @@ -10,6 +10,8 @@ * This file licensed under Mozilla Public License v2.0 http://mozilla.org/MPL/2.0/ * * https://processwire.com + * + * @method string renderComment(Comment $comment, array $options = array()) * */ @@ -23,7 +25,7 @@ class ProcessCommentsManager extends Process { return array( 'title' => __('Comments', __FILE__), 'summary' => __('Manage comments in your site outside of the page editor.', __FILE__), - 'version' => 11, + 'version' => 12, 'author' => 'Ryan Cramer', 'icon' => 'comments', 'requires' => 'FieldtypeComments', @@ -120,12 +122,20 @@ class ProcessCommentsManager extends Process { Comment::statusSpam => $this->_('Spam'), Comment::statusDelete => $this->_('Delete') ); + $this->labelAll = $this->_('All'); $this->notifyFlagsTranslations = array( 0 => $this->_('No'), - Comment::flagNotifyAll => $this->_('All'), + Comment::flagNotifyAll => $this->labelAll, Comment::flagNotifyReply => $this->_('Replies'), ); - $this->labelAll = $this->_('All'); + if(wireClassExists("CommentStars")) { + $config = $this->config; + $cssFile = $config->urls('FieldtypeComments') . 'comments.css'; + $jsFile = $config->urls('FieldtypeComments') . 'comments.js'; + $config->styles->add($cssFile); + $config->scripts->add($jsFile); + CommentStars::setDefault('star', wireIconMarkup('star')); + } } /** @@ -141,6 +151,7 @@ class ProcessCommentsManager extends Process { // locate all the FieldtypeComments fields $fields = array(); foreach($this->fields as $field) { + /** @var Field $field */ if($field->type instanceof FieldtypeComments) $fields[] = $field; } @@ -179,15 +190,6 @@ class ProcessCommentsManager extends Process { */ public function ___executeList() { - if(wireClassExists("CommentStars")) { - $config = $this->config; - $cssFile = $config->urls('FieldtypeComments') . 'comments.css'; - $jsFile = $config->urls('FieldtypeComments') . 'comments.js'; - $config->styles->add($cssFile); - $config->scripts->add($jsFile); - CommentStars::setDefault('star', wireIconMarkup('star')); - } - $session = $this->wire('session'); /** @var Session $session */ $input = $this->wire('input'); /** @var WireInput $input */ $sanitizer = $this->wire('sanitizer'); /** @var Sanitizer $sanitizer */ @@ -369,7 +371,7 @@ class ProcessCommentsManager extends Process { /** @var InputfieldSubmit $f */ $f = $modules->get('InputfieldButton'); $f->attr('name', 'submit_cancel'); - $f->setSecondary(true); + $f->setSecondary(); $f->val($this->_('Cancel')); $form->add($f); @@ -402,14 +404,364 @@ class ProcessCommentsManager extends Process { return $out; } + /** + * Edit or add comment + * + * @return string + * @throws WireException + * @throws WirePermissionException + * + */ + protected function ___executeEdit() { + + $input = $this->wire()->input; + $user = $this->wire()->user; + $submit = false; + $out = ''; + + if($input->post('submit_save_comment')) { + $submit = true; + $pageId = (int) $input->post('page_id'); + $fieldId = (int) $input->post('field_id'); + $parentId = (int) $input->post('parent_id'); + $commentId = (int) $input->post('comment_id'); + } else { + $pageId = (int) $input->get('page_id'); + $fieldId = (int) $input->get('field_id'); + $parentId = (int) $input->get('parent_id'); + $commentId = (int) $input->get('comment_id'); + } + + $page = $this->wire()->pages->get($pageId); + $field = $this->wire()->fields->get($fieldId); /** @var CommentField $field */ + + if(!$page->id) throw new WireException("Cannot find page $pageId"); + if(!$field) throw new WireException("Cannot find field $fieldId"); + if(!$page->hasField($field)) throw new WireException("Page $pageId does not have field $field->name"); + + if($commentId) { + // editing existing comment + $comment = $field->getCommentByID($page, $commentId); + if(!$comment) throw new WireException('Comment not found'); + if($comment->getField()->id != $field->id) throw new WireException('Invalid field'); + if($comment->getPage()->id != $page->id) throw new WireException('Invalid page'); + $this->headline(sprintf($this->_('Edit comment #%d'), $comment->id)); + + } else { + // adding new comment + $comment = new Comment(); + $this->wire($comment); + $comment->setPage($page); + $comment->setField($field); + $comment->cite = $user->get('title|name'); + $comment->email = $user->get('email'); + $comment->created = time(); + if($parentId) { + // new comment that is reply to existing comment + $parentComment = $field->getCommentByID($page, $parentId); + if(!$parentComment) throw new WireException("Cannot find parent comment $parentId"); + $comment->parent_id = $parentId; + $this->headline(sprintf($this->_('Comment #%d by %s'), $parentId, $comment->getFormatted('cite'))); + // show comment being replied to + $out .= '

' . $parentComment->getFormattedCommentText() . '

'; + $out .= "

" . $this->_('Your reply') . "

"; + } + } + + $form = $this->buildEditForm($page, $field, $comment); + + if($submit) { + $this->processEditForm($form, $page, $field, $comment); + } + + return $out . $form->render(); + } + + /** + * Process comment edit form + * + * @param InputfieldForm $form + * @param Page $page + * @param CommentField $field + * @param Comment $comment + * @return bool + * + */ + protected function processEditForm(InputfieldForm $form, Page $page, CommentField $field, Comment $comment) { + + $input = $this->wire()->input; + + $form->processInput($input->post); + if(count($form->getErrors())) return false; + + $values = array(); + $properties = array( + 'cite', + 'email', + 'website', + 'text', + 'created', + 'status' + ); + + if($field->useVotes) { + $properties[] = 'upvotes'; + $properties[] = 'downvotes'; + } + + foreach($properties as $name) { + $f = $form->getChildByName($name); + if(!$f) continue; + $value = $f->val(); + if($value != $comment->get($name)) { + $comment->set($name, $value); + $values[$name] = $value; + } + } + + if($field->useStars) { + $stars = (int) $input->post('stars'); + if($stars != $comment->stars && $stars > 0 && $stars <= 5) { + $comment->stars = $stars; + $values['stars'] = $stars; + } + } + + $f = $field->useNotify ? $form->getChildByName('notify_author') : null; + if($f) { + $notify = (int) $f->val(); + if($this->applyCommentNotifyFlag($comment, $notify)) { + $values['flags'] = $comment->flags; + } + } + + /** @var Inputfield $f */ + $f = $form->getChildByName('page_id'); + $pageId = $f->val(); + if($pageId != $page->id) { + $f->error('Changing page is not currently supported with this form'); + return false; + /* + $newPage = $this->wire()->pages->get($pageId); + if(!$newPage->editable()) { + $f->error($this->_('Selected page is not editable')); + return false; + } + if(!$newPage->hasField($field)) { + $f->error(sprintf($this->_('Selected page does not have field: %s'), $field->name)); + return false; + } + */ + } + + + if($comment->id) { + // existing comment + if($comment->status === Comment::statusDelete) { + $success = $field->deleteComment($page, $comment); + if($success) { + $this->message(sprintf($this->_('Deleted comment #%d'), $comment->id)); + $this->wire()->session->location("../list/$field->name/all/"); + } + } else { + $success = $field->updateComment($page, $comment, $values); + if($success) $this->message(sprintf($this->_('Updated comment #%d'), $comment->id)); + } + } else { + // new comment + /** @var Inputfield $f */ + $f = $form->getChildByName('notify'); + $notify = $f && $f->val(); + $comment->status = Comment::statusApproved; + $success = $field->addComment($page, $comment, $notify); + if($success) $this->message(sprintf($this->_('Added comment #%d'), $comment->id)); + } + + if($success) { + $this->wire()->session->location("../list/$field->name/all/?id=$comment->id"); + } else { + $this->error($this->_('Error saving comment')); + } + + return $success; + } + + /** + * Build comment edit/add form + * + * @param Page $page + * @param CommentField $field + * @param Comment $comment + * @return InputfieldForm + * + */ + protected function buildEditForm(Page $page, CommentField $field, Comment $comment) { + + $modules = $this->wire()->modules; + + /** @var InputfieldForm $form */ + $form = $modules->get('InputfieldForm'); + + /** @var InputfieldText $f */ + $f = $modules->get('InputfieldText'); + $f->attr('name', 'cite'); + $f->label = $this->_('Cite'); + $f->val($comment->cite); + $f->required = true; + $f->columnWidth = 50; + $form->add($f); + + /** @var InputfieldEmail $f */ + $f = $modules->get('InputfieldEmail'); + $f->attr('name', 'email'); + $f->label = $this->_('Email'); + $f->val($comment->email); + $f->columnWidth = 50; + $f->required = true; + $form->add($f); + + /** @var InputfieldSelect $f */ + $f = $modules->get('InputfieldSelect'); + $f->attr('name', 'status'); + $f->label = $this->_('Status'); + $f->required = true; + foreach($this->statusTranslations as $status => $statusText) { + $f->addOption($status, $statusText); + } + $f->val($comment->status); + $f->columnWidth = 50; + $form->add($f); + + /** @var InputfieldDatetime $f */ + $f = $modules->get('InputfieldDatetime'); + $f->attr('name', 'created'); + $f->label = $this->_('Created'); + $f->inputType = 'html'; + $f->htmlType = 'datetime'; + $f->val($comment->created); + $f->required = true; + $f->columnWidth = 50; + $form->add($f); + + if($field->useWebsite) { + /** @var InputfieldText $f */ + $f = $modules->get('InputfieldUrl'); + $f->attr('name', 'website'); + $f->label = $this->_('Website/URL'); + $f->val($comment->website); + $form->add($f); + } + + /** @var InputfieldTextarea $f */ + $f = $modules->get('InputfieldTextarea'); + $f->attr('name', 'text'); + $f->label = $this->_('Text'); + $f->val($comment->text); + $f->attr('rows', 10); + $f->required = true; + $form->add($f); + + if($field->useStars && $comment->id) { + /** @var InputfieldMarkup $f */ + $f = $modules->get('InputfieldMarkup'); + $f->attr('name', 'stars'); + $f->label = $this->_('Stars'); + $f->value = + "" . + $comment->renderStars(array('input' => true)); + $form->add($f); + } + + if($field->useVotes) { + /** @var InputfieldInteger $f */ + $f = $modules->get('InputfieldInteger'); + $f->attr('name', 'upvotes'); + $f->label = $this->_('Upvotes'); + $f->val($comment->upvotes); + $f->columnWidth = 50; + $form->add($f); + + /** @var InputfieldInteger $f */ + $f = $modules->get('InputfieldInteger'); + $f->attr('name', 'downvotes'); + $f->label = $this->_('Downvotes'); + $f->val($comment->upvotes); + $f->columnWidth = 50; + $form->add($f); + } + + /** @var InputfieldSelect $f */ + $f = $modules->get('InputfieldSelect'); + $f->attr('name', 'notify_author'); + $f->label = $this->_('Notify comment author'); + $f->addOption(0, $this->_('Do not send author notifications')); + if($field->depth) $f->addOption(Comment::flagNotifyReply, $this->_('Notify author of replies to this comment')); + $f->addOption(Comment::flagNotifyAll, $this->_('Notify author of all new comments on page')); + $form->add($f); + + /** @var InputfieldToggle $f */ + if(!$comment->id) { + $f = $modules->get('InputfieldToggle'); + $f->attr('name', 'notify'); + $f->label = $this->_('Allow notifications to be sent for this comment?'); + $f->description = $this->_('When “Yes”, emails about this new comment will be sent to users that have opted in to receive notifications.'); + $f->val(true); + $form->add($f); + } + + /** @var InputfieldPageListSelect $f */ + /* + $f = $modules->get('InputfieldPageListSelect'); + $f->attr('name', 'page_id'); + $f->label = $this->_('Page'); + $f->val($page->id); + $form->add($f); + */ + + /** @var InputfieldHidden $f */ + $f = $modules->get('InputfieldHidden'); + $f->attr('name', 'page_id'); + $f->val($page->id); + $form->add($f); + + /** @var InputfieldHidden $f */ + $f = $modules->get('InputfieldHidden'); + $f->attr('name', 'field_id'); + $f->val($field->id); + $form->add($f); + + /** @var InputfieldHidden $f */ + $f = $modules->get('InputfieldHidden'); + $f->attr('name', 'comment_id'); + $f->val($comment->id); + $form->add($f); + + /** @var InputfieldHidden $f */ + $f = $modules->get('InputfieldHidden'); + $f->attr('name', 'parent_id'); + $f->val($comment->parent_id); + $form->add($f); + + /** @var InputfieldSubmit $f */ + $f = $modules->get('InputfieldSubmit'); + $f->attr('name', 'submit_save_comment'); + $f->showInHeader(); + $form->add($f); + + return $form; + } + + /** * Process changes to posted comments * * @param CommentArray $comments - * @param Field $field + * @param CommentField $field * */ protected function processComments(CommentArray $comments, Field $field) { + + $input = $this->wire()->input; $numDeleted = 0; $numChanged = 0; @@ -420,16 +772,13 @@ class ProcessCommentsManager extends Process { /** @var FieldtypeComments $fieldtype */ $fieldtype = $field->type; - - /** @var WireInput $input */ - $input = $this->wire('input'); foreach($comments as $comment) { /** @var Comment $comment */ $properties = array(); - $text = $input->post("CommentText{$comment->id}"); + $text = $input->post("CommentText$comment->id"); if(!is_null($text) && $text != $comment->text) { $comment->text = $text; // cleans it $properties['text'] = $comment->text; @@ -456,7 +805,7 @@ class ProcessCommentsManager extends Process { } } - $_status = $input->post("CommentStatus{$comment->id}"); + $_status = $input->post("CommentStatus$comment->id"); $status = (int) $_status; if($status === Comment::statusDelete && (!$commentField || $commentField->allowDeleteComment($comment))) { if($fieldtype->deleteComment($comment->getPage(), $field, $comment)) { @@ -472,29 +821,20 @@ class ProcessCommentsManager extends Process { $properties['status'] = $comment->status; } - $notify = $input->post("CommentNotify{$comment->id}"); + $notify = $input->post("CommentNotify$comment->id"); if($field->useNotify && ctype_digit($notify)) { $notify = (int) $notify; - if($notify === 0 && $comment->flags) { - if($comment->flags & Comment::flagNotifyAll) $comment->flags = $comment->flags & ~Comment::flagNotifyAll; - if($comment->flags & Comment::flagNotifyReply) $comment->flags = $comment->flags & ~Comment::flagNotifyReply; - if($comment->flags & Comment::flagNotifyConfirmed) $comment->flags = $comment->flags & ~Comment::flagNotifyConfirmed; + if($this->applyCommentNotifyFlag($comment, $notify)) { $properties['flags'] = $comment->flags; - } else if($notify === Comment::flagNotifyAll && !($comment->flags & Comment::flagNotifyAll)) { - $comment->flags = $comment->flags | Comment::flagNotifyAll; - $properties['flags'] = $comment['flags']; - } else if($notify === Comment::flagNotifyReply) { - $comment->flags = $comment->flags | Comment::flagNotifyReply; - $properties['flags'] = $comment['flags']; } } $changePage = null; if($allowChangePage) { // check for change of Page ID - $pageID = (int) $input->post("CommentPage{$comment->id}"); + $pageID = (int) $input->post("CommentPage$comment->id"); if($pageID > 0 && "$pageID" !== "$comment->page") { - $page = $this->wire('pages')->get($pageID); + $page = $this->wire()->pages->get($pageID); $parentID = $comment->parent_id; if($parentID) $comment->parent_id = 0; // temporarily set to 0 for page change if(!$page->id) { @@ -576,12 +916,23 @@ class ProcessCommentsManager extends Process { /** * Render the markup for a single comment * + * Hookable since 3.0.204 + * * @param Comment $comment + * @param array $options Options (since 3.0.204) * @return string * */ - protected function renderComment(Comment $comment) { - + protected function ___renderComment(Comment $comment, array $options = array()) { + + $defaults = array( + 'prependMarkup' => '', + 'appendMarkup' => '', + 'prependContentMarkup' => '', + 'appendContentMarkup' => '', + ); + + $options = array_merge($defaults, $options); $sanitizer = $this->sanitizer; $page = $comment->getPage(); $pageTitle = $sanitizer->entities1($page->get('title|name')); @@ -607,6 +958,11 @@ class ProcessCommentsManager extends Process { 'changed' => 'dot-circle-o', 'reply' => 'angle-double-down', 'replies' => 'angle-double-right', + 'pageEdit' => 'pencil', + 'pageView' => 'external-link-square', + 'commentEdit' => 'pencil', + 'commentReply' => 'reply', + 'meta' => 'sliders', ); $outs = array( @@ -637,17 +993,20 @@ class ProcessCommentsManager extends Process { 'page' => $this->_('Page'), 'date' => $this->_('When'), 'status' => $this->_('Status'), + 'action' => $this->_('Action'), 'cite' => $this->_('Cite'), 'website' => $this->_('Web'), 'email' => $this->_('Mail'), 'none' => $this->_('None'), 'parent' => $this->_('Parent'), 'where' => $this->_('Where'), + 'reply' => $this->_('reply'), 'replyTo' => $this->_('Reply to %s'), 'stars' => $this->_('Stars'), 'votes' => $this->_('Votes'), 'notify' => $this->_('Notify'), 'commentId' => $this->_('Comment ID'), + 'commentEdit' => $this->_('editor'), ); $values = array( @@ -673,6 +1032,8 @@ class ProcessCommentsManager extends Process { 'pageView' => "$page->url#Comment$id", 'pageEdit' => $page->editUrl(), 'metaEdit' => "../../../meta/?comment_id=$comment->id&page_id=$page->id&field_id=$field->id&modal=1", + 'commentReply' => "../../../edit/?parent_id=$comment->id&page_id=$page->id&field_id=$field->id", + 'commentEdit' => "../../../edit/?comment_id=$comment->id&page_id=$page->id&field_id=$field->id", 'email' => "./?email=" . urlencode($values['email']), 'cite' => "../all/?cite=" . urlencode($values['cite']), 'ip' => "../all/?ip=" . urlencode($values['ip']), @@ -682,8 +1043,15 @@ class ProcessCommentsManager extends Process { 'parent' => $this->_('ID of the Comment that this one is replying to.'), 'page' => $this->_('ID of the Page that this comment lives on.'), 'viewAll' => $this->_('View all having value'), + 'viewPage' => $this->_('View page'), 'edit' => $this->_('Edit value'), + 'editPage' => $this->_('Edit page'), 'pageFilter' => $this->_('Show only comments from page'), + 'pageEdit' => $this->_('Edit page'), + 'pageView' => $this->_('View page'), + 'commentEdit' => $this->_('Comment editor'), + 'commentReply' => $this->_('Reply to this comment'), + 'meta' => $this->_('View/edit metadata'), ); foreach($values as $key => $value) { @@ -691,7 +1059,7 @@ class ProcessCommentsManager extends Process { } foreach($icons as $key => $value) { - $icons[$key] = wireIconMarkup($value); + $icons[$key] = wireIconMarkup($value, 'fw'); } if($allowDepth) { @@ -699,24 +1067,31 @@ class ProcessCommentsManager extends Process { $numChildren = count($children); } - if($adminTheme && $adminTheme instanceof AdminThemeFramework) { + if($adminTheme instanceof AdminThemeFramework) { $classes['input'] = trim("$classes[input] " . $adminTheme->getClass('input-small')); $classes['textarea'] = $adminTheme->getClass('textarea'); $classes['radio'] = $adminTheme->getClass('input-radio'); $classes['checkbox'] = $adminTheme->getClass('input-checkbox'); $classes['table'] = $adminTheme->getClass('table'); + $classes['select'] = $adminTheme->getClass('select-small'); // if(strpos($classes['input'], 'uk-input') !== false) $classes['input'] .= " uk-form-blank"; } - + + $outs['status'] = " " . "$label" . "  "; + */ } + $outs['status'] .= ""; if($page->editable()) { $text = @@ -817,10 +1192,19 @@ class ProcessCommentsManager extends Process { $meta = $comment->getMeta(); $metaCnt = count($meta); - $metaTip = sprintf($this->_n('%d value', '%d values', $metaCnt), $metaCnt); + $metaTip = $tooltips['meta'] . ' (' . sprintf($this->_n('%d value', '%d values', $metaCnt), $metaCnt) . ')'; + + $statusLinks = array( + "$icons[commentEdit] $labels[commentEdit]", + "$icons[meta] $labels[meta]", + ); + if($comment->allowChildren()) { + $statusLinks[] = "$icons[commentReply] $labels[reply]"; + } $out = "
" . + $options['prependMarkup'] . "" . "" . "" . "" . "" . - "" . - "" . + "" . + "" . "" . $outs['notify'] . "" . @@ -872,10 +1257,13 @@ class ProcessCommentsManager extends Process { $outs['where'] . "
" . @@ -832,17 +1216,18 @@ class ProcessCommentsManager extends Process { "" . "$pageTitle " . " " . - "$labels[view] / " . - "$labels[edit] / " . - "$labels[meta]" . + "$labels[view] / " . + "$labels[edit]" . "" . "$icons[changed]" . "
$labels[status]$outs[status]$labels[action]" . + $outs['status'] . "   " . + implode('  ', $statusLinks) . + "
" . "
" . + $options['prependContentMarkup'] . "$outs[reply]" . "
$text
" . "$outs[children]" . + $options['appendContentMarkup'] . "
" . + $options['appendMarkup'] . "
"; /* @@ -925,8 +1313,8 @@ class ProcessCommentsManager extends Process { $setStatusLabel = $this->_('Set status:'); $perPageLabel = $this->_('per page'); $adminTheme = $this->wire('adminTheme'); - $selectClass = $adminTheme && $adminTheme instanceof AdminThemeFramework ? $adminTheme->getClass('select') : ''; - $checkboxClass = $adminTheme && $adminTheme instanceof AdminThemeFramework ? $adminTheme->getClass('input-checkbox') : ''; + $selectClass = $adminTheme instanceof AdminThemeFramework ? $adminTheme->getClass('select') : ''; + $checkboxClass = $adminTheme instanceof AdminThemeFramework ? $adminTheme->getClass('input-checkbox') : ''; $pagerLimitOut = "