1 <?php
2 3 4 5 6 7 8 9 10
11 class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionProvider {
12
13 static $url_segment = '';
14
15 static $url_rule = '/$Action/$ID/$OtherID';
16
17
18
19 static $url_priority = 40;
20
21 static = 'Pages';
22
23 static = 10;
24
25 static $tree_class = "SiteTree";
26
27 static $subitem_class = "Member";
28
29 static $allowed_actions = array(
30 'addmember',
31 'addpage',
32 'buildbrokenlinks',
33 'canceldraftchangesdialog',
34 'compareversions',
35 'createtranslation',
36 'delete',
37 'deletefromlive',
38 'deleteitems',
39 'DeleteItemsForm',
40 'dialog',
41 'duplicate',
42 'duplicatewithchildren',
43 'getpagecount',
44 'getversion',
45 'publishall',
46 'publishitems',
47 'PublishItemsForm',
48 'restore',
49 'revert',
50 'rollback',
51 'sidereport',
52 'submit',
53 'unpublish',
54 'versions',
55 'EditForm',
56 'AddPageOptionsForm',
57 'SiteTreeAsUL',
58 'getshowdeletedsubtree',
59 'getfilteredsubtree',
60 'batchactions'
61 );
62
63 static function T_SiteTreeFilterOptions(){
64 return array(
65 'Title' => _t('CMSMain.TITLEOPT', 'Title', 0, 'The dropdown title in CMSMain left SiteTreeFilterOptions'),
66 'MenuTitle' => _t('CMSMain.MENUTITLEOPT', 'Navigation Label', 0, 'The dropdown title in CMSMain left SiteTreeFilterOptions'),
67 'ClassName' => _t('CMSMain.PAGETYPEOPT', 'Page Type'),
68 'Status' => _t('CMSMain.STATUSOPT', 'Status', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"),
69 'MetaDescription' => _t('CMSMain.METADESCOPT', 'Description', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"),
70 'MetaKeywords' => _t('CMSMain.METAKEYWORDSOPT', 'Keywords', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions")
71 );
72 }
73
74 public function init() {
75 parent::init();
76
77
78
79
80
81 if($this->getRequest()->requestVar("Locale")) {
82 $this->Locale = $this->getRequest()->requestVar("Locale");
83 } elseif($this->getRequest()->requestVar("locale")) {
84 $this->Locale = $this->getRequest()->requestVar("locale");
85 } else {
86 $this->Locale = Translatable::default_locale();
87 }
88 Translatable::set_current_locale($this->Locale);
89
90
91
92 $langName = i18n::get_locale_name($this->Locale);
93 HtmlEditorConfig::get('cms')->setOption('spellchecker_languages', "+{$langName}={$this->Locale}");
94
95 Requirements::javascript(CMS_DIR . '/javascript/CMSMain.js');
96 Requirements::javascript(CMS_DIR . '/javascript/CMSMain_left.js');
97 Requirements::javascript(CMS_DIR . '/javascript/CMSMain_right.js');
98 }
99
100 101 102 103 104 105
106 function ShowSwitchView() {
107 return true;
108 }
109
110 111 112 113
114 function SwitchView($page = null) {
115 if(!$page) {
116 $page = $this->currentPage();
117 }
118
119 if($page) {
120 $nav = SilverStripeNavigator::get_for_record($page);
121 Requirements::customScript("window.name = windowName('cms');");
122 return $nav['items'];
123 }
124 }
125
126
127
128
129
130
131
132 133 134 135 136
137 public function Link($action = null) {
138 return Controller::join_links(
139 $this->stat('url_base', true),
140 $this->stat('url_segment', true),
141 '/',
142 "$action"
143 );
144 }
145
146 147 148
149 public function SiteTreeAsUL() {
150 $this->generateDataTreeHints();
151 $this->generateTreeStylingJS();
152
153
154 Versioned::prepopulate_versionnumber_cache("SiteTree", "Stage");
155 Versioned::prepopulate_versionnumber_cache("SiteTree", "Live");
156
157 return $this->getSiteTreeFor("SiteTree");
158 }
159
160 public function getCMSTreeTitle() {
161 return SiteConfig::current_site_config()->i18n_singular_name();
162 }
163
164 165 166 167 168
169 public function getfilteredsubtree() {
170
171 if (!isset($_REQUEST['filter'])) die('No filter passed');
172 if (!ClassInfo::exists($_REQUEST['filter'])) die ('That filter class does not exist');
173 if (!is_subclass_of($_REQUEST['filter'], 'CMSSiteTreeFilter')) die ('That is not a valid filter');
174
175
176 $filter = new $_REQUEST['filter']();
177 return $filter->getTree();
178 }
179
180 181 182
183 function SiteTreeFilters() {
184 $filters = ClassInfo::subclassesFor('CMSSiteTreeFilter');
185 array_shift($filters);
186 $doSet = new DataObjectSet();
187 $doSet->push(new ArrayData(array(
188 'ClassName' => 'all',
189 'Title' => _t('CMSSiteTreeFilter.ALL', 'All items')
190 )));
191 foreach($filters as $filter) {
192 if (call_user_func(array($filter, 'showInList'))) {
193 $doSet->push(new ArrayData(array(
194 'ClassName' => $filter,
195 'Title' => call_user_func(array($filter, 'title'))
196 )));
197 }
198 }
199 return $doSet;
200 }
201
202 203 204
205 public function SiteTreeFilterOptions() {
206 $filter_options = new DataObjectSet();
207 foreach(self::T_SiteTreeFilterOptions() as $key => $value) {
208 $record = array(
209 'Column' => $key,
210 'Title' => $value,
211 );
212 $filter_options->push(new ArrayData($record));
213 }
214 return $filter_options;
215 }
216 public function SiteTreeFilterDateField() {
217 $dateField = new DateField('SiteTreeFilterDate');
218 $dateField->setConfig('showcalendar', true);
219 return $dateField->Field();
220 }
221 public function SiteTreeFilterPageTypeField() {
222 $types = SiteTree::page_type_classes();
223 $source = array_combine($types, $types);
224 $source['All']= _t('CMSMain.AllClasses', 'All');
225 ksort($source);
226 $optionsetField = new DropdownField('ClassName', 'ClassName', $source, 'Any');
227 return $optionsetField->Field();
228 }
229
230 public function generateDataTreeHints() {
231 $classes = ClassInfo::subclassesFor( $this->stat('tree_class') );
232
233 $def['Root'] = array();
234
235 foreach($classes as $class) {
236 $obj = singleton($class);
237 if($obj instanceof HiddenClass) continue;
238
239 $allowedChildren = $obj->allowedChildren();
240 if($allowedChildren != "none") $def[$class]['allowedChildren'] = $allowedChildren;
241 $def[$class]['defaultChild'] = $obj->defaultChild();
242 $def[$class]['defaultParent'] = ($obj->defaultParent() && isset(SiteTree::get_by_link($obj->defaultParent())->ID)) ? SiteTree::get_by_link($obj->defaultParent())->ID : null;
243
244 if(is_array($allowedChildren)) foreach($allowedChildren as $allowedChild) {
245 $def[$allowedChild]['allowedParents'][] = $class;
246 }
247
248 if($obj->stat('can_be_root')) {
249 $def['Root']['allowedChildren'][] = $class;
250 }
251 }
252
253
254 Requirements::customScript("siteTreeHints = " . $this->jsDeclaration($def) . ";");
255 }
256
257 public function generateTreeStylingJS() {
258 $classes = ClassInfo::subclassesFor('SiteTree');
259 foreach($classes as $class) {
260 $obj = singleton($class);
261 if($obj instanceof HiddenClass) continue;
262 if($icon = $obj->stat('icon')) $iconInfo[$class] = $icon;
263 }
264 $iconInfo['BrokenLink'] = 'cms/images/treeicons/brokenlink';
265
266
267 $js = "var _TREE_ICONS = [];\n";
268
269
270 foreach($iconInfo as $class => $icon) {
271
272
273 $option = null;
274 if(is_array($icon)) list($icon, $option) = $icon;
275
276 $fileImage = ($option == "folder") ? $icon . '-closedfolder.gif' : $icon . '-file.gif';
277 $openFolderImage = $icon . '-openfolder.gif';
278 if(!Director::fileExists($openFolderImage) || $option == "file") $openFolderImage = $fileImage;
279 $closedFolderImage = $icon . '-closedfolder.gif';
280 if(!Director::fileExists($closedFolderImage) || $option == "file") $closedFolderImage = $fileImage;
281
282 $js .= <<<JS
283 _TREE_ICONS['$class'] = {
284 fileIcon: '$fileImage',
285 openFolderIcon: '$openFolderImage',
286 closedFolderIcon: '$closedFolderImage'
287 };
288
289 JS;
290 }
291
292 Requirements::customScript($js);
293 }
294
295 296 297
298 protected function jsDeclaration($array) {
299 $parts = array();
300 if(is_array($array)) {
301 $object = false;
302 foreach(array_keys($array) as $key) {
303 if(!is_numeric($key)) {
304 $object = true;
305 break;
306 }
307 }
308
309 if($object) {
310 foreach($array as $k => $v) {
311 $parts[] = "$k : " . $this->jsDeclaration($v);
312 }
313 return " {\n " . implode(", \n", $parts) . " }\n";
314 } else {
315 foreach($array as $part) $parts[] = $this->jsDeclaration($part);
316 return " [ " . implode(", ", $parts) . " ]\n";
317 }
318 } else {
319 return "'" . addslashes($array) . "'";
320 }
321 }
322
323 324 325 326 327 328
329 public function PageTypes() {
330 $classes = SiteTree::page_type_classes();
331
332 $result = new DataObjectSet();
333
334 foreach($classes as $class) {
335 $instance = singleton($class);
336
337 if($instance instanceof HiddenClass) continue;
338
339 if(!$instance->canCreate()) continue;
340
341
342 if($instance->stat('need_permission') && !$this->can(singleton($class)->stat('need_permission'))) continue;
343
344 $addAction = $instance->i18n_singular_name();
345
346
347
348
349
350 if (Director::isDev()) {
351 $addAction .= " ({$class})";
352 }
353
354 $result->push(new ArrayData(array(
355 'ClassName' => $class,
356 'AddAction' => $addAction,
357 'Sort' => ($class == 'DocPage') ? '0' : $addAction,
358 )));
359 }
360
361 $result->sort('Sort');
362
363 return $result;
364 }
365
366 367 368 369 370 371 372
373 function save_siteconfig($data, $form) {
374 $siteConfig = SiteConfig::current_site_config();
375 $form->saveInto($siteConfig);
376 $siteConfig->write();
377 FormResponse::status_message('Saved site configuration', "good");
378 FormResponse::add("$('Form_EditForm').resetElements();");
379
380 return FormResponse::respond();
381 }
382 383 384
385 public function getRecord($id, $className = NULL) {
386
387 $treeClass = $this->stat('tree_class');
388
389 if($id && is_numeric($id)) {
390 $record = DataObject::get_one( $treeClass, "\"$treeClass\".\"ID\" = $id");
391
392
393 if(!$record) {
394
395 Versioned::reading_stage('Live');
396 singleton($treeClass)->flushCache();
397
398 $record = DataObject::get_one( $treeClass, "\"$treeClass\".\"ID\" = $id");
399 if($record) Versioned::set_reading_mode('');
400 }
401
402
403 if(!$record) {
404 $record = Versioned::get_latest_version($treeClass, $id);
405 }
406
407
408 409 410 411 412 413
414 415 416
417
418 return $record;
419
420 } else if(substr($id,0,3) == 'new') {
421 return $this->getNewItem($id);
422 }
423 }
424
425 public function getEditForm($id) {
426 $record = $this->getRecord($id);
427
428 if($record) {
429 if($record->IsDeletedFromStage) $record->Status = _t('CMSMain.REMOVEDFD',"Removed from the draft site");
430
431 $fields = $record->getCMSFields();
432 if ($fields == null) {
433 user_error("getCMSFields returned null on a '".get_class($record)."' object - it should return a FieldSet object. Perhaps you forgot to put a return statement at the end of your method?", E_USER_ERROR);
434 }
435 $fields->push($idField = new HiddenField("ID"));
436 $fields->push($liveURLField = new HiddenField("LiveURLSegment"));
437 $fields->push($stageURLField = new HiddenField("StageURLSegment"));
438
439
440 $fields->push(new HiddenField('Sort','', $record->Sort ));
441
442 $idField->setValue($id);
443
444 if($record->ID && is_numeric( $record->ID ) ) {
445 $liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree\".\"ID\" = $record->ID");
446 if($liveRecord) $liveURLField->setValue($liveRecord->AbsoluteLink());
447 }
448
449 if(!$record->IsDeletedFromStage) {
450 $stageURLField->setValue($record->AbsoluteLink());
451 }
452
453
454 if($record->hasMethod('getAllCMSActions')) {
455 $actions = $record->getAllCMSActions();
456 } else {
457 $actions = $record->getCMSActions();
458 }
459
460
461
462
463
464
465
466
467
468 if($record->hasMethod('getCMSValidator')) {
469 $validator = $record->getCMSValidator();
470 } else {
471 $validator = new RequiredFields();
472 }
473
474
475
476
477 $validator->setJavascriptValidationHandler('prototype');
478
479 $form = new Form($this, "EditForm", $fields, $actions, $validator);
480 $form->loadDataFrom($record);
481 $form->disableDefaultAction();
482
483 if(!$record->canEdit() || $record->IsDeletedFromStage) {
484 $readonlyFields = $form->Fields()->makeReadonly();
485 $form->setFields($readonlyFields);
486 }
487
488 $this->extend('updateEditForm', $form);
489
490 return $form;
491 } if ($id == 0 || $id == 'root') {
492 return $this->RootForm();
493 } else if($id) {
494 return new Form($this, "EditForm", new FieldSet(
495 new LabelField('PageDoesntExistLabel',_t('CMSMain.PAGENOTEXISTS',"This page doesn't exist"))), new FieldSet());
496
497 }
498 }
499
500 501 502
503 function RootForm() {
504 $siteConfig = SiteConfig::current_site_config();
505 $fields = $siteConfig->getCMSFields();
506 if(SS_Object::has_extension('SiteConfig',"Translatable")){
507 $fields->push(new HiddenField('Locale','', $siteConfig->Locale ));
508 }
509 $form = new Form($this, "EditForm", $fields, $siteConfig->getCMSActions());
510 $form->loadDataFrom($siteConfig);
511
512 $this->extend('updateEditForm', $form);
513
514 return $form;
515 }
516
517
518
519
520
521 public function addpage() {
522
523 $className = 'DocPage';
524 if(isset($_REQUEST['PageType']) && $_REQUEST['PageType']!='' && class_exists($_REQUEST['PageType'])){
525 $className = $_REQUEST['PageType'];
526 }
527
528
529 $parent = isset($_REQUEST['ParentID']) ? $_REQUEST['ParentID'] : 0;
530 $suffix = isset($_REQUEST['Suffix']) ? "-" . $_REQUEST['Suffix'] : null;
531
532 if(!$parent && isset($_REQUEST['Parent'])) {
533 $page = SiteTree::get_by_link($_REQUEST['Parent']);
534 if($page) $parent = $page->ID;
535 }
536
537 if(is_numeric($parent)) $parentObj = DataObject::get_by_id("SiteTree", $parent);
538 if(!$parentObj || !$parentObj->ID) $parent = 0;
539
540 if($parentObj){
541 if(!$parentObj->canAddChildren()) return Security::permissionFailure($this);
542 if(!singleton($className)->canCreate()) return Security::permissionFailure($this);
543 }else{
544 if(!SiteConfig::current_site_config()->canCreateTopLevel())
545 return Security::permissionFailure($this);
546 }
547
548 $p = $this->getNewItem("new-$className-$parent".$suffix, false);
549 $p->Locale = $_REQUEST['Locale'];
550 $p->write();
551
552 return $this->returnItemToUser($p);
553 }
554
555 556 557
558 public function getNewItem($id, $setID = true) {
559 list($dummy, $className, $parentID, $suffix) = array_pad(explode('-',$id),4,null);
560
561 $newItem = new $className();
562
563 if( !$suffix ) {
564 $sessionTag = "NewItems." . $parentID . "." . $className;
565 if(Session::get($sessionTag)) {
566 $suffix = '-' . Session::get($sessionTag);
567 Session::set($sessionTag, Session::get($sessionTag) + 1);
568 }
569 else
570 Session::set($sessionTag, 1);
571
572 $id = $id . $suffix;
573 }
574
575
576 if (!$newItem->Title) $newItem->Title = singleton($className)->i18n_singular_name();
577 if (!$newItem->URLSegment) $newItem->URLSegment = "new-" . strtolower($className);
578 $newItem->ClassName = $className;
579 $newItem->ParentID = $parentID;
580
581
582
583 if($newItem->castingHelper('Sort')) {
584 $newItem->Sort = DB::query("SELECT MAX(\"Sort\") FROM \"SiteTree\" WHERE \"ParentID\" = '" . Convert::raw2sql($parentID) . "'")->value() + 1;
585 }
586
587 if($setID) $newItem->ID = $id;
588
589
590 $this->extend('augmentNewSiteTreeItem', $newItem);
591
592 return $newItem;
593 }
594
595 596 597 598 599
600 public function deletefromlive($urlParams, $form) {
601 $id = $_REQUEST['ID'];
602 Versioned::reading_stage('Live');
603 $record = DataObject::get_by_id("SiteTree", $id);
604 if($record && !($record->canDelete() && $record->canDeleteFromLive())) return Security::permissionFailure($this);
605
606 $descRemoved = '';
607 $descendantsRemoved = 0;
608
609
610 if($record) {
611 $descendantIDs = $record->getDescendantIDList();
612
613
614 $descendantsRemoved = 0;
615 foreach( $descendantIDs as $descID )
616 if( $descendant = DataObject::get_by_id('SiteTree', $descID) ) {
617 $descendant->doDeleteFromLive();
618 $descendantsRemoved++;
619 }
620
621
622 $record->doDeleteFromLive();
623 }
624
625 Versioned::reading_stage('Stage');
626
627 if(isset($descendantsRemoved)) {
628 $descRemoved = " and $descendantsRemoved descendants";
629 $descRemoved = sprintf(' '._t('CMSMain.DESCREMOVED', 'and %s descendants'), $descendantsRemoved);
630 } else {
631 $descRemoved = '';
632 }
633
634 FormResponse::add($this->deleteTreeNodeJS($record));
635 FormResponse::status_message(sprintf(_t('CMSMain.REMOVED', 'Deleted \'%s\'%s from live site'), $record->Title, $descRemoved), 'good');
636
637 return FormResponse::respond();
638 }
639
640 641 642
643 public function performPublish($record) {
644 if($record && !$record->canPublish()) return Security::permissionFailure($this);
645
646 $record->doPublish();
647 }
648
649 650 651 652 653 654 655
656 public function revert($urlParams, $form) {
657 $id = (int)$_REQUEST['ID'];
658 $record = Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree_Live\".\"ID\" = '{$id}'");
659
660
661
662 if(isset($record) && $record && !$record->canEdit()) return Security::permissionFailure($this);
663
664 $record->doRevertToLive();
665
666 $title = Convert::raw2js($record->Title);
667 FormResponse::get_page($id);
668 FormResponse::add("$('sitetree').setNodeTitle($id, '$title');");
669 FormResponse::status_message(sprintf(_t('CMSMain.RESTORED',"Restored '%s' successfully",PR_MEDIUM,'Param %s is a title'),$title),'good');
670
671 return FormResponse::respond();
672 }
673
674 675 676 677
678 public function delete($data, $form) {
679 $record = DataObject::get_one(
680 "SiteTree",
681 sprintf("\"SiteTree\".\"ID\" = %d", Convert::raw2sql($data['ID']))
682 );
683 if($record && !$record->canDelete()) return Security::permissionFailure();
684
685
686 $recordID = $record->ID;
687 $record->delete();
688
689 if(Director::is_ajax()) {
690
691
692 $liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree_Live\".\"ID\" = $recordID");
693
694 if($liveRecord) {
695
696 FormResponse::get_page($recordID);
697 return $this->tellBrowserAboutPublicationChange($liveRecord, sprintf(_t('CMSMain.REMOVEDPAGEFROMDRAFT',"Removed '%s' from the draft site"),$record->Title));
698 } else {
699 FormResponse::add($this->deleteTreeNodeJS($record));
700 FormResponse::status_message(sprintf(_t('CMSMain.REMOVEDPAGEFROMDRAFT',"Removed '%s' from the draft site"),$record->Title), 'good');
701 return FormResponse::respond();
702 }
703 } else {
704 Director::redirectBack();
705 }
706 }
707
708 function SideReports() {
709 return SS_Report::get_reports('SideReport');
710 }
711
712 713 714
715 function ReportSelector() {
716
717 foreach($this->SideReports() as $report) {
718 if($report->canView()) {
719 $options[$report->group()][$report->sort()][$report->ID()] = $report->title();
720 }
721 }
722
723 $finalOptions = array();
724 foreach($options as $group => $weights) {
725 ksort($weights);
726 foreach($weights as $weight => $reports) {
727 foreach($reports as $class => $report) {
728 $finalOptions[$group][$class] = $report;
729 }
730 }
731 }
732
733 return new GroupedDropdownField("ReportSelector", _t('CMSMain.REPORT', 'Report'),$finalOptions);
734 }
735
736 737 738 739 740
741 function ReportFormParameters() {
742 $forms = array();
743 foreach($this->SideReports() as $report) {
744 if ($report->canView()) {
745 if ($fieldset = $report->parameterFields()) {
746 $formHtml = '';
747 foreach($fieldset as $field) {
748 $formHtml .= $field->FieldHolder();
749 }
750 $forms[$report->ID()] = $formHtml;
751 }
752 }
753 }
754 $pageHtml = '';
755 foreach($forms as $class => $html) {
756 $pageHtml .= "<div id=\"SideReportForm_$class\" style=\"display:none\">$html</div>\n\n";
757 }
758 return new LiteralField("ReportFormParameters", '<div id="SideReportForms" style="display:none">'.$pageHtml.'</div>');
759 }
760
761 762 763
764 function sidereport() {
765 $reportClass = $this->urlParams['ID'];
766 $reports = $this->SideReports();
767 if(isset($reports[$reportClass])) {
768 $report = $reports[$reportClass];
769 if($report) {
770 $view = new SideReportView($this, $report);
771 $view->setParameters($this->request->requestVars());
772 return $view->forTemplate();
773 } else {
774 return false;
775 }
776 }
777 }
778
779
780 781 782
783 function versions() {
784 $pageID = $this->urlParams['ID'];
785 $page = $this->getRecord($pageID);
786 if($page) {
787 $versions = $page->allVersions($_REQUEST['unpublished'] ? "" : "\"SiteTree\".\"WasPublished\" = 1");
788 return array(
789 'Versions' => $versions,
790 );
791 } else {
792 return sprintf(_t('CMSMain.VERSIONSNOPAGE',"Can't find page #%d",PR_LOW),$pageID);
793 }
794 }
795
796 797 798
799 function rollback() {
800 if(isset($_REQUEST['Version']) && (bool)$_REQUEST['Version']) {
801 $this->extend('onBeforeRollback', $_REQUEST['ID']);
802 $record = $this->performRollback($_REQUEST['ID'], $_REQUEST['Version']);
803 echo sprintf(_t('CMSMain.ROLLEDBACKVERSION',"Rolled back to version #%d. New version number is #%d"),$_REQUEST['Version'],$record->Version);
804 } else {
805 $record = $this->performRollback($_REQUEST['ID'], "Live");
806 echo sprintf(_t('CMSMain.ROLLEDBACKPUB',"Rolled back to published version. New version number is #%d"),$record->Version);
807 }
808 }
809
810 function unpublish() {
811 $SQL_id = Convert::raw2sql($_REQUEST['ID']);
812
813 $page = DataObject::get_by_id("SiteTree", $SQL_id);
814
815 if($page && !$page->canDeleteFromLive()) return Security::permissionFailure($this);
816
817 $page->doUnpublish();
818
819 return $this->tellBrowserAboutPublicationChange($page, sprintf(_t('CMSMain.REMOVEDPAGE',"Removed '%s' from the published site"),$page->Title));
820 }
821
822 823 824 825 826 827 828
829 function tellBrowserAboutPublicationChange($page, $statusMessage) {
830 $JS_title = Convert::raw2js($page->TreeTitle());
831
832 $JS_stageURL = $page->IsDeletedFromStage ? '' : Convert::raw2js($page->AbsoluteLink());
833 $liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree\".\"ID\" = $page->ID");
834
835 $JS_liveURL = $liveRecord ? Convert::raw2js($liveRecord->AbsoluteLink()) : '';
836
837 FormResponse::add($this->getActionUpdateJS($page));
838 FormResponse::update_status($page->Status);
839
840 if($JS_stageURL || $JS_liveURL) {
841 FormResponse::add("\$('sitetree').setNodeTitle($page->ID, '$JS_title');");
842 } else {
843 FormResponse::add("var node = $('sitetree').getTreeNodeByIdx('$page->ID');");
844 FormResponse::add("if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node);");
845 FormResponse::add("$('Form_EditForm').reloadIfSetTo($page->ID);");
846 }
847
848 if($statusMessage) FormResponse::status_message($statusMessage, 'good');
849 FormResponse::add("$('Form_EditForm').elements.StageURLSegment.value = '$JS_stageURL';");
850 FormResponse::add("$('Form_EditForm').elements.LiveURLSegment.value = '$JS_liveURL';");
851 FormResponse::add("$('Form_EditForm').notify('PagePublished', $('Form_EditForm').elements.ID.value);");
852
853 return FormResponse::respond();
854 }
855
856 function performRollback($id, $version) {
857 $record = DataObject::get_by_id($this->stat('tree_class'), $id);
858 if($record && !$record->canEdit()) return Security::permissionFailure($this);
859
860 $record->doRollbackTo($version);
861 return $record;
862 }
863
864 function getversion() {
865 $id = $this->urlParams['ID'];
866 $version = str_replace('&ajax=1','',$this->urlParams['OtherID']);
867 $record = Versioned::get_version("SiteTree", $id, $version);
868
869 if($record) {
870 if($record && !$record->canView()) return Security::permissionFailure($this);
871 $fields = $record->getCMSFields();
872 $fields->removeByName("Status");
873
874 $fields->push(new HiddenField("ID"));
875 $fields->push(new HiddenField("Version"));
876
877 $versionAuthor = DataObject::get_by_id('Member', $record->AuthorID);
878 if(!$versionAuthor) $versionAuthor = new ArrayData(array('Title' => 'Unknown author'));
879 $fields->insertBefore(
880 new LiteralField(
881 'YouAreViewingHeader',
882 '<p class="message notice">' .
883 sprintf(
884 _t(
885 'CMSMain.VIEWING',
886 "You are viewing version #%s, created %s by %s",
887 PR_MEDIUM,
888 'Version number is a linked string, created is a relative time (e.g. 2 days ago), by a specific author'
889 ),
890 "<a href=\"admin/getversion/$record->ID/$version\" title=\"" . ($versionAuthor ? $versionAuthor->Title : '') . "\">$version</a>",
891 $record->obj('LastEdited')->Ago(),
892 ($versionAuthor ? $versionAuthor->Title : '')
893 ) .
894 '</p>'
895 ),
896 'Root'
897 );
898
899 $actions = new FieldSet(
900 new FormAction("email", _t('CMSMain.EMAIL',"Email")),
901 new FormAction("rollback", _t('CMSMain.ROLLBACK',"Roll back to this version"))
902 );
903
904
905 $archiveURL = Director::absoluteBaseURL() . $record->URLSegment . '?archiveDate=' . $record->obj('LastEdited')->URLDatetime();
906
907
908 SSViewer::set_source_file_comments(false);
909
910 $archiveEmailMessage = urlencode( $this->customise( array( 'ArchiveDate' => $record->obj('LastEdited'), 'ArchiveURL' => $archiveURL ) )->renderWith( 'ViewArchivedEmail' ) );
911 $archiveEmailMessage = preg_replace( '/\+/', '%20', $archiveEmailMessage );
912
913 $fields->push( new HiddenField( 'ArchiveEmailMessage', '', $archiveEmailMessage ) );
914 $fields->push( new HiddenField( 'ArchiveEmailSubject', '', preg_replace( '/\+/', '%20', urlencode( 'Archived version of ' . $record->Title ) ) ) );
915 $fields->push( new HiddenField( 'ArchiveURL', '', $archiveURL ) );
916
917 $form = new Form($this, "EditForm", $fields, $actions);
918 $form->loadDataFrom($record);
919 $form->loadDataFrom(array(
920 "ID" => $id,
921 "Version" => $version,
922 ));
923
924
925 $readonlyFields = $form->Fields()->makeReadonly();
926 $form->setFields($readonlyFields);
927
928 $templateData = $this->customise(array(
929 "EditForm" => $form
930 ));
931
932 SSViewer::setOption('rewriteHashlinks', false);
933
934 if(Director::is_ajax()) {
935 $result = $templateData->renderWith($this->class . '_right');
936 $parts = preg_split('!</?form[^>]*>!', $result);
937 $content = $parts[sizeof($parts)-2];
938 if($this->ShowSwitchView()) {
939 $content .= '<div id="AjaxSwitchView">' . $this->SwitchView($record) . '</div>';
940 }
941 return $content;
942 } else {
943 return $templateData->renderWith('LeftAndMain');
944 }
945 }
946 }
947
948 function compareversions() {
949 $id = (int)$this->urlParams['ID'];
950 $version1 = (int)$_REQUEST['From'];
951 $version2 = (int)$_REQUEST['To'];
952
953 if( $version1 > $version2 ) {
954 $toVersion = $version1;
955 $fromVersion = $version2;
956 } else {
957 $toVersion = $version2;
958 $fromVersion = $version1;
959 }
960
961 $page = DataObject::get_by_id("SiteTree", $id);
962 if($page && !$page->canView()) return Security::permissionFailure($this);
963
964 $record = $page->compareVersions($fromVersion, $toVersion);
965
966 $fromVersionRecord = Versioned::get_version('SiteTree', $id, $fromVersion);
967 $toVersionRecord = Versioned::get_version('SiteTree', $id, $toVersion);
968 if(!$fromVersionRecord) user_error("Can't find version $fromVersion of page $id", E_USER_ERROR);
969 if(!$toVersionRecord) user_error("Can't find version $toVersion of page $id", E_USER_ERROR);
970
971 if($record) {
972 $fromDateNice = $fromVersionRecord->obj('LastEdited')->Ago();
973 $toDateNice = $toVersionRecord->obj('LastEdited')->Ago();
974 $fromAuthor = DataObject::get_by_id('Member', $fromVersionRecord->AuthorID);
975 if(!$fromAuthor) $fromAuthor = new ArrayData(array('Title' => 'Unknown author'));
976 $toAuthor = DataObject::get_by_id('Member', $toVersionRecord->AuthorID);
977 if(!$toAuthor) $toAuthor = new ArrayData(array('Title' => 'Unknown author'));
978
979 $fields = $record->getCMSFields();
980 $fields->push(new HiddenField("ID"));
981 $fields->push(new HiddenField("Version"));
982 $fields->insertBefore(
983 new LiteralField(
984 'YouAreComparingHeader',
985 '<p class="message notice">' .
986 sprintf(
987 _t('CMSMain.COMPARINGV',"Comparing versions %s and %s"),
988 "<a href=\"admin/getversion/$id/$fromVersionRecord->Version\" title=\"$fromAuthor->Title\">$fromVersionRecord->Version</a> <small>($fromDateNice)</small>",
989 "<a href=\"admin/getversion/$id/$toVersionRecord->Version\" title=\"$toAuthor->Title\">$toVersionRecord->Version</a> <small>($toDateNice)</small>"
990 ) .
991 '</p>'
992 ),
993 "Root"
994 );
995
996 $actions = new FieldSet();
997
998 $form = new Form($this, "EditForm", $fields, $actions);
999 $form->loadDataFrom($record);
1000 $form->loadDataFrom(array(
1001 "ID" => $id,
1002 "Version" => $fromVersion,
1003 ));
1004
1005
1006 $readonlyFields = $form->Fields()->makeReadonly();
1007 $form->setFields($readonlyFields);
1008
1009 foreach($form->Fields()->dataFields() as $field) {
1010 $field->dontEscape = true;
1011 }
1012
1013 return $this->sendFormToBrowser(array(
1014 "EditForm" => $form
1015 ));
1016 }
1017 }
1018
1019 function sendFormToBrowser($templateData) {
1020 if(Director::is_ajax()) {
1021 SSViewer::setOption('rewriteHashlinks', false);
1022 $result = $this->customise($templateData)->renderWith($this->class . '_right');
1023 $parts = preg_split('!</?form[^>]*>!', $result);
1024 return $parts[sizeof($parts)-2];
1025 } else {
1026 return array(
1027 "Right" => $this->customise($templateData)->renderWith($this->class . '_right'),
1028 );
1029 }
1030 }
1031
1032 function dialog() {
1033 Requirements::clear();
1034
1035 $buttons = new DataObjectSet;
1036 if($_REQUEST['Buttons']) foreach($_REQUEST['Buttons'] as $button) {
1037 list($name, $title) = explode(',',$button,2);
1038 $buttons->push(new ArrayData(array(
1039 "Name" => $name,
1040 "Title" => $title,
1041 )));
1042 }
1043
1044 return array(
1045 "Message" => htmlentities($_REQUEST['Message']),
1046 "Buttons" => $buttons,
1047 "Modal" => $_REQUEST['Modal'] ? true : false,
1048 );
1049 }
1050
1051 function canceldraftchangesdialog() {
1052 Requirements::clear();
1053 Requirements::css(CMS_DIR . 'css/dialog.css');
1054 Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/prototype/prototype.js');
1055 Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/behaviour/behaviour.js');
1056 Requirements::javascript(SAPPHIRE_DIR . '/javascript/prototype_improvements.js');
1057 Requirements::javascript(CMS_DIR . '/javascript/dialog.js');
1058
1059 $message = _t('CMSMain.COPYPUBTOSTAGE',"Do you really want to copy the published content to the stage site?");
1060 $buttons = "<button name=\"OK\">" . _t('CMSMain.OK','OK') ."</button><button name=\"Cancel\">" . _t('CMSMain.CANCEL',"Cancel") . "</button>";
1061
1062 return $this->customise( array(
1063 'Message' => $message,
1064 'Buttons' => $buttons,
1065 'DialogType' => 'alert'
1066 ))->renderWith('Dialog');
1067 }
1068
1069 1070 1071
1072 function batchactions() {
1073 return new CMSBatchActionHandler($this, 'batchactions');
1074 }
1075
1076 1077 1078
1079 public function PublishItemsForm() {
1080 $form = new Form(
1081 $this,
1082 'PublishItemsForm',
1083 new FieldSet(
1084 new HiddenField('csvIDs'),
1085 new CheckboxField('ShowDrafts', _t('CMSMain_left.ss.SHOWONLYCHANGED','Show only changed pages'))
1086 ),
1087 new FieldSet(
1088 new FormAction('publishitems', _t('CMSMain_left.ss.PUBLISHCONFIRM','Publish the selected pages'))
1089 )
1090 );
1091 $form->addExtraClass('actionparams');
1092 return $form;
1093 }
1094
1095 function BatchActionParameters() {
1096 $batchActions = CMSBatchActionHandler::$batch_actions;
1097
1098 $forms = array();
1099 foreach($batchActions as $urlSegment => $batchAction) {
1100 $SNG_action = singleton($batchAction);
1101 if ($SNG_action->canView() && $fieldset = $SNG_action->getParameterFields()) {
1102 $formHtml = '';
1103 foreach($fieldset as $field) {
1104 $formHtml .= $field->Field();
1105 }
1106 $forms[$urlSegment] = $formHtml;
1107 }
1108 }
1109 $pageHtml = '';
1110 foreach($forms as $urlSegment => $html) {
1111 $pageHtml .= "<div class=\"params\" id=\"BatchActionParameters_$urlSegment\">$html</div>\n\n";
1112 }
1113 return new LiteralField("BatchActionParameters", '<div id="BatchActionParameters" style="display:none">'.$pageHtml.'</div>');
1114 }
1115 1116 1117
1118 function BatchActionList() {
1119 return $this->batchactions()->batchActionList();
1120 }
1121
1122 1123 1124
1125 function DeleteItemsForm() {
1126 $form = new Form(
1127 $this,
1128 'DeleteItemsForm',
1129 new FieldSet(
1130 new LiteralField('SelectedPagesNote',
1131 sprintf('<p>%s</p>', _t('CMSMain_left.ss.SELECTPAGESACTIONS','Select the pages that you want to change & then click an action:'))
1132 ),
1133 new HiddenField('csvIDs')
1134 ),
1135 new FieldSet(
1136 new FormAction('deleteitems', _t('CMSMain_left.ss.DELETECONFIRM','Delete the selected pages'))
1137 )
1138 );
1139 $form->addExtraClass('actionparams');
1140 return $form;
1141 }
1142
1143 function buildbrokenlinks() {
1144 if($this->urlParams['ID']) {
1145 $newPageSet[] = DataObject::get_by_id("Page", $this->urlParams['ID']);
1146 } else {
1147 $pages = DataObject::get("Page");
1148 foreach($pages as $page) $newPageSet[] = $page;
1149 $pages = null;
1150 }
1151
1152 $content = new HtmlEditorField('Content');
1153 $download = new HtmlEditorField('Download');
1154
1155 foreach($newPageSet as $i => $page) {
1156 $page->HasBrokenLink = 0;
1157 $page->HasBrokenFile = 0;
1158
1159 $lastUsage = (memory_get_usage() - $lastPoint);
1160 $lastPoint = memory_get_usage();
1161 $content->setValue($page->Content);
1162 $content->saveInto($page);
1163
1164 $download->setValue($page->Download);
1165 $download->saveInto($page);
1166
1167 echo "<li>$page->Title (link:$page->HasBrokenLink, file:$page->HasBrokenFile)";
1168
1169 $page->writeWithoutVersion();
1170 $page->destroy();
1171 $newPageSet[$i] = null;
1172 }
1173 }
1174
1175 function AddPageOptionsForm() {
1176 $pageTypes = array();
1177
1178 foreach( $this->PageTypes() as $arrayData ) {
1179 $pageTypes[$arrayData->getField('ClassName')] = $arrayData->getField('AddAction');
1180 }
1181
1182 $fields = new FieldSet(
1183 new HiddenField("ParentID"),
1184 new HiddenField("Locale", 'Locale', Translatable::get_current_locale()),
1185 new DropdownField("PageType", "", $pageTypes, 'Page')
1186 );
1187
1188 $this->extend('updatePageOptions', $fields);
1189
1190 $actions = new FieldSet(
1191 new FormAction("addpage", _t('CMSMain.GO',"Go"))
1192 );
1193
1194 return new Form($this, "AddPageOptionsForm", $fields, $actions);
1195 }
1196
1197 1198 1199
1200 function getpagecount() {
1201 ini_set('max_execution_time', 0);
1202 $excludePages = preg_split("! *, *!", $_GET['exclude']);
1203
1204 $pages = DataObject::get("SiteTree", "\"ParentID\" = 0");
1205 foreach($pages as $page) $pageArr[] = $page;
1206
1207 while(list($i,$page) = each($pageArr)) {
1208 if(!in_array($page->URLSegment, $excludePages)) {
1209 if($children = $page->AllChildren()) {
1210 foreach($children as $child) $pageArr[] = $child;
1211 }
1212
1213
1214 if(!$_GET['onlywithcontent'] || strlen(Convert::xml2raw($page->Content)) > 100) {
1215 echo "<li>" . $page->Breadcrumbs(null, true) . "</li>";
1216 $count++;
1217 } else {
1218 echo "<li style=\"color: #777\">" . $page->Breadcrumbs(null, true) . " - " . _t('CMSMain.NOCONTENT',"no content") . "</li>";
1219 }
1220
1221 }
1222 }
1223
1224 echo '<p>' . _t('CMSMain.TOTALPAGES',"Total pages: ") . "$count</p>";
1225 }
1226
1227 function publishall() {
1228 ini_set("memory_limit", -1);
1229 ini_set('max_execution_time', 0);
1230
1231 $response = "";
1232
1233 if(isset($this->requestParams['confirm'])) {
1234 $start = 0;
1235 $pages = DataObject::get("SiteTree", "", "", "", "$start,30");
1236 $count = 0;
1237 if($pages){
1238 while(true) {
1239 foreach($pages as $page) {
1240 if($page && !$page->canPublish()) return Security::permissionFailure($this);
1241
1242 $page->doPublish();
1243 $page->destroy();
1244 unset($page);
1245 $count++;
1246 $response .= "<li>$count</li>";
1247 }
1248 if($pages->Count() > 29) {
1249 $start += 30;
1250 $pages = DataObject::get("SiteTree", "", "", "", "$start,30");
1251 } else {
1252 break;
1253 }
1254 }
1255 }
1256 $response .= sprintf(_t('CMSMain.PUBPAGES',"Done: Published %d pages"), $count);
1257
1258 } else {
1259 $response .= '<h1>' . _t('CMSMain.PUBALLFUN','"Publish All" functionality') . '</h1>
1260 <p>' . _t('CMSMain.PUBALLFUN2', 'Pressing this button will do the equivalent of going to every page and pressing "publish". It\'s
1261 intended to be used after there have been massive edits of the content, such as when the site was
1262 first built.') . '</p>
1263 <form method="post" action="publishall">
1264 <input type="submit" name="confirm" value="'
1265 . _t('CMSMain.PUBALLCONFIRM',"Please publish every page in the site, copying content stage to live",PR_LOW,'Confirmation button') .'" />
1266 </form>';
1267 }
1268
1269 return $response;
1270 }
1271
1272 1273 1274
1275 function restore() {
1276 if(($id = $_REQUEST['ID']) && is_numeric($id)) {
1277 $restoredPage = Versioned::get_latest_version("SiteTree", $id);
1278 if($restoredPage) {
1279 $restoredPage = $restoredPage->doRestoreToStage();
1280
1281 FormResponse::get_page($id);
1282 $title = Convert::raw2js($restoredPage->TreeTitle());
1283 FormResponse::add("$('sitetree').setNodeTitle($id, '$title');");
1284 FormResponse::status_message(sprintf(_t('CMSMain.RESTORED',"Restored '%s' successfully",PR_MEDIUM,'Param %s is a title'),$title),'good');
1285 return FormResponse::respond();
1286
1287 } else {
1288 return new SS_HTTPResponse("SiteTree #$id not found", 400);
1289 }
1290 } else {
1291 return new SS_HTTPResponse("Please pass an ID in the form content", 400);
1292 }
1293 }
1294
1295 function duplicate() {
1296 if(($id = $this->urlParams['ID']) && is_numeric($id)) {
1297 $page = DataObject::get_by_id("SiteTree", $id);
1298 if($page && (!$page->canEdit() || !$page->canCreate())) {
1299 return Security::permissionFailure($this);
1300 }
1301
1302 $newPage = $page->duplicate();
1303
1304
1305 if($_GET['parentID'] && is_numeric($_GET['parentID'])) {
1306 $newPage->ParentID = $_GET['parentID'];
1307 $newPage->write();
1308 }
1309
1310 return $this->returnItemToUser($newPage);
1311 } else {
1312 user_error("CMSMain::duplicate() Bad ID: '$id'", E_USER_WARNING);
1313 }
1314 }
1315
1316 function duplicatewithchildren() {
1317 if(($id = $this->urlParams['ID']) && is_numeric($id)) {
1318 $page = DataObject::get_by_id("SiteTree", $id);
1319 if($page && (!$page->canEdit() || !$page->canCreate())) {
1320 return Security::permissionFailure($this);
1321 }
1322
1323 $newPage = $page->duplicateWithChildren();
1324
1325 return $this->returnItemToUser($newPage);
1326 } else {
1327 user_error("CMSMain::duplicate() Bad ID: '$id'", E_USER_WARNING);
1328 }
1329 }
1330
1331
1332
1333 1334 1335
1336 function createtranslation () {
1337 $langCode = Convert::raw2sql($_REQUEST['newlang']);
1338 $originalLangID = (int)$_REQUEST['ID'];
1339
1340 $record = $this->getRecord($originalLangID);
1341
1342 $this->Locale = $langCode;
1343 Translatable::set_current_locale($langCode);
1344
1345
1346
1347
1348
1349
1350 $translatedRecord = $record->createTranslation($langCode);
1351
1352 $url = sprintf(
1353 "%s/%d/?locale=%s",
1354 $this->Link('show'),
1355 $translatedRecord->ID,
1356 $langCode
1357 );
1358 FormResponse::add(sprintf('window.location.href = "%s";', $url));
1359 return FormResponse::respond();
1360 }
1361
1362 1363 1364 1365
1366 function providePermissions() {
1367 $classes = ClassInfo::subclassesFor('LeftAndMain');
1368
1369 foreach($classes as $i => $class) {
1370 $title = _t("{$class}.MENUTITLE", LeftAndMain::menu_title_for_class($class));
1371 $perms["CMS_ACCESS_" . $class] = array(
1372 'name' => sprintf(_t(
1373 'CMSMain.ACCESS',
1374 "Access to '%s' section",
1375 PR_MEDIUM,
1376 "Item in permission selection identifying the admin section. Example: Access to 'Files & Images'"
1377 ), $title, null),
1378 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
1379 );
1380 }
1381 $perms["CMS_ACCESS_LeftAndMain"] = array(
1382 'name' => _t('CMSMain.ACCESSALLINTERFACES', 'Access to all CMS sections'),
1383 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access'),
1384 'help' => _t('CMSMain.ACCESSALLINTERFACESHELP', 'Overrules more specific access settings.'),
1385 'sort' => -100
1386 );
1387 $perms['CMS_ACCESS_CMSMain']['help'] = _t(
1388 'CMSMain.ACCESS_HELP',
1389 'Allow viewing of the section containing page tree and content. View and edit permissions can be handled through page specific dropdowns, as well as the separate "Content permissions".'
1390 );
1391 $perms['CMS_ACCESS_SecurityAdmin']['help'] = _t(
1392 'SecurityAdmin.ACCESS_HELP',
1393 'Allow viewing, adding and editing users, as well as assigning permissions and roles to them.'
1394 );
1395
1396 if (isset($perms['CMS_ACCESS_ModelAdmin'])) unset($perms['CMS_ACCESS_ModelAdmin']);
1397
1398 return $perms;
1399 }
1400
1401 1402 1403 1404
1405 function LangSelector() {
1406 $member = Member::currentUser();
1407 $dropdown = new LanguageDropdownField(
1408 'LangSelector',
1409 'Language',
1410 array(),
1411 'SiteTree',
1412 'Locale-English',
1413 singleton('SiteTree')
1414 );
1415 $dropdown->setValue(Translatable::get_current_locale());
1416 return $dropdown;
1417 }
1418
1419 1420 1421 1422 1423
1424 function MultipleLanguages() {
1425 $langs = Translatable::get_existing_content_languages('SiteTree');
1426
1427 return (count($langs) > 1);
1428 }
1429
1430 1431 1432
1433 function IsTranslatableEnabled() {
1434 return SS_Object::has_extension('SiteTree', 'Translatable');
1435 }
1436 }
1437
1438 1439 1440 1441
1442 class CMSMainMarkingFilter {
1443
1444 function __construct() {
1445 $this->ids = array();
1446 $this->expanded = array();
1447
1448 $where = array();
1449
1450
1451 if (isset($_REQUEST['SiteTreeSearchTerm'])) {
1452 $term = Convert::raw2sql($_REQUEST['SiteTreeSearchTerm']);
1453 $where[] = "\"URLSegment\" LIKE '%$term%' OR \"Title\" LIKE '%$term%' OR \"MenuTitle\" LIKE '%$term%' OR \"Content\" LIKE '%$term%'";
1454 }
1455
1456
1457 if (isset($_REQUEST['SiteTreeFilterDate'])) {
1458 $date = $_REQUEST['SiteTreeFilterDate'];
1459 $date = ((int)substr($date,6,4)) . '-' . ((int)substr($date,3,2)) . '-' . ((int)substr($date,0,2));
1460 $where[] = "\"LastEdited\" > '$date'";
1461 }
1462
1463
1464 if (isset($_REQUEST['ClassName']) && $_REQUEST['ClassName'] != 'All') {
1465 $klass = Convert::raw2sql($_REQUEST['ClassName']);
1466 $where[] = "\"ClassName\" = '$klass'";
1467 }
1468
1469
1470 foreach (CMSMain::T_SiteTreeFilterOptions() as $key => $value) {
1471 if (!empty($_REQUEST[$key])) {
1472 $match = Convert::raw2sql($_REQUEST[$key]);
1473 $where[] = "\"$key\" LIKE '%$match%'";
1474 }
1475 }
1476
1477 $where = empty($where) ? '' : 'WHERE (' . implode(') AND (',$where) . ')';
1478
1479 $parents = array();
1480
1481
1482 $res = DB::query('SELECT "ParentID", "ID" FROM "SiteTree" '.$where);
1483 if (!$res) return;
1484
1485
1486 foreach($res as $row) {
1487 if ($row['ParentID']) $parents[$row['ParentID']] = true;
1488 $this->ids[$row['ID']] = true;
1489 }
1490
1491
1492 while (!empty($parents)) {
1493 $res = DB::query('SELECT "ParentID", "ID" FROM "SiteTree" WHERE "ID" in ('.implode(',',array_keys($parents)).')');
1494 $parents = array();
1495
1496 foreach($res as $row) {
1497 if ($row['ParentID']) $parents[$row['ParentID']] = true;
1498 $this->ids[$row['ID']] = true;
1499 $this->expanded[$row['ID']] = true;
1500 }
1501 }
1502 }
1503
1504 function mark($node) {
1505 $id = $node->ID;
1506 if(array_key_exists((int) $id, $this->expanded)) $node->markOpened();
1507 return array_key_exists((int) $id, $this->ids) ? $this->ids[$id] : false;
1508 }
1509 }
1510
1511 ?>
1512
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-