mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-05 07:38:26 +02:00
Merge pull request #4153 from tractorcow/pulls/3/filter-page-highlight
API Enable tree filter highlighting
This commit is contained in:
commit
2a04713323
@ -772,6 +772,29 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
|||||||
return $html;
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current search filter for this request, if available
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
* @return LeftAndMain_SearchFilter
|
||||||
|
*/
|
||||||
|
protected function getSearchFilter() {
|
||||||
|
// Check for given FilterClass
|
||||||
|
$params = $this->getRequest()->getVar('q');
|
||||||
|
if(empty($params['FilterClass'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate classname
|
||||||
|
$filterClass = $params['FilterClass'];
|
||||||
|
$filterInfo = new ReflectionClass($filterClass);
|
||||||
|
if(!$filterInfo->implementsInterface('LeftAndMain_SearchFilter')) {
|
||||||
|
throw new InvalidArgumentException(sprintf('Invalid filter class passed: %s', $filterClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Injector::inst()->createWithArgs($filterClass, array($params));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a site tree HTML listing which displays the nodes under the given criteria.
|
* Get a site tree HTML listing which displays the nodes under the given criteria.
|
||||||
*
|
*
|
||||||
@ -786,15 +809,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
|||||||
$filterFunction = null, $nodeCountThreshold = 30) {
|
$filterFunction = null, $nodeCountThreshold = 30) {
|
||||||
|
|
||||||
// Filter criteria
|
// Filter criteria
|
||||||
$params = $this->getRequest()->getVar('q');
|
$filter = $this->getSearchFilter();
|
||||||
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
|
// Default childrenMethod and numChildrenMethod
|
||||||
if(!$childrenMethod) $childrenMethod = ($filter && $filter->getChildrenMethod())
|
if(!$childrenMethod) $childrenMethod = ($filter && $filter->getChildrenMethod())
|
||||||
@ -807,7 +822,11 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
|||||||
$numChildrenMethod = $filter->getNumChildrenMethod();
|
$numChildrenMethod = $filter->getNumChildrenMethod();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!$filterFunction) $filterFunction = ($filter) ? array($filter, 'isPageIncluded') : null;
|
if(!$filterFunction && $filter) {
|
||||||
|
$filterFunction = function($node) use($filter) {
|
||||||
|
return $filter->isPageIncluded($node);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Get the tree root
|
// Get the tree root
|
||||||
$record = ($rootID) ? $this->getRecord($rootID) : null;
|
$record = ($rootID) ? $this->getRecord($rootID) : null;
|
||||||
@ -833,9 +852,9 @@ class LeftAndMain extends Controller implements PermissionProvider {
|
|||||||
// getChildrenAsUL is a flexible and complex way of traversing the tree
|
// getChildrenAsUL is a flexible and complex way of traversing the tree
|
||||||
$controller = $this;
|
$controller = $this;
|
||||||
$recordController = ($this->stat('tree_class') == 'SiteTree') ? singleton('CMSPageEditController') : $this;
|
$recordController = ($this->stat('tree_class') == 'SiteTree') ? singleton('CMSPageEditController') : $this;
|
||||||
$titleFn = function(&$child, $numChildrenMethod) use(&$controller, &$recordController) {
|
$titleFn = function(&$child, $numChildrenMethod) use(&$controller, &$recordController, $filter) {
|
||||||
$link = Controller::join_links($recordController->Link("show"), $child->ID);
|
$link = Controller::join_links($recordController->Link("show"), $child->ID);
|
||||||
$node = LeftAndMain_TreeNode::create($child, $link, $controller->isCurrentPage($child), $numChildrenMethod);
|
$node = LeftAndMain_TreeNode::create($child, $link, $controller->isCurrentPage($child), $numChildrenMethod, $filter);
|
||||||
return $node->forTemplate();
|
return $node->forTemplate();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1866,36 +1885,56 @@ class LeftAndMain_HTTPResponse extends SS_HTTPResponse {
|
|||||||
class LeftAndMain_TreeNode extends ViewableData {
|
class LeftAndMain_TreeNode extends ViewableData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var obj
|
* Object represented by this node
|
||||||
|
*
|
||||||
|
* @var Object
|
||||||
*/
|
*/
|
||||||
protected $obj;
|
protected $obj;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var String Edit link to the current record in the CMS
|
* Edit link to the current record in the CMS
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $link;
|
protected $link;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Bool
|
* True if this is the currently selected node in the tree
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
*/
|
*/
|
||||||
protected $isCurrent;
|
protected $isCurrent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Name of method to count the number of children
|
||||||
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $numChildrenMethod;
|
protected $numChildrenMethod;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $obj
|
*
|
||||||
* @param null $link
|
* @var LeftAndMain_SearchFilter
|
||||||
* @param bool $isCurrent
|
|
||||||
* @param $numChildrenMethod
|
|
||||||
*/
|
*/
|
||||||
public function __construct($obj, $link = null, $isCurrent = false, $numChildrenMethod='numChildren') {
|
protected $filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Object $obj
|
||||||
|
* @param string $link
|
||||||
|
* @param bool $isCurrent
|
||||||
|
* @param string $numChildrenMethod
|
||||||
|
* @param LeftAndMain_SearchFilter $filter
|
||||||
|
*/
|
||||||
|
public function __construct($obj, $link = null, $isCurrent = false,
|
||||||
|
$numChildrenMethod = 'numChildren', $filter = null
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
$this->obj = $obj;
|
$this->obj = $obj;
|
||||||
$this->link = $link;
|
$this->link = $link;
|
||||||
$this->isCurrent = $isCurrent;
|
$this->isCurrent = $isCurrent;
|
||||||
$this->numChildrenMethod = $numChildrenMethod;
|
$this->numChildrenMethod = $numChildrenMethod;
|
||||||
|
$this->filter = $filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1915,16 +1954,34 @@ class LeftAndMain_TreeNode extends ViewableData {
|
|||||||
. "</span></a>";
|
. "</span></a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the CSS classes to apply to this node
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getClasses() {
|
public function getClasses() {
|
||||||
|
// Get classes from object
|
||||||
$classes = $this->obj->CMSTreeClasses($this->numChildrenMethod);
|
$classes = $this->obj->CMSTreeClasses($this->numChildrenMethod);
|
||||||
if($this->isCurrent) $classes .= " current";
|
if($this->isCurrent) {
|
||||||
$flags = $this->obj->hasMethod('getStatusFlags') ? $this->obj->getStatusFlags() : false;
|
$classes .= ' current';
|
||||||
|
}
|
||||||
|
// Get status flag classes
|
||||||
|
$flags = $this->obj->hasMethod('getStatusFlags')
|
||||||
|
? $this->obj->getStatusFlags()
|
||||||
|
: false;
|
||||||
if ($flags) {
|
if ($flags) {
|
||||||
$statuses = array_keys($flags);
|
$statuses = array_keys($flags);
|
||||||
foreach ($statuses as $s) {
|
foreach ($statuses as $s) {
|
||||||
$classes .= ' status-' . $s;
|
$classes .= ' status-' . $s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Get additional filter classes
|
||||||
|
if($this->filter && ($filterClasses = $this->filter->getPageClasses($this->obj))) {
|
||||||
|
if(is_array($filterClasses)) {
|
||||||
|
$filterClasses = implode(' ' . $filterClasses);
|
||||||
|
}
|
||||||
|
$classes .= ' ' . $filterClasses;
|
||||||
|
}
|
||||||
return $classes;
|
return $classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1956,3 +2013,42 @@ class LeftAndMain_TreeNode extends ViewableData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract interface for a class which may be used to filter the results displayed
|
||||||
|
* in a nested tree
|
||||||
|
*/
|
||||||
|
interface LeftAndMain_SearchFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method on {@link Hierarchy} objects which is used to traverse into children relationships.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getChildrenMethod();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method on {@link Hierarchy} objects which is used find the number of children for a parent page
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getNumChildrenMethod();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns TRUE if the given page should be included in the tree.
|
||||||
|
* Caution: Does NOT check view permissions on the page.
|
||||||
|
*
|
||||||
|
* @param DataObject $page
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isPageIncluded($page);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a page, determine any additional CSS classes to apply to the tree node
|
||||||
|
*
|
||||||
|
* @param DataObject $page
|
||||||
|
* @return array|string
|
||||||
|
*/
|
||||||
|
public function getPageClasses($page);
|
||||||
|
}
|
||||||
|
@ -850,6 +850,8 @@ form.import-form label.left { width: 250px; }
|
|||||||
.tree-holder.jstree .jstree-hovered, .cms-tree.jstree .jstree-hovered { text-shadow: none; text-decoration: none; }
|
.tree-holder.jstree .jstree-hovered, .cms-tree.jstree .jstree-hovered { text-shadow: none; text-decoration: none; }
|
||||||
.tree-holder.jstree .jstree-closed > ins, .cms-tree.jstree .jstree-closed > ins { background-position: 0 0; }
|
.tree-holder.jstree .jstree-closed > ins, .cms-tree.jstree .jstree-closed > ins { background-position: 0 0; }
|
||||||
.tree-holder.jstree .jstree-open > ins, .cms-tree.jstree .jstree-open > ins { background-position: -20px 0; }
|
.tree-holder.jstree .jstree-open > ins, .cms-tree.jstree .jstree-open > ins { background-position: -20px 0; }
|
||||||
|
.tree-holder.filtered-list li.class-Page a, .cms-tree.filtered-list li.class-Page a { color: #aaaaaa; }
|
||||||
|
.tree-holder.filtered-list li.class-Page.filtered-item a, .cms-tree.filtered-list li.class-Page.filtered-item a { color: #0073c1; }
|
||||||
|
|
||||||
/* ensure status is visible in sidebar */
|
/* ensure status is visible in sidebar */
|
||||||
#cms-content-tools-CMSMain .cms-tree.jstree li { min-width: 159px; }
|
#cms-content-tools-CMSMain .cms-tree.jstree li { min-width: 159px; }
|
||||||
|
@ -552,6 +552,17 @@
|
|||||||
background-position:-20px 0;
|
background-position:-20px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Applied to trees when displaying filter / search results.
|
||||||
|
&.filtered-list {
|
||||||
|
li.class-Page a {
|
||||||
|
color: $color-text-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.class-Page.filtered-item a {
|
||||||
|
color: $color-text-blue-link;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ensure status is visible in sidebar */
|
/* ensure status is visible in sidebar */
|
||||||
|
Loading…
Reference in New Issue
Block a user