/**
     * Alternate version of Index that uses the embed master view.
     *
     * @param int $DiscussionID Unique identifier, if discussion has been created.
     * @param string $DiscussionStub Deprecated.
     * @param int $Offset
     * @param int $Limit
     */
    public function embed($DiscussionID = '', $DiscussionStub = '', $Offset = '', $Limit = '')
    {
        $this->title(t('Comments'));
        // Add theme data
        $this->Theme = c('Garden.CommentsTheme', $this->Theme);
        Gdn_Theme::section('Comments');
        // Force view options
        $this->MasterView = 'empty';
        $this->CanEditComments = false;
        // Don't show the comment checkboxes on the embed comments page
        // Add some css to help with the transparent bg on embedded comments
        if ($this->Head) {
            $this->Head->addString('<style type="text/css">
body { background: transparent !important; }
</style>');
        }
        // Javascript files & options
        $this->addJsFile('jquery.gardenmorepager.js');
        $this->addJsFile('jquery.autosize.min.js');
        $this->addJsFile('discussion.js');
        $this->removeJsFile('autosave.js');
        $this->addDefinition('DoInform', '0');
        // Suppress inform messages on embedded page.
        $this->addDefinition('SelfUrl', Gdn::request()->PathAndQuery());
        $this->addDefinition('Embedded', true);
        // Define incoming variables (prefer querystring parameters over method parameters)
        $DiscussionID = is_numeric($DiscussionID) && $DiscussionID > 0 ? $DiscussionID : 0;
        $DiscussionID = getIncomingValue('vanilla_discussion_id', $DiscussionID);
        $Offset = getIncomingValue('Offset', $Offset);
        $Limit = getIncomingValue('Limit', $Limit);
        $vanilla_identifier = getIncomingValue('vanilla_identifier', '');
        // Only allow vanilla identifiers of 32 chars or less - md5 if larger
        if (strlen($vanilla_identifier) > 32) {
            $vanilla_identifier = md5($vanilla_identifier);
        }
        $vanilla_type = getIncomingValue('vanilla_type', 'page');
        $vanilla_url = getIncomingValue('vanilla_url', '');
        $vanilla_category_id = getIncomingValue('vanilla_category_id', '');
        $ForeignSource = array('vanilla_identifier' => $vanilla_identifier, 'vanilla_type' => $vanilla_type, 'vanilla_url' => $vanilla_url, 'vanilla_category_id' => $vanilla_category_id);
        $this->setData('ForeignSource', $ForeignSource);
        // Set comment sorting
        $SortComments = c('Garden.Embed.SortComments') == 'desc' ? 'desc' : 'asc';
        $this->setData('SortComments', $SortComments);
        // Retrieve the discussion record
        $Discussion = false;
        if ($DiscussionID > 0) {
            $Discussion = $this->DiscussionModel->getID($DiscussionID);
        } elseif ($vanilla_identifier != '' && $vanilla_type != '') {
            $Discussion = $this->DiscussionModel->GetForeignID($vanilla_identifier, $vanilla_type);
        }
        // Set discussion data if we have one for this page
        if ($Discussion) {
            // Allow Vanilla.Comments.View to be defined to limit access to embedded comments only.
            // Otherwise, go with normal discussion view permissions. Either will do.
            $this->permission(array('Vanilla.Discussions.View', 'Vanilla.Comments.View'), false, 'Category', $Discussion->PermissionCategoryID);
            $this->setData('Discussion', $Discussion, true);
            $this->setData('DiscussionID', $Discussion->DiscussionID, true);
            $this->title($Discussion->Name);
            // Actual number of comments, excluding the discussion itself
            $ActualResponses = $Discussion->CountComments;
            // Define the query offset & limit
            if (!is_numeric($Limit) || $Limit < 0) {
                $Limit = c('Garden.Embed.CommentsPerPage', 30);
            }
            $OffsetProvided = $Offset != '';
            list($Offset, $Limit) = offsetLimit($Offset, $Limit);
            $this->Offset = $Offset;
            if (c('Vanilla.Comments.AutoOffset')) {
                if ($ActualResponses <= $Limit) {
                    $this->Offset = 0;
                }
                if ($this->Offset == $ActualResponses) {
                    $this->Offset -= $Limit;
                }
            } elseif ($this->Offset == '') {
                $this->Offset = 0;
            }
            if ($this->Offset < 0) {
                $this->Offset = 0;
            }
            // Set the canonical url to have the proper page title.
            $this->canonicalUrl(discussionUrl($Discussion, pageNumber($this->Offset, $Limit)));
            // Load the comments.
            $CurrentOrderBy = $this->CommentModel->orderBy();
            if (stringBeginsWith(GetValueR('0.0', $CurrentOrderBy), 'c.DateInserted')) {
                $this->CommentModel->orderBy('c.DateInserted ' . $SortComments);
                // allow custom sort
            }
            $this->setData('Comments', $this->CommentModel->get($Discussion->DiscussionID, $Limit, $this->Offset), true);
            if (count($this->CommentModel->where()) > 0) {
                $ActualResponses = false;
            }
            $this->setData('_Count', $ActualResponses);
            // Build a pager
            $PagerFactory = new Gdn_PagerFactory();
            $this->EventArguments['PagerType'] = 'MorePager';
            $this->fireEvent('BeforeBuildPager');
            $this->Pager = $PagerFactory->getPager($this->EventArguments['PagerType'], $this);
            $this->Pager->ClientID = 'Pager';
            $this->Pager->MoreCode = 'More Comments';
            $this->Pager->configure($this->Offset, $Limit, $ActualResponses, 'discussion/embed/' . $Discussion->DiscussionID . '/' . Gdn_Format::url($Discussion->Name) . '/%1$s');
            $this->Pager->CurrentRecords = $this->Comments->numRows();
            $this->fireEvent('AfterBuildPager');
        }
        // Define the form for the comment input
        $this->Form = Gdn::Factory('Form', 'Comment');
        $this->Form->Action = url('/post/comment/');
        $this->Form->addHidden('CommentID', '');
        $this->Form->addHidden('Embedded', 'true');
        // Tell the post controller that this is an embedded page (in case there are custom views it needs to pick up from a theme).
        $this->Form->addHidden('DisplayNewCommentOnly', 'true');
        // Only load/display the new comment after posting (don't load all new comments since the page last loaded).
        // Grab the page title
        if ($this->Request->get('title')) {
            $this->Form->setValue('Name', $this->Request->get('title'));
        }
        // Set existing DiscussionID for comment form
        if ($Discussion) {
            $this->Form->addHidden('DiscussionID', $Discussion->DiscussionID);
        }
        foreach ($ForeignSource as $Key => $Val) {
            // Drop the foreign source information into the form so it can be used if creating a discussion
            $this->Form->addHidden($Key, $Val);
            // Also drop it into the definitions so it can be picked up for stashing comments
            $this->addDefinition($Key, $Val);
        }
        // Retrieve & apply the draft if there is one:
        $Draft = false;
        if (Gdn::session()->UserID && $Discussion) {
            $DraftModel = new DraftModel();
            $Draft = $DraftModel->get(Gdn::session()->UserID, 0, 1, $Discussion->DiscussionID)->firstRow();
            $this->Form->addHidden('DraftID', $Draft ? $Draft->DraftID : '');
        }
        if ($Draft) {
            $this->Form->setFormValue('Body', $Draft->Body);
        } else {
            // Look in the session stash for a comment
            $StashComment = Gdn::session()->getPublicStash('CommentForForeignID_' . $ForeignSource['vanilla_identifier']);
            if ($StashComment) {
                $this->Form->setValue('Body', $StashComment);
                $this->Form->setFormValue('Body', $StashComment);
            }
        }
        // Deliver JSON data if necessary
        if ($this->_DeliveryType != DELIVERY_TYPE_ALL) {
            if ($this->Discussion) {
                $this->setJson('LessRow', $this->Pager->toString('less'));
                $this->setJson('MoreRow', $this->Pager->toString('more'));
            }
            $this->View = 'comments';
        }
        // Ordering note for JS
        if ($SortComments == 'desc') {
            $this->addDefinition('PrependNewComments', '1');
        }
        // Report the discussion id so js can use it.
        if ($Discussion) {
            $this->addDefinition('DiscussionID', $Discussion->DiscussionID);
        }
        $this->fireEvent('BeforeDiscussionRender');
        $this->render();
    }
 /**
  * Show all discussions in a particular category.
  *
  * @since 2.0.0
  * @access public
  *
  * @param string $CategoryIdentifier Unique category slug or ID.
  * @param int $Offset Number of discussions to skip.
  */
 public function index($CategoryIdentifier = '', $Page = '0')
 {
     // Figure out which category layout to choose (Defined on "Homepage" settings page).
     $Layout = c('Vanilla.Categories.Layout');
     if ($CategoryIdentifier == '') {
         switch ($Layout) {
             case 'mixed':
                 $this->View = 'discussions';
                 $this->discussions();
                 break;
             case 'table':
                 $this->table();
                 break;
             default:
                 $this->View = 'all';
                 $this->all('', CategoryModel::getRootDisplayAs());
                 break;
         }
         return;
     } else {
         $Category = CategoryModel::categories($CategoryIdentifier);
         if (empty($Category)) {
             throw notFoundException();
         }
         $Category = (object) $Category;
         Gdn_Theme::section($Category->CssClass);
         // Load the breadcrumbs.
         $this->setData('Breadcrumbs', CategoryModel::getAncestors(val('CategoryID', $Category)));
         $this->setData('Category', $Category, true);
         $this->title(htmlspecialchars(val('Name', $Category, '')));
         $this->description(val('Description', $Category), true);
         switch ($Category->DisplayAs) {
             case 'Flat':
             case 'Heading':
             case 'Categories':
                 $stopHeadings = val('Depth', $Category) > CategoryModel::instance()->getNavDepth();
                 CategoryModel::instance()->setStopHeadingsCalculation($stopHeadings);
                 if ($this->SyndicationMethod != SYNDICATION_NONE) {
                     // RSS can't show a category list so just tell it to expand all categories.
                     saveToConfig('Vanilla.ExpandCategories', true, false);
                 } else {
                     // This category is an overview style category and displays as a category list.
                     switch ($Layout) {
                         case 'mixed':
                             $this->View = 'discussions';
                             $this->discussions($CategoryIdentifier);
                             break;
                         case 'table':
                             $this->table($CategoryIdentifier, $Category->DisplayAs);
                             break;
                         default:
                             $this->View = 'all';
                             $this->All($CategoryIdentifier, $Category->DisplayAs);
                             break;
                     }
                     return;
                 }
                 break;
         }
         Gdn_Theme::section('DiscussionList');
         // Figure out which discussions layout to choose (Defined on "Homepage" settings page).
         $Layout = c('Vanilla.Discussions.Layout');
         switch ($Layout) {
             case 'table':
                 if ($this->SyndicationMethod == SYNDICATION_NONE) {
                     $this->View = 'table';
                 }
                 break;
             default:
                 // $this->View = 'index';
                 break;
         }
         $this->setData('CategoryTree', $this->getCategoryTree($CategoryIdentifier, val('DisplayAs', $Category)));
         // Add a backwards-compatibility shim for the old categories.
         $this->categoriesCompatibilityCallback = function () use($CategoryIdentifier) {
             $categories = CategoryModel::getSubtree($CategoryIdentifier, false);
             return $categories;
         };
         // Setup head
         $this->Menu->highlightRoute('/discussions');
         if ($this->Head) {
             $this->addJsFile('discussions.js');
             $this->Head->addRss(categoryUrl($Category) . '/feed.rss', $this->Head->title());
         }
         // Set CategoryID
         $CategoryID = val('CategoryID', $Category);
         $this->setData('CategoryID', $CategoryID, true);
         // Add modules
         $this->addModule('NewDiscussionModule');
         $this->addModule('DiscussionFilterModule');
         $this->addModule('CategoriesModule');
         $this->addModule('BookmarkedModule');
         // Get a DiscussionModel
         $DiscussionModel = new DiscussionModel();
         $DiscussionModel->setSort(Gdn::request()->get());
         $DiscussionModel->setFilters(Gdn::request()->get());
         $this->setData('Sort', $DiscussionModel->getSort());
         $this->setData('Filters', $DiscussionModel->getFilters());
         $CategoryIDs = array($CategoryID);
         if (c('Vanilla.ExpandCategories')) {
             $CategoryIDs = array_merge($CategoryIDs, array_column($this->data('Categories'), 'CategoryID'));
         }
         $Wheres = array('d.CategoryID' => $CategoryIDs);
         $this->setData('_ShowCategoryLink', count($CategoryIDs) > 1);
         // Check permission
         $this->permission('Vanilla.Discussions.View', true, 'Category', val('PermissionCategoryID', $Category));
         // Set discussion meta data.
         $this->EventArguments['PerPage'] = c('Vanilla.Discussions.PerPage', 30);
         $this->fireEvent('BeforeGetDiscussions');
         list($Offset, $Limit) = offsetLimit($Page, $this->EventArguments['PerPage']);
         if (!is_numeric($Offset) || $Offset < 0) {
             $Offset = 0;
         }
         $Page = PageNumber($Offset, $Limit);
         // Allow page manipulation
         $this->EventArguments['Page'] =& $Page;
         $this->EventArguments['Offset'] =& $Offset;
         $this->EventArguments['Limit'] =& $Limit;
         $this->fireEvent('AfterPageCalculation');
         // We want to limit the number of pages on large databases because requesting a super-high page can kill the db.
         $MaxPages = c('Vanilla.Categories.MaxPages');
         if ($MaxPages && $Page > $MaxPages) {
             throw notFoundException();
         }
         $CountDiscussions = $DiscussionModel->getCount($Wheres);
         if ($MaxPages && $MaxPages * $Limit < $CountDiscussions) {
             $CountDiscussions = $MaxPages * $Limit;
         }
         $this->setData('CountDiscussions', $CountDiscussions);
         $this->setData('_Limit', $Limit);
         // We don't wan't child categories in announcements.
         $Wheres['d.CategoryID'] = $CategoryID;
         $AnnounceData = $DiscussionModel->getAnnouncements($Wheres, $Offset, $Limit);
         $this->AnnounceData = $this->setData('Announcements', $AnnounceData);
         $Wheres['d.CategoryID'] = $CategoryIDs;
         // RSS should include announcements.
         if ($this->SyndicationMethod !== SYNDICATION_NONE) {
             $Wheres['Announce'] = 'all';
         }
         $this->DiscussionData = $this->setData('Discussions', $DiscussionModel->getWhereRecent($Wheres, $Limit, $Offset));
         // Build a pager
         $PagerFactory = new Gdn_PagerFactory();
         $url = CategoryUrl($CategoryIdentifier);
         $this->EventArguments['PagerType'] = 'Pager';
         $this->fireEvent('BeforeBuildPager');
         if (!$this->data('_PagerUrl')) {
             $this->setData('_PagerUrl', $url . '/{Page}');
         }
         $queryString = DiscussionModel::getSortFilterQueryString($DiscussionModel->getSort(), $DiscussionModel->getFilters());
         $this->setData('_PagerUrl', $this->data('_PagerUrl') . $queryString);
         $this->Pager = $PagerFactory->GetPager($this->EventArguments['PagerType'], $this);
         $this->Pager->ClientID = 'Pager';
         $this->Pager->configure($Offset, $Limit, $CountDiscussions, $this->data('_PagerUrl'));
         $this->Pager->Record = $Category;
         PagerModule::current($this->Pager);
         $this->setData('_Page', $Page);
         $this->setData('_Limit', $Limit);
         $this->fireEvent('AfterBuildPager');
         // Set the canonical Url.
         $this->canonicalUrl(categoryUrl($Category, pageNumber($Offset, $Limit)));
         // Change the controller name so that it knows to grab the discussion views
         $this->ControllerName = 'DiscussionsController';
         // Pick up the discussions class
         $this->CssClass = 'Discussions Category-' . val('UrlCode', $Category);
         // Deliver JSON data if necessary
         if ($this->_DeliveryType != DELIVERY_TYPE_ALL) {
             $this->setJson('LessRow', $this->Pager->toString('less'));
             $this->setJson('MoreRow', $this->Pager->toString('more'));
             $this->View = 'discussions';
         }
         // Render default view.
         $this->fireEvent('BeforeCategoriesRender');
         $this->render();
     }
 }
 /**
  * Return the page number from the given variables that may have an offset or a page.
  *
  * @param array $Vars The variables that should contain an Offset or Page key.
  * @param int|string $PageSize The pagesize or the config key of the pagesize.
  * @return int
  */
 public static function pageNumber($Vars, $PageSize)
 {
     if (isset($Vars['Page'])) {
         return $Vars['Page'];
     }
     if (isset($Vars['Offset'])) {
         if (is_numeric($PageSize)) {
             return pageNumber($Vars['Offset'], $PageSize, false, Gdn::Session()->IsValid());
         } else {
             return pageNumber($Vars['Offset'], C($PageSize, 30), false, Gdn::Session()->IsValid());
         }
     }
     return 1;
 }
Example #4
0
<?php

$pager = Gdn::controller()->data('Pager');
$pagerType = !$pager->TotalRecords ? 'more' : 'numbered';
$hasNext = true;
// Get total page count, allowing override
$pageCount = ceil($pager->TotalRecords / $pager->Limit);
$currentPage = pageNumber($pager->Offset, $pager->Limit);
if ($pagerType === 'numbered' && $currentPage >= $pageCount) {
    $hasNext = false;
}
if ($pagerType === 'more' && ($pager->CurrentRecords === false || $pager->CurrentRecords < $pager->Limit)) {
    $hasNext = false;
}
$pagerString = '<div class="pager">';
$pagerCount = '<div class="pager-count">';
$pagerCount .= sprintf(t('Page %s of %s'), $currentPage, $pageCount ? $pageCount : 1);
$pagerCount .= '</div>';
if ($pagerType === 'more') {
    $pagerCount = '<div class="pager-count">';
    $pagerCount .= sprintf(t('Page %s'), $currentPage);
    $pagerCount .= '</div>';
}
$pagerString .= $pagerCount;
$pagerString .= '<nav class="btn-group">';
// Previous
if ($currentPage == 1) {
    $disabled = 'disabled';
} else {
    $disabled = '';
}