updateCMSFields()}). // $Lang serves as a "context" which can be inspected by Translatable - hence it // has the same name as the database property on Translatable. if($this->getRequest()->requestVar("Locale")) { $this->Locale = $this->getRequest()->requestVar("Locale"); } elseif($this->getRequest()->requestVar("locale")) { $this->Locale = $this->getRequest()->requestVar("locale"); } else { $this->Locale = Translatable::default_locale(); } Translatable::set_current_locale($this->Locale); // collect languages for TinyMCE spellchecker plugin. // see http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker $langName = i18n::get_locale_name($this->Locale); HtmlEditorConfig::get('cms')->setOption('spellchecker_languages', "+{$langName}={$this->Locale}"); Requirements::javascript(CMS_DIR . '/javascript/CMSMain.js'); Requirements::javascript(CMS_DIR . '/javascript/CMSMain.Tree.js'); Requirements::javascript(CMS_DIR . '/javascript/CMSMain.EditForm.js'); Requirements::javascript(CMS_DIR . '/javascript/CMSMain.BatchActions.js'); Requirements::javascript(CMS_DIR . '/javascript/CMSMain.Translatable.js'); Requirements::css(CMS_DIR . '/css/CMSMain.css'); } /** * If this is set to true, the "switchView" context in the * template is shown, with links to the staging and publish site. * * @return boolean */ function ShowSwitchView() { return true; } //------------------------------------------------------------------------------------------// // Main controllers //------------------------------------------------------------------------------------------// // Main UI components /** * Override {@link LeftAndMain} Link to allow blank URL segment for CMSMain. * * @return string */ public function Link($action = null) { return Controller::join_links( $this->stat('url_base', true), $this->stat('url_segment', true), // in case we want to change the segment '/', // trailing slash needed if $action is null! "$action" ); } /** * Return the entire site tree as a nested set of ULs */ public function SiteTreeAsUL() { $this->generateDataTreeHints(); $this->generateTreeStylingJS(); // Pre-cache sitetree version numbers for querying efficiency Versioned::prepopulate_versionnumber_cache("SiteTree", "Stage"); Versioned::prepopulate_versionnumber_cache("SiteTree", "Live"); return $this->getSiteTreeFor("SiteTree"); } /** * Use a CMSSiteTreeFilter to only get certain nodes * * @return string */ public function getfilteredsubtree($data, $form) { $params = $form->getData(); // Get the tree $tree = $this->getSiteTreeFor( $this->stat('tree_class'), $data['ID'], null, array(new CMSMainMarkingFilter($params), 'mark') ); // Trim off the outer tag $tree = ereg_replace('^[ \t\r\n]*
%s
', _t('CMSMain_left.ss.SELECTPAGESACTIONS','Select the pages that you want to change & then click an action:')) ), new HiddenField('csvIDs') ), new FieldSet( new FormAction('deleteitems', _t('CMSMain_left.ss.DELETECONFIRM','Delete the selected pages')) ) ); $form->addExtraClass('actionparams'); return $form; } function buildbrokenlinks() { if($this->urlParams['ID']) { $newPageSet[] = DataObject::get_by_id("Page", $this->urlParams['ID']); } else { $pages = DataObject::get("Page"); foreach($pages as $page) $newPageSet[] = $page; $pages = null; } $content = new HtmlEditorField('Content'); $download = new HtmlEditorField('Download'); foreach($newPageSet as $i => $page) { $page->HasBrokenLink = 0; $page->HasBrokenFile = 0; $lastUsage = (memory_get_usage() - $lastPoint); $lastPoint = memory_get_usage(); $content->setValue($page->Content); $content->saveInto($page); $download->setValue($page->Download); $download->saveInto($page); echo "%s
', _t( 'CMSMain_left.ss.SELECTPAGESACTIONS', 'Select the pages that you want to change & then click an action:' ) ) ), new HiddenField('csvIDs'), new DropdownField( 'Action', false, $actionsMap ) ), new FieldSet( // TODO i18n new FormAction('submit', "Go") ) ); $form->addExtraClass('actionparams'); $form->unsetValidator(); return $form; } /** * Helper function to get page count */ function getpagecount() { ini_set('max_execution_time', 0); $excludePages = split(" *, *", $_GET['exclude']); $pages = DataObject::get("SiteTree", "\"ParentID\" = 0"); foreach($pages as $page) $pageArr[] = $page; while(list($i,$page) = each($pageArr)) { if(!in_array($page->URLSegment, $excludePages)) { if($children = $page->AllChildren()) { foreach($children as $child) $pageArr[] = $child; } if(!$_GET['onlywithcontent'] || strlen(Convert::xml2raw($page->Content)) > 100) { echo "' . _t('CMSMain.TOTALPAGES',"Total pages: ") . "$count
"; } function publishall() { ini_set("memory_limit", -1); ini_set('max_execution_time', 0); $response = ""; if(isset($this->requestParams['confirm'])) { $start = 0; $pages = DataObject::get("SiteTree", "", "", "", "$start,30"); $count = 0; if($pages){ while(true) { foreach($pages as $page) { if($page && !$page->canPublish()) return Security::permissionFailure($this); $page->doPublish(); $page->destroy(); unset($page); $count++; $response .= "' . _t('CMSMain.PUBALLFUN2', 'Pressing this button will do the equivalent of going to every page and pressing "publish". It\'s intended to be used after there have been massive edits of the content, such as when the site was first built.') . '
'; } return $response; } /** * Restore a completely deleted page from the SiteTree_versions table. */ function restore($data, $form) { if(!isset($data['ID']) || !is_numeric($data['ID'])) { return new HTTPResponse("Please pass an ID in the form content", 400); } $restoredPage = Versioned::get_latest_version("SiteTree", $id); if(!$restoredPage) return new HTTPResponse("SiteTree #$id not found", 400); $restoredPage = $restoredPage->doRestoreToStage(); $this->response->addHeader( 'X-Status', sprintf( _t('CMSMain.RESTORED',"Restored '%s' successfully",PR_MEDIUM,'Param %s is a title'), $restoredPage->TreeTitle ) ); $form = $this->getEditForm($id); return $form->formHtmlContent(); } function duplicate() { if(($id = $this->urlParams['ID']) && is_numeric($id)) { $page = DataObject::get_by_id("SiteTree", $id); if($page && (!$page->canEdit() || !$page->canCreate())) { return Security::permissionFailure($this); } $newPage = $page->duplicate(); // ParentID can be hard-set in the URL. This is useful for pages with multiple parents if($_GET['parentID'] && is_numeric($_GET['parentID'])) { $newPage->ParentID = $_GET['parentID']; $newPage->write(); } $form = $this->getEditForm($newPage->ID); return $form->formHtmlContent(); } else { user_error("CMSMain::duplicate() Bad ID: '$id'", E_USER_WARNING); } } function duplicatewithchildren() { if(($id = $this->urlParams['ID']) && is_numeric($id)) { $page = DataObject::get_by_id("SiteTree", $id); if($page && (!$page->canEdit() || !$page->canCreate())) { return Security::permissionFailure($this); } $newPage = $page->duplicateWithChildren(); $form = $this->getEditForm($newPage->ID); return $form->formHtmlContent(); } else { user_error("CMSMain::duplicate() Bad ID: '$id'", E_USER_WARNING); } } /** * Create a new translation from an existing item, switch to this language and reload the tree. */ function createtranslation($request) { $langCode = Convert::raw2sql($request->getVar('newlang')); $originalLangID = (int)$request->getVar('ID'); $record = $this->getRecord($originalLangID); $this->Locale = $langCode; Translatable::set_current_locale($langCode); // Create a new record in the database - this is different // to the usual "create page" pattern of storing the record // in-memory until a "save" is performed by the user, mainly // to simplify things a bit. // @todo Allow in-memory creation of translations that don't persist in the database before the user requests it $translatedRecord = $record->createTranslation($langCode); $url = sprintf( "%s/%d/?locale=%s", $this->Link('show'), $translatedRecord->ID, $langCode ); return Director::redirect($url); } /** * Provide the permission codes used by LeftAndMain. * Can't put it on LeftAndMain since that's an abstract base class. */ function providePermissions() { $classes = ClassInfo::subclassesFor('LeftAndMain'); foreach($classes as $i => $class) { $title = _t("{$class}.MENUTITLE", LeftAndMain::menu_title_for_class($class)); $perms["CMS_ACCESS_" . $class] = array( 'name' => sprintf(_t( 'CMSMain.ACCESS', "Access to %s", PR_MEDIUM, "Item in permission selection identifying the admin section, with title and classname. Example: Access to Files & Images" ), $title), 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access') ); } $perms["CMS_ACCESS_LeftAndMain"] = array( 'name' => _t('CMSMain.ACCESSALLINTERFACES', 'Access to all CMS sections'), 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access'), 'sort' => -100 ); if (isset($perms['CMS_ACCESS_ModelAdmin'])) unset($perms['CMS_ACCESS_ModelAdmin']); return $perms; } /** * Returns a form with all languages with languages already used appearing first. * * @return Form */ function LangForm() { $member = Member::currentUser(); //check to see if the current user can switch langs or not if(Permission::checkMember($member, 'VIEW_LANGS')) { $field = new LanguageDropdownField( 'Locale', // TODO i18n 'Language', array(), 'SiteTree', 'Locale-English', singleton('SiteTree') ); $field->setValue(Translatable::get_current_locale()); } else { // user doesn't have permission to switch langs // so just show a string displaying current language $field = new LiteralField( 'Locale', i18n::get_locale_name( Translatable::get_current_locale()) ); } $form = new Form( $this, 'LangForm', new FieldSet( $field ), new FieldSet( new FormAction('selectlang', _t('CMSMain_left.ss.GO','Go')) ) ); $form->unsetValidator(); return $form; } function selectlang($data, $form) { return $this; } /** * Determine if there are more than one languages in our site tree. * * @return boolean */ function MultipleLanguages() { $langs = Translatable::get_existing_content_languages('SiteTree'); return (count($langs) > 1); } /** * @return boolean */ function IsTranslatableEnabled() { return Object::has_extension('SiteTree', 'Translatable'); } } class CMSMainMarkingFilter { /** * @var array Request params (unsanitized) */ protected $params = array(); /** * @param array $params Request params (unsanitized) */ function __construct($params = null) { $this->ids = array(); $this->expanded = array(); $this->params = $params; $where = array(); $SQL_params = Convert::raw2sql($this->params); foreach($SQL_params as $name => $val) { switch($name) { // Match against URLSegment, Title, MenuTitle & Content case 'SiteTreeSearchTerm': $where[] = "\"URLSegment\" LIKE '%$val%' OR \"Title\" LIKE '%$val%' OR \"MenuTitle\" LIKE '%$val%' OR \"Content\" LIKE '%$val%'"; break; // Match against date case 'SiteTreeFilterDate': $val = ((int)substr($val,6,4)) . '-' . ((int)substr($val,3,2)) . '-' . ((int)substr($val,0,2)); $where[] = "\"LastEdited\" > '$val'"; break; // Match against exact ClassName case 'ClassName': if($val != 'All') { $where[] = "\"ClassName\" = '$val'"; } break; default: // Partial string match against a variety of fields if(!empty($val) && singleton("SiteTree")->hasDatabaseField($name)) { $where[] = "\"$name\" LIKE '%$val%'"; } } } $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; } } } function mark($node) { $id = $node->ID; if(array_key_exists((int) $id, $this->expanded)) $node->markOpened(); return array_key_exists((int) $id, $this->ids) ? $this->ids[$id] : false; } } ?>