diff --git a/code/CMSMain.php b/code/CMSMain.php
index 4a0ee603..abea0e60 100644
--- a/code/CMSMain.php
+++ b/code/CMSMain.php
@@ -57,6 +57,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
'SiteTreeAsUL',
'getshowdeletedsubtree',
'getfilteredsubtree',
+ 'getawesomesubtree',
'batchactions'
);
@@ -152,31 +153,43 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
return $this->getSiteTreeFor("SiteTree");
}
-
+
/**
- * Get a subtree underneath the request param 'ID', of the tree that includes deleted pages.
- * If ID = 0, then get the whole tree.
+ * Use a CMSSiteTreeFilter to only get certain nodes
+ *
+ * @return string
*/
- public function getshowdeletedsubtree() {
- // Get the tree
- $tree = $this->getSiteTreeFor($this->stat('tree_class'), $_REQUEST['ID'], "AllHistoricalChildren");
-
- // Trim off the outer tag
- $tree = ereg_replace('^[ \t\r\n]*
]*>','', $tree);
- $tree = ereg_replace('
]*>[ \t\r\n]*$','', $tree);
-
- return $tree;
+ public function getfilteredsubtree() {
+ // Sanity and security checks
+ if (!isset($_REQUEST['filter'])) die('No filter passed');
+ if (!ClassInfo::exists($_REQUEST['filter'])) die ('That filter class does not exist');
+ if (!is_subclass_of($_REQUEST['filter'], 'CMSSiteTreeFilter')) die ('That is not a valid filter');
+
+ // Do eeet!
+ $filter = new $_REQUEST['filter']();
+ return $filter->getTree();
}
- public function getfilteredsubtree() {
- // Get the tree
- $tree = $this->getSiteTreeFor($this->stat('tree_class'), $_REQUEST['ID'], null, array(new CMSMainMarkingFilter(), 'mark'));
-
- // Trim off the outer tag
- $tree = ereg_replace('^[ \t\r\n]*
]*>','', $tree);
- $tree = ereg_replace('
]*>[ \t\r\n]*$','', $tree);
-
- return $tree;
+ /**
+ * Returns a list of batch actions
+ */
+ function SiteTreeFilters() {
+ $filters = ClassInfo::subclassesFor('CMSSiteTreeFilter');
+ array_shift($filters);
+ $doSet = new DataObjectSet();
+ $doSet->push(new ArrayData(array(
+ 'ClassName' => 'all',
+ 'Title' => 'All items'
+ )));
+ foreach($filters as $filter) {
+ if (call_user_func(array($filter, 'showInList'))) {
+ $doSet->push(new ArrayData(array(
+ 'ClassName' => $filter,
+ 'Title' => call_user_func(array($filter, 'title'))
+ )));
+ }
+ }
+ return $doSet;
}
/**
diff --git a/code/CMSSiteTreeFilter.php b/code/CMSSiteTreeFilter.php
new file mode 100644
index 00000000..e0a858b2
--- /dev/null
+++ b/code/CMSSiteTreeFilter.php
@@ -0,0 +1,136 @@
+getSiteTreeFor('SiteTree', isset($_REQUEST['ID']) ? $_REQUEST['ID'] : 0, "AllHistoricalChildren");
+
+ // Trim off the outer tag
+ $tree = ereg_replace('^[ \t\r\n]*
]*>','', $tree);
+ $tree = ereg_replace('
]*>[ \t\r\n]*$','', $tree);
+
+ return $tree;
+ }
+}
+
+class CMSSiteTreeFilter_ChangedPages extends CMSSiteTreeFilter {
+ static function title() {
+ return "Changed pages";
+ }
+
+ function getTree() {
+ $search = new CMSSitetreeFilter_Search();
+ $search->data = array('Status' => 'Saved');
+ return $search->getTree();
+ }
+}
+
+class CMSSiteTreeFilter_Search extends CMSSiteTreeFilter {
+ protected $ids = null;
+ protected $expanded = array();
+ public $data;
+
+
+ function __construct() {
+ $this->data = $_REQUEST;
+ }
+
+ static function showInList() { return false; }
+
+ static function title() {
+ return "Search";
+ }
+
+ function populateIds($data) {
+ $this->ids = array();
+ $this->expanded = array();
+
+ $where = array();
+
+ // Match against URLSegment, Title, MenuTitle & Content
+ if (isset($data['SiteTreeSearchTerm'])) {
+ $term = Convert::raw2sql($data['SiteTreeSearchTerm']);
+ $where[] = "\"URLSegment\" LIKE '%$term%' OR \"Title\" LIKE '%$term%' OR \"MenuTitle\" LIKE '%$term%' OR \"Content\" LIKE '%$term%'";
+ }
+
+ // Match against date
+ if (isset($data['SiteTreeFilterDate'])) {
+ $date = $data['SiteTreeFilterDate'];
+ $date = ((int)substr($date,6,4)) . '-' . ((int)substr($date,3,2)) . '-' . ((int)substr($date,0,2));
+ $where[] = "\"LastEdited\" > '$date'";
+ }
+
+ // Match against exact ClassName
+ if (isset($data['ClassName']) && $data['ClassName'] != 'All') {
+ $klass = Convert::raw2sql($data['ClassName']);
+ $where[] = "\"ClassName\" = '$klass'";
+ }
+
+ // Partial string match against a variety of fields
+ foreach (CMSMain::T_SiteTreeFilterOptions() as $key => $value) {
+ if (!empty($data[$key])) {
+ $match = Convert::raw2sql($data[$key]);
+ $where[] = "\"$key\" LIKE '%$match%'";
+ }
+ }
+
+ $where = empty($where) ? '' : 'WHERE (' . implode(') AND (',$where) . ')';
+
+ $parents = array();
+
+ /* Do the actual search */
+ $res = DB::query('SELECT "ParentID", "ID" FROM "SiteTree" '.$where);
+ if (!$res) return;
+
+ /* And keep a record of parents we don't need to get parents of themselves, as well as IDs to mark */
+ foreach($res as $row) {
+ if ($row['ParentID']) $parents[$row['ParentID']] = true;
+ $this->ids[$row['ID']] = true;
+ }
+
+ /* We need to recurse up the tree, finding ParentIDs for each ID until we run out of parents */
+ while (!empty($parents)) {
+ $res = DB::query('SELECT "ParentID", "ID" FROM "SiteTree" WHERE "ID" in ('.implode(',',array_keys($parents)).')');
+ $parents = array();
+
+ foreach($res as $row) {
+ if ($row['ParentID']) $parents[$row['ParentID']] = true;
+ $this->ids[$row['ID']] = true;
+ $this->expanded[$row['ID']] = true;
+ }
+ }
+ }
+
+ public function includeInTree($page) {
+ if ($this->ids === null) $this->populateIds($this->data);
+ return isset($this->ids[$page->ID]) && $this->ids[$page->ID] ? true : false;
+ }
+
+ function getTree() {
+ $leftAndMain = new LeftAndMain();
+ $tree = $leftAndMain->getSiteTreeFor('SiteTree', isset($_REQUEST['ID']) ? $_REQUEST['ID'] : 0, null, array($this, 'includeInTree'));
+
+ // Trim off the outer tag
+ $tree = ereg_replace('^[ \t\r\n]*