/** * Get a site tree HTML listing which displays the nodes under the given criteria. * * @param $className The class of the root object * @param $rootID The ID of the root object. If this is null then a complete tree will be * shown * @param $childrenMethod The method to call to get the children of the tree. For example, * Children, AllChildrenIncludingDeleted, or AllHistoricalChildren * @return String Nested unordered list with links to each page */ function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $numChildrenMethod = null, $filterFunction = null, $minNodeCount = 30) { // Filter criteria $params = $this->request->getVar('q'); if (isset($params['FilterClass']) && ($filterClass = $params['FilterClass'])) { if (!is_subclass_of($filterClass, 'CMSSiteTreeFilter')) { throw new Exception(sprintf('Invalid filter class passed: %s', $filterClass)); } $filter = new $filterClass($params); } else { $filter = null; } // Default childrenMethod and numChildrenMethod if (!$childrenMethod) { $childrenMethod = $filter && $filter->getChildrenMethod() ? $filter->getChildrenMethod() : 'AllChildrenIncludingDeleted'; } if (!$numChildrenMethod) { $numChildrenMethod = 'numChildren'; } if (!$filterFunction) { $filterFunction = $filter ? array($filter, 'isPageIncluded') : null; } // Get the tree root $record = $rootID ? $this->getRecord($rootID) : null; $obj = $record ? $record : singleton($className); // Mark the nodes of the tree to return if ($filterFunction) { $obj->setMarkingFilterFunction($filterFunction); } $obj->markPartialTree($minNodeCount, $this, $childrenMethod, $numChildrenMethod); // Ensure current page is exposed if ($p = $this->currentPage()) { $obj->markToExpose($p); } // NOTE: SiteTree/CMSMain coupling :-( if (class_exists('SiteTree')) { SiteTree::prepopulate_permission_cache('CanEditType', $obj->markedNodeIDs(), 'SiteTree::can_edit_multiple'); } // getChildrenAsUL is a flexible and complex way of traversing the tree $controller = $this; $recordController = $this->stat('tree_class') == 'SiteTree' ? singleton('CMSPageEditController') : $this; $titleFn = function (&$child) use(&$controller, &$recordController) { $link = Controller::join_links($recordController->Link("show"), $child->ID); return LeftAndMain_TreeNode::create($child, $link, $controller->isCurrentPage($child))->forTemplate(); }; $html = $obj->getChildrenAsUL("", $titleFn, singleton('CMSPagesController'), true, $childrenMethod, $numChildrenMethod, $minNodeCount); // Wrap the root if needs be. if (!$rootID) { $rootLink = $this->Link('show') . '/root'; // This lets us override the tree title with an extension if ($this->hasMethod('getCMSTreeTitle') && ($customTreeTitle = $this->getCMSTreeTitle())) { $treeTitle = $customTreeTitle; } elseif (class_exists('SiteConfig')) { $siteConfig = SiteConfig::current_site_config(); $treeTitle = $siteConfig->Title; } else { $treeTitle = '...'; } $html = "<ul><li id=\"record-0\" data-id=\"0\" class=\"Root nodelete\"><strong>{$treeTitle}</strong>" . $html . "</li></ul>"; } return $html; }
/** * Get a site tree HTML listing which displays the nodes under the given criteria. * * @param $className The class of the root object * @param $rootID The ID of the root object. If this is null then a complete tree will be * shown * @param $childrenMethod The method to call to get the children of the tree. For example, * Children, AllChildrenIncludingDeleted, or AllHistoricalChildren * @return String Nested unordered list with links to each page */ public function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $numChildrenMethod = null, $filterFunction = null, $nodeCountThreshold = 30) { // Filter criteria $params = $this->request->getVar('q'); if (isset($params['FilterClass']) && ($filterClass = $params['FilterClass'])) { if (!is_subclass_of($filterClass, 'CMSSiteTreeFilter')) { throw new Exception(sprintf('Invalid filter class passed: %s', $filterClass)); } $filter = new $filterClass($params); } else { $filter = null; } // Default childrenMethod and numChildrenMethod if (!$childrenMethod) { $childrenMethod = $filter && $filter->getChildrenMethod() ? $filter->getChildrenMethod() : 'AllChildrenIncludingDeleted'; } if (!$numChildrenMethod) { $numChildrenMethod = 'numChildren'; } if (!$filterFunction) { $filterFunction = $filter ? array($filter, 'isPageIncluded') : null; } // Get the tree root $record = $rootID ? $this->getRecord($rootID) : null; $obj = $record ? $record : singleton($className); // Mark the nodes of the tree to return if ($filterFunction) { $obj->setMarkingFilterFunction($filterFunction); } $obj->markPartialTree($nodeCountThreshold, $this, $childrenMethod, $numChildrenMethod); // Ensure current page is exposed if ($p = $this->currentPage()) { $obj->markToExpose($p); } // NOTE: SiteTree/CMSMain coupling :-( if (class_exists('SiteTree')) { SiteTree::prepopulate_permission_cache('CanEditType', $obj->markedNodeIDs(), 'SiteTree::can_edit_multiple'); } // getChildrenAsUL is a flexible and complex way of traversing the tree $controller = $this; $recordController = $this->stat('tree_class') == 'SiteTree' ? singleton('CMSPageEditController') : $this; $titleFn = function (&$child) use(&$controller, &$recordController) { $link = Controller::join_links($recordController->Link("show"), $child->ID); return LeftAndMain_TreeNode::create($child, $link, $controller->isCurrentPage($child))->forTemplate(); }; // Limit the amount of nodes shown for performance reasons. // Skip the check if we're filtering the tree, since its not clear how many children will // match the filter criteria until they're queried (and matched up with previously marked nodes). $nodeThresholdLeaf = Config::inst()->get('Hierarchy', 'node_threshold_leaf'); if ($nodeThresholdLeaf && !$filterFunction) { $nodeCountCallback = function ($parent, $numChildren) use(&$controller, $className, $nodeThresholdLeaf) { if ($className == 'SiteTree' && $parent->ID && $numChildren > $nodeThresholdLeaf) { return sprintf('<ul><li class="readonly"><span class="item">' . '%s (<a href="%s" class="cms-panel-link" data-pjax-target="Content">%s</a>)' . '</span></li></ul>', _t('LeftAndMain.TooManyPages', 'Too many pages'), Controller::join_links($controller->LinkWithSearch($controller->Link()), ' ?view=list&ParentID=' . $parent->ID), _t('LeftAndMain.ShowAsList', 'show as list', 'Show large amount of pages in list instead of tree view')); } }; } else { $nodeCountCallback = null; } // If the amount of pages exceeds the node thresholds set, use the callback $html = null; if ($obj->ParentID && $nodeCountCallback) { $html = $nodeCountCallback($obj, $obj->{$numChildrenMethod}()); } // Otherwise return the actual tree (which might still filter leaf thresholds on children) if (!$html) { $html = $obj->getChildrenAsUL("", $titleFn, singleton('CMSPagesController'), true, $childrenMethod, $numChildrenMethod, $nodeCountThreshold, $nodeCountCallback); } // Wrap the root if needs be. if (!$rootID) { $rootLink = $this->Link('show') . '/root'; // This lets us override the tree title with an extension if ($this->hasMethod('getCMSTreeTitle') && ($customTreeTitle = $this->getCMSTreeTitle())) { $treeTitle = $customTreeTitle; } elseif (class_exists('SiteConfig')) { $siteConfig = SiteConfig::current_site_config(); $treeTitle = Convert::raw2xml($siteConfig->Title); } else { $treeTitle = '...'; } $html = "<ul><li id=\"record-0\" data-id=\"0\" class=\"Root nodelete\"><strong>{$treeTitle}</strong>" . $html . "</li></ul>"; } return $html; }