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 +