mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
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
This commit is contained in:
parent
c09e518635
commit
a56657fb83
108
code/CMSMain.php
108
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("", '
|
||||
"<li id=\"record-$child->ID\" class=\"" . $child->CMSTreeClasses($extraArg) . "\">" .
|
||||
"<a href=\"" . Director::link(substr($extraArg->Link(),0,-1), "show", $child->ID) . "\" " . (($child->canEdit() || $child->canAddChildren()) ? "" : "class=\"disabled\"") . " title=\"' . _t('LeftAndMain.PAGETYPE','Page type: ') . '".$child->class."\" >" .
|
||||
($child->TreeTitle()) .
|
||||
"</a>"
|
||||
'
|
||||
,$this, true);
|
||||
|
||||
// Wrap the root if needs be.
|
||||
|
||||
if(!$rootID) {
|
||||
$rootLink = $this->Link() . '0';
|
||||
$siteTree = "<ul id=\"sitetree\" class=\"tree unformatted\"><li id=\"record-0\" class=\"Root nodelete\"><a href=\"$rootLink\">" .
|
||||
_t('LeftAndMain.SITECONTENT',"Site Content",PR_HIGH,'Root node on left') . "</a>"
|
||||
. $siteTree . "</li></ul>";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -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;
|
||||
}
|
@ -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<br />' + 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
|
||||
*/
|
||||
|
@ -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<br />' + 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<br />' + response.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -42,6 +42,26 @@
|
||||
|
||||
</form>
|
||||
<% end_control %>
|
||||
<form class="actionparams" style="display: none" id="search_options" action="admin/filterSiteTree">
|
||||
<div>
|
||||
<input type="hidden" id="SiteTreeIsFiltered" value="0" />
|
||||
<input type="text" id="SiteTreeSearchTerm" name="SiteTreeSearchTerm" />
|
||||
<input type="submit" id="SiteTreeSearchButton" value="<% _t('SEARCH','Search'); %>" title="<% _t('SEARCHTITLE','Search through URL, Title, Menu Title, & Content'); %>" />
|
||||
<div style="display:none" id="TextSiteTreeFilterDate" class="SearchCriteria"><b><% _t('EDITEDSINCE','Edited Since'); %>:</b></div>
|
||||
<div style="display:none" id="InputSiteTreeFilterDate">$SiteTreeFilterDateField</div>
|
||||
<% control SiteTreeFilterOptions %>
|
||||
<div style="display:none" id="Text$Column" class="SearchCriteria"><b>$Title:</b></div>
|
||||
<input style="display:none" id="Input$Column" name="$Column" class="SearchCriteria" />
|
||||
<% end_control %>
|
||||
<select id="SiteTreeFilterAddCriteria">
|
||||
<option><% _t('ADDSEARCHCRITERIA','Add Criteria...'); %></option>
|
||||
<option value="SiteTreeFilterDate"><% _t('EDITEDSINCE','Edited Since'); %></option>
|
||||
<% control SiteTreeFilterOptions %>
|
||||
<option value="$Column">$Title</option>
|
||||
<% end_control %>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
<div id="batchactionsforms" style="display: none">
|
||||
<form class="actionparams" style="border:0" id="deletepage_options" action="admin/deleteitems">
|
||||
<p><% _t('SELECTPAGESACTIONS','Select the pages that you want to change & then click an action:'); %></p>
|
||||
@ -74,8 +94,9 @@
|
||||
<span style="cursor: help" title="<% _t('EDITEDNOTPUB','Edited on the draft site and not published yet'); %>" class="modified"><% _t('CHANGED','changed'); %></span>
|
||||
</div>
|
||||
|
||||
|
||||
$SiteTreeAsUL
|
||||
<div id="sitetree_ul">
|
||||
$SiteTreeAsUL
|
||||
</div>
|
||||
</div>
|
||||
<!--<div id="search_holder" style="display:none">
|
||||
<h2>Search</h2>
|
||||
|
Loading…
Reference in New Issue
Block a user