diff --git a/ReplyTo/class.replyto.plugin.php b/ReplyTo/class.replyto.plugin.php index d4d605d..9ac3064 100644 --- a/ReplyTo/class.replyto.plugin.php +++ b/ReplyTo/class.replyto.plugin.php @@ -10,6 +10,7 @@ class ReplyToPlugin extends Gdn_Plugin { const QUERY_PARAMETER_VIEW='view'; const VIEW_FLAT = 'flat'; const VIEW_THREADED = 'threaded'; + const VIEW_MODE = 'ReplyTo.ViewMode'; private $replyToModel; /** @@ -56,24 +57,102 @@ public function assetModel_styleCss_handler($sender) { // Set JS for this plugin. protected function prepareController(&$sender) { $sender->addJsFile('replyto.js', 'plugins/ReplyTo'); + } + + /** + * Set a view mode for Discussion Controller + * View Mode is calculated from request url. + * Flat mode is used - '/discussion/{DiscussionID}/p{Page} + * Threaded mode is used by default + * + * @param $sender + * @param $args + */ + public function discussionController_initialize_handler($sender, $args) { + $viewMode = self::getViewMode(); + $sender->setData(self::VIEW_MODE, $viewMode); + + } + + /** + * Set a view mode for Post Controller + * Replying to a comment and leaving a comment are processed by Post Controller. + * (the url 'post/comment/, 'post' method). + * Use HTTP_REFERER to get the current view mode + * @param $sender + * @param $args + */ + public function postController_initialize_handler($sender, $args) { + if(isset($_SERVER['HTTP_REFERER'])) { + $url = $_SERVER['HTTP_REFERER']; + } + parse_str( parse_url( $url, PHP_URL_QUERY), $array ); + $viewMode = $array[self::QUERY_PARAMETER_VIEW]; + if(!$viewMode) { + $viewMode = self::isPagingUrl($url)? self::VIEW_FLAT: self::VIEW_THREADED; + } + $sender->setData(self::VIEW_MODE, $viewMode); } public function discussionController_render_before(&$sender) { $this->prepareController($sender); } + /** + * After deleting a comment in a threaded view, the comment tree should be re-rendered + * because tree left/right might be changed if a parent comment has been deleted. + * deliveryType is VIEW in a threaded view + * deliveryType is BOOL in a flat view. Don't re-render a view. Deleted comment + * is hidden on the client. + * + * @param $sender + * @param $args + */ + public function discussionController_AfterCommentDeleted_handler($sender, $args) { + $viewMode = $sender->data('ReplyTo.ViewMode'); + if($sender->deliveryMethod() == DELIVERY_METHOD_JSON) { + $discussionID = $args['DiscussionID']; + $sender->json(self::VIEW_MODE, $viewMode); + if ($viewMode == self::VIEW_THREADED) { + // Show all comments + $commentModel = new CommentModel(); + $CountComments = $commentModel->getCountByDiscussion($discussionID); + $sender->setData('Comments', $commentModel->getByDiscussion($discussionID, $CountComments, 0)); + $sender->ClassName = 'DiscussionController'; + $sender->ControllerName = 'discussion'; + $sender->View = 'comments'; + } + } + } + public function postController_render_before($sender) { $this->prepareController($sender); } /** - * Add View Mode before rendering comments + * The 'beforeCommentRender' are fired by DiscussionController and PostController. + * Re-render a comment tree if new comment is added in threaded view. + * * @param $sender * @param $args */ - public function base_beforeCommentsRender_handler($sender, $args) { - $viewMode = self::getViewMode(); - $sender->setData('ViewMode', $viewMode); + public function base_beforeCommentRender_handler($sender, $args) { + // Editing existing comment or new comment added + if ($sender->deliveryType() != DELIVERY_TYPE_DATA) { + $sender->json('ReplyTo.ViewMode', $sender->data(self::VIEW_MODE)); + $isNewComment = $sender->data('NewComments'); + if($isNewComment) { + $discussionID = val('DiscussionID', $args['Discussion']); + $commentModel = new CommentModel(); + $countComments = $commentModel->getCountByDiscussion($discussionID); + // FIX: https://github.com/topcoder-platform/forums/issues/511 + // Render a full comment tree in threaded mode + if($sender->data(self::VIEW_MODE) == self::VIEW_THREADED) { + // Show all comments + $sender->setData('Comments', $commentModel->getByDiscussion($discussionID, $countComments, 0)); + } + } + } } /** @@ -81,7 +160,7 @@ public function base_beforeCommentsRender_handler($sender, $args) { * @param $sender * @param $args */ - public function base_InlineDiscussionOptionsLeft_handler($sender, $args){ + public function discussionController_InlineDiscussionOptionsLeft_handler($sender, $args){ $discussion = $sender->data('Discussion'); if (!$discussion) { return; @@ -92,7 +171,7 @@ public function base_InlineDiscussionOptionsLeft_handler($sender, $args){ } $discussionUrl = discussionUrl($discussion, '', '/'); - $viewMode = self::getViewMode(); + $viewMode = $sender->data(self::VIEW_MODE); echo ''; echo 'View: '; @@ -143,8 +222,16 @@ public function commentModel_deleteComment_handler(&$Sender) { $this->replyToModel->onDeleteComment($Comment); } + /** + * Set offset and limit depends on view mode. + * In the threaded mode, all comments are displayed. + * In the flat mode, comments are displayed with pagination. + * The hook is used when rendering a discussion page with comments + * @param $sender + * @param $args + */ public function discussionController_BeforeCalculatingOffsetLimit_handler($sender, $args) { - $viewMode = self::getViewMode(); + $viewMode = $sender->data(self::VIEW_MODE); // $offsetProvided = $args['OffsetProvided']; $discussion = $args['Discussion']; $offset = & $args['Offset']; @@ -179,7 +266,7 @@ public function discussionController_beforeDiscussionRender_handler($sender, $ar return; } - $viewMode = self::getViewMode(); + $viewMode = $sender->data(self::VIEW_MODE); if($viewMode == self::VIEW_FLAT) { return; } @@ -222,19 +309,16 @@ public function base_commentOptions_handler($sender, $args) { 'Class' => 'ReplyComment' ]; - $viewMode = self::getViewMode(); + $viewMode = $sender->data(self::VIEW_MODE); + $deliveryType = $viewMode == self::VIEW_THREADED? DELIVERY_TYPE_VIEW : DELIVERY_TYPE_BOOL; foreach ($options as $key => $value) { - $currentUrl = $options[$key]['Url']; - if (strpos($currentUrl, '?') !== false ) { - if (strpos($currentUrl, 'Target') !== false) { - $options[$key]['Url'] = $currentUrl.urlencode('?view='.$viewMode); - } else { - $options[$key]['Url'] = $currentUrl. '&view=' . $viewMode; - } - } else { - $options[$key]['Url'] = $currentUrl.'?view='.$viewMode; + $options[$key]['Url'] = strpos($options[$key]['Url'], '?') !== false ? $options[$key]['Url']: $options[$key]['Url'].'?'; + $options[$key]['Url'] .= '&view=' . $viewMode; + if($key == 'DeleteComment') { + $options[$key]['Url'] .='&deliveryType='.$deliveryType; } } + } /** @@ -276,7 +360,7 @@ public function base_inlineDiscussionOptions_handler($sender, $args) { * @param $args */ public function base_beforeCommentDisplay_handler($sender, $args) { - if($sender->deliveryType() != DELIVERY_TYPE_ALL) { + if($sender->deliveryType() != DELIVERY_TYPE_ALL) { // Editing a comment is processed by PostController // Ajax request to post new comments or update comments if(isset($_SERVER['HTTP_REFERER'])) { $previous = $_SERVER['HTTP_REFERER']; @@ -286,13 +370,13 @@ public function base_beforeCommentDisplay_handler($sender, $args) { if(!$viewMode) { $viewMode = self::isPagingUrl($previous) ? self::VIEW_FLAT : self::VIEW_THREADED; } - $sender->setData('ViewMode', $viewMode); + $sender->setData(self::VIEW_MODE, $viewMode); if($viewMode == self::VIEW_THREADED) { $this->buildCommentReplyToCssClasses($sender); } } } else { - $viewMode = self::getViewMode(); + $viewMode = $sender->data(self::VIEW_MODE); if($viewMode == self::VIEW_THREADED) { $this->buildCommentReplyToCssClasses($sender); } diff --git a/ReplyTo/js/replyto.js b/ReplyTo/js/replyto.js index 5ed35b1..01d6e8f 100644 --- a/ReplyTo/js/replyto.js +++ b/ReplyTo/js/replyto.js @@ -4,12 +4,6 @@ jQuery(document).ready(function($) { return (href.split(name + '=')[1] || '').split('&')[0]; } - //If view is not flat, reload a page to rebuild a tree - function reloadPage() { - var currentView = param(window.location.href, 'view'); - return currentView == 'threaded'; - } - $(document).on('click','a.ReplyComment', function(ev) { var btn = this; var parent = $(btn).parents('.MainContent'); @@ -61,25 +55,6 @@ jQuery(document).ready(function($) { return false; }); - - // Comment was added. - $(document).on('CommentAdded',function(ev) { - if (reloadPage() === true) { - window.location.reload(); - return false; - } - return false; - }); - - // Comment was deleted. - $(document).on('CommentDeleted',function(ev) { - if (reloadPage() === true) { - window.location.reload(); - return false; - } - return false; - }); - $(document).on('click','a.CancelReplyComment', function(ev) { clearReplyCommentForm(this); return false;