From a56657fb83d3cdea9c711dfb99daca321478f0bc Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Sun, 16 Sep 2007 15:19:17 +0000 Subject: [PATCH] elofgren: NEW FEATURE: When 'Search' button is clicked show a simple search text input and button which allow for filtering the Site Tree by searching the URL, Title, Menu Title, and Content. Also show an 'Add criteria...' drop-down with 'Page Type', 'Status', 'Description', and 'Keywords' options which allow for more fine grained filtering based on columns in the SiteTree? table. In addition add an 'Edited Since' option which uses a CalendarDatePicker? which allows for filtering pages based on when they were last edited. NOTE: Pages that have children will always be shown whether they match the filter or not, in case one of their children matches the filter. It would probably be better to switch to a flat display of the results. More info: http://www.silverstripe.com/google-summer-of-code-forum/flat/2526 (merged from branches/gsoc) git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@42086 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- code/CMSMain.php | 108 +++++++++++++++++++++++++++++ css/cms_left.css | 4 ++ javascript/CMSMain_left.js | 47 +++++++++++++ javascript/LeftAndMain_left.js | 39 +++++------ lang/en_US.php | 10 +++ templates/Includes/CMSMain_left.ss | 25 ++++++- 6 files changed, 209 insertions(+), 24 deletions(-) diff --git a/code/CMSMain.php b/code/CMSMain.php index fd545dce..1336f742 100644 --- a/code/CMSMain.php +++ b/code/CMSMain.php @@ -9,6 +9,11 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionProvider { static $tree_class = "SiteTree"; static $subitem_class = "Member"; + /** + * SiteTree Columns that can be filtered using the the Site Tree Search button + */ + static $site_tree_filter_options = array('ClassName' => 'Page Type', 'Status' => 'Status', + 'MetaDescription' => 'Description', 'MetaKeywords' => 'Keywords'); public function init() { parent::init(); @@ -103,6 +108,59 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr return $this->getSiteTreeFor("SiteTree"); } + /** + * Returns the SiteTree columns that can be filtered using the the Site Tree Search button as a DataObjectSet + */ + public function SiteTreeFilterOptions() { + $filter_options = new DataObjectSet(); + foreach(self::$site_tree_filter_options as $key => $value) { + $record = array( + 'Column' => $key, + 'Title' => $value, + ); + $filter_options->push(new ArrayData($record)); + } + return $filter_options; + } + public function SiteTreeFilterDateField() { + $dateField = new CalendarDateField('SiteTreeFilterDate'); + return $dateField->Field(); + } + + /** + * Returns a filtered Site Tree + */ + public function filterSiteTree() { + $className = 'SiteTree'; + $rootID = null; + $obj = $rootID ? $this->getRecord($rootID) : singleton($className); + $obj->setMarkingFilterFunction('CMSMainMarkingFilterFunction'); + $obj->markPartialTree(); + + if($p = $this->currentPage()) $obj->markToExpose($p); + + // getChildrenAsUL is a flexible and complex way of traversing the tree + $siteTree = $obj->getChildrenAsUL("", ' + "
  • ID\" class=\"" . $child->CMSTreeClasses($extraArg) . "\">" . + "Link(),0,-1), "show", $child->ID) . "\" " . (($child->canEdit() || $child->canAddChildren()) ? "" : "class=\"disabled\"") . " title=\"' . _t('LeftAndMain.PAGETYPE','Page type: ') . '".$child->class."\" >" . + ($child->TreeTitle()) . + "" +' + ,$this, true); + + // Wrap the root if needs be. + + if(!$rootID) { + $rootLink = $this->Link() . '0'; + $siteTree = ""; + } + + return $siteTree; + + } + public function generateDataTreeHints() { $classes = ClassInfo::subclassesFor( $this->stat('tree_class') ); @@ -1162,5 +1220,55 @@ HTML; return $perms; } } +// TODO: Find way to put this in a class +function CMSMainMarkingFilterFunction($node) { + // Expand all nodes + // $node->markingFinished(); + // Don't ever hide nodes with children, because otherwise if one of their children matches the search, it wouldn't be shown. + if($node->AllChildrenIncludingDeleted()->count() > 0) { + // Open all nodes with children so it is easy to see any children that match the search. + $node->markOpened(); + return true; + } else { + $failed_filter = false; + // First check for the generic search term in the URLSegment, Title, MenuTitle, & Content + if (!empty($_REQUEST['SiteTreeSearchTerm'])) { + // For childless nodes, show only those matching the filter + $filter = strtolower($_REQUEST['SiteTreeSearchTerm']); + if ( strpos( strtolower($node->URLSegment) , $filter) === false + && strpos( strtolower($node->Title) , $filter) === false + && strpos( strtolower($node->MenuTitle) , $filter) === false + && strpos( strtolower($node->Content) , $filter) === false) { + $failed_filter = true; + } + } + // Check the 'Edited Since' date + if (!empty($_REQUEST['SiteTreeFilterDate'])) { + $edited_since = mktime(0, 0, 0, substr($_REQUEST['SiteTreeFilterDate'], 3, 2), + substr($_REQUEST['SiteTreeFilterDate'], 0, 2), substr($_REQUEST['SiteTreeFilterDate'], 6, 4)); + if ( strtotime($node->LastEdited) < $edited_since ) { + $failed_filter = true; + } + } + // Now check if a specified Criteria attribute matches + foreach (CMSMain::$site_tree_filter_options as $key => $value) + { + if (!empty($_REQUEST[$key])) { + $parameterName = $key; + $filter = strtolower($_REQUEST[$key]); + // Show node only if the filter string exists anywere in the filter paramater (ignoring case) + if (strpos( strtolower($node->$parameterName) , $filter) === false) { + $failed_filter = true; + } + } + } + // Each filter must match or it fails + if (true == $failed_filter) { + return false; + } else { + return true; + } + } +} ?> \ No newline at end of file diff --git a/css/cms_left.css b/css/cms_left.css index 8bd584f7..1c10ad10 100644 --- a/css/cms_left.css +++ b/css/cms_left.css @@ -375,3 +375,7 @@ ul.tree span.a.MailType span.c, ul.tree span.a.last.MailType span.c, ul.tree spa background-color: #B6BDD2; text-decoration: none; } +#left form.actionparams .SearchCriteria { + width: 45%; + float: left; +} \ No newline at end of file diff --git a/javascript/CMSMain_left.js b/javascript/CMSMain_left.js index 99dd0ff0..6da820f6 100755 --- a/javascript/CMSMain_left.js +++ b/javascript/CMSMain_left.js @@ -97,6 +97,53 @@ addpage.prototype = { } } +/** + * Search button click action + */ +search = Class.create(); +search.applyTo('#search'); +search.prototype = { + initialize : function() { + Observable.applyTo($(_HANDLER_FORMS.search)); + }, + onclick : function() { + if(treeactions.toggleSelection(this)) { + this.o2 = $(_HANDLER_FORMS[this.id]).observeMethod('Close', this.popupClosed.bind(this)); + } + return false; + }, + popupClosed : function() { + $(_HANDLER_FORMS.search).stopObserving(this.o2); + // Reload the site tree if it has been filtered + if ($('SiteTreeIsFiltered').value == 1) { + // Show all items in Site Tree again + new Ajax.Request( 'admin/SiteTreeAsUL' + '&ajax=1', { + onSuccess: function( response ) { + $('sitetree_ul').innerHTML = response.responseText; + Behaviour.apply(); + $('SiteTreeIsFiltered').value = 0; + statusMessage('Unfiltered tree','good'); + }, + onFailure : function(response) { + errorMessage('Could not unfilter site tree
    ' + response.responseText); + } + }); + } + } +} + +/** + * Add Criteria Drop-down onchange action which allows more criteria to be shown + */ +SiteTreeFilterAddCriteria = Class.create(); +SiteTreeFilterAddCriteria.applyTo('#SiteTreeFilterAddCriteria'); +SiteTreeFilterAddCriteria.prototype = { + onchange : function() { + Element.show('Text' + this.value); + Element.show('Input' + this.value); + } +} + /** * Batch Actions button click action */ diff --git a/javascript/LeftAndMain_left.js b/javascript/LeftAndMain_left.js index 9cf3b9ce..e62b1adb 100755 --- a/javascript/LeftAndMain_left.js +++ b/javascript/LeftAndMain_left.js @@ -12,7 +12,8 @@ SiteTreeHandlers.controller_url = 'admin'; var _HANDLER_FORMS = { addpage : 'Form_AddPageOptionsForm', - batchactions : 'batchactionsforms' + batchactions : 'batchactionsforms', + search : 'search_options' }; @@ -460,28 +461,22 @@ ReorganiseAction.prototype = { * Control the site tree filter */ SiteTreeFilterForm = Class.create(); -SiteTreeFilterForm.applyTo('form#SiteTreeFilter'); +SiteTreeFilterForm.applyTo('form#search_options'); SiteTreeFilterForm.prototype = { - - initialize: function() { - this.valueField = $('SiteTreeFilterValue'); - this.submitButton = $('SiteTreeFilterButton'); - this.submitButton.onclick = this.submitclick.bind(this); - // this.submitButton.onclick = function() { alert('Click'); return false; } - }, - - submitclick: function() { - new Ajax.Request( this.action + '?SiteTreeFilterValue=' + encodeURIComponent( this.valueField.value ) + '&ajax=1', { - onSuccess: function( response ) { - alert(response.responseText); - $('sitetree').innerHTML = response.responseText; - Behaviour.apply( $('sitetree') ); - statusMessage('Filtered tree','good'); - }, - onFailure: function( response ) { - errorMessage('Could not filter site tree
    ' + response.responseText); - } - }); + onsubmit: function() { + $('SiteTreeSearchButton').className = 'loading'; + Ajax.SubmitForm(this, null, { + onSuccess : function(response) { + $('SiteTreeIsFiltered').value = 1; + $('SiteTreeSearchButton').className = ''; + $('sitetree_ul').innerHTML = response.responseText; + Behaviour.apply(); + statusMessage('Filtered tree','good'); + }, + onFailure : function(response) { + errorMessage('Could not filter site tree
    ' + response.responseText); + } + }); return false; } diff --git a/lang/en_US.php b/lang/en_US.php index 4eea6b57..254cad8d 100755 --- a/lang/en_US.php +++ b/lang/en_US.php @@ -2,6 +2,12 @@ global $lang; +$lang['en_US']['LeftAndMain']['PAGETYPE'] = 'Page type: '; +$lang['en_US']['LeftAndMain']['SITECONTENT'] = array( + 'Site Content', + PR_HIGH, + 'Root node on left' +); $lang['en_US']['CMSMain']['CREATE'] = array( 'Create a ', PR_MEDIUM, @@ -143,6 +149,10 @@ $lang['en_US']['CMSMain_left.ss']['ENABLEDRAGGING'] = array( 'Allow drag & drop reordering', PR_HIGH ); +$lang['en_US']['CMSMain_left.ss']['SEARCH'] = 'Search'; +$lang['en_US']['CMSMain_left.ss']['SEARCHTITLE'] = 'Search through URL, Title, Menu Title, & Content'; +$lang['en_US']['CMSMain_left.ss']['EDITEDSINCE'] = 'Edited Since'; +$lang['en_US']['CMSMain_left.ss']['ADDSEARCHCRITERIA'] = 'Add Criteria...'; $lang['en_US']['CMSMain_left.ss']['SELECTPAGESACTIONS'] = 'Select the pages that you want to change & then click an action:'; $lang['en_US']['CMSMain_left.ss']['DELETECONFIRM'] = 'Delete the selected pages'; $lang['en_US']['CMSMain_left.ss']['PUBLISHCONFIRM'] = 'Publish the selected pages'; diff --git a/templates/Includes/CMSMain_left.ss b/templates/Includes/CMSMain_left.ss index cafb021e..207d34ff 100755 --- a/templates/Includes/CMSMain_left.ss +++ b/templates/Includes/CMSMain_left.ss @@ -42,6 +42,26 @@ <% end_control %> + - - $SiteTreeAsUL +
    + $SiteTreeAsUL +