diff --git a/code/controllers/AssetAdmin.php b/code/controllers/AssetAdmin.php index 84b9868a..4621c84f 100644 --- a/code/controllers/AssetAdmin.php +++ b/code/controllers/AssetAdmin.php @@ -2,20 +2,20 @@ /** * AssetAdmin is the 'file store' section of the CMS. * It provides an interface for manipulating the File and Folder objects in the system. - * + * * @package cms * @subpackage assets */ class AssetAdmin extends LeftAndMain implements PermissionProvider{ private static $url_segment = 'assets'; - + private static $url_rule = '/$Action/$ID'; - + private static $menu_title = 'Files'; private static $tree_class = 'Folder'; - + /** * Amount of results showing on a single page. * @@ -23,14 +23,14 @@ class AssetAdmin extends LeftAndMain implements PermissionProvider{ * @var int */ private static $page_length = 15; - + /** * @config * @see Upload->allowedMaxFileSize * @var int */ private static $allowed_max_file_size; - + private static $allowed_actions = array( 'addfolder', 'delete', @@ -45,7 +45,7 @@ class AssetAdmin extends LeftAndMain implements PermissionProvider{ 'doSync', 'filter', ); - + /** * Return fake-ID "root" if no ID is found (needed to upload files into the root-folder) */ @@ -66,7 +66,7 @@ class AssetAdmin extends LeftAndMain implements PermissionProvider{ */ public function init() { parent::init(); - + // Create base folder if it doesnt exist already if(!file_exists(ASSETS_PATH)) Filesystem::makeFolder(ASSETS_PATH); @@ -84,7 +84,7 @@ class AssetAdmin extends LeftAndMain implements PermissionProvider{ }; JS ); - + CMSBatchActionHandler::register('delete', 'AssetAdmin_DeleteBatchAction', 'Folder'); } @@ -92,7 +92,7 @@ JS * Returns the files and subfolders contained in the currently selected folder, * defaulting to the root node. Doubles as search results, if any search parameters * are set through {@link SearchForm()}. - * + * * @return SS_List */ public function getList() { @@ -122,7 +122,7 @@ JS )); } - // Always show folders at the top + // Always show folders at the top $list = $list->sort('(CASE WHEN "File"."ClassName" = \'Folder\' THEN 0 ELSE 1 END), "Name"'); // If a search is conducted, check for the "current folder" limitation. @@ -138,7 +138,7 @@ JS $exts = File::config()->app_categories[$params['AppCategory']]; $list = $list->filter('Name:PartialMatch', $exts); } - + // Date filter if(!empty($params['CreatedFrom'])) { $fromDate = new DateField(null, null, $params['CreatedFrom']); @@ -184,19 +184,19 @@ JS 'Created' => 'SS_Datetime->Nice' )); $gridField->setAttribute( - 'data-url-folder-template', + 'data-url-folder-template', Controller::join_links($this->Link('show'), '%s') ); if($folder->canCreate()) { $uploadBtn = new LiteralField( - 'UploadButton', + 'UploadButton', sprintf( '%s', Controller::join_links(singleton('CMSFileAddController')->Link(), '?ID=' . $folder->ID), _t('Folder.UploadFilesButton', 'Upload') ) - ); + ); } else { $uploadBtn = null; } @@ -204,7 +204,7 @@ JS if(!$folder->hasMethod('canAddChildren') || ($folder->hasMethod('canAddChildren') && $folder->canAddChildren())) { // TODO Will most likely be replaced by GridField logic $addFolderBtn = new LiteralField( - 'AddFolderButton', + 'AddFolderButton', sprintf( '%s', Controller::join_links($this->Link('AddForm'), '?' . http_build_query(array( @@ -233,12 +233,12 @@ JS } else { $syncButton = null; } - + // Move existing fields to a "details" tab, unless they've already been tabbed out through extensions. // Required to keep Folder->getCMSFields() simple and reuseable, // without any dependencies into AssetAdmin (e.g. useful for "add folder" views). if(!$fields->hasTabset()) { - $tabs = new TabSet('Root', + $tabs = new TabSet('Root', $tabList = new Tab('ListView', _t('AssetAdmin.ListView', 'List View')), $tabTree = new Tab('TreeView', _t('AssetAdmin.TreeView', 'Tree View')) ); @@ -269,7 +269,7 @@ JS )->addExtraClass('cms-content-toolbar field'), $gridField )); - + $treeField = new LiteralField('Tree', ''); // Tree view $fields->addFieldsToTab('Root.TreeView', array( @@ -278,10 +278,10 @@ JS new LiteralField( 'Tree', FormField::create_tag( - 'div', + 'div', array( - 'class' => 'cms-tree', - 'data-url-tree' => $this->Link('getsubtree'), + 'class' => 'cms-tree', + 'data-url-tree' => $this->Link('getsubtree'), 'data-url-savetreenode' => $this->Link('savetreenode') ), $this->SiteTreeAsUL() @@ -297,11 +297,11 @@ JS $actions->removeByName('action_delete'); if(($saveBtn || $deleteBtn) && $fields->fieldByName('Root.DetailsView')) { $fields->addFieldToTab( - 'Root.DetailsView', + 'Root.DetailsView', CompositeField::create($saveBtn,$deleteBtn)->addExtraClass('Actions') ); } - + $fields->setForm($form); @@ -333,7 +333,7 @@ JS public function delete($data, $form) { $className = $this->stat('tree_class'); - + $record = DataObject::get_by_id($className, $data['ID']); if($record && !$record->canDelete()) return Security::permissionFailure(); if(!$record || !$record->ID) throw new SS_HTTPResponse_Exception("Bad record ID #" . (int)$data['ID'], 404); @@ -341,8 +341,8 @@ JS $record->delete(); $this->setCurrentPageID(null); - $this->response->addHeader('X-Status', rawurlencode(_t('LeftAndMain.DELETED', 'Deleted.'))); - $this->response->addHeader('X-Pjax', 'Content'); + $this->getResponse()->addHeader('X-Status', rawurlencode(_t('LeftAndMain.DELETED', 'Deleted.'))); + $this->getResponse()->addHeader('X-Pjax', 'Content'); return $this->redirect(Controller::join_links($this->Link('show'), $parentID ? $parentID : 0)); } @@ -353,7 +353,7 @@ JS */ public function getSearchContext() { $context = singleton('File')->getDefaultSearchContext(); - + // Namespace fields, for easier detection if a search is present foreach($context->getFields() as $field) $field->setName(sprintf('q[%s]', $field->getName())); foreach($context->getFilters() as $filter) $filter->setFullName(sprintf('q[%s]', $filter->getFullName())); @@ -395,7 +395,7 @@ JS return $context; } - + /** * Returns a form for filtering of files and assets gridfield. * Result filtering takes place in {@link getList()}. @@ -413,7 +413,7 @@ JS ->addExtraClass('ss-ui-action-constructive'), Object::create('ResetFormAction', 'clear', _t('CMSMain_left_ss.RESET', 'Reset')) ); - + $form = new Form($this, 'filter', $fields, $actions); $form->setFormMethod('GET'); $form->setFormAction(Controller::join_links($this->Link('show'), $folder->ID)); @@ -424,10 +424,10 @@ JS $form->setAttribute('data-gridfield', 'File'); return $form; } - + public function AddForm() { $folder = singleton('Folder'); - $form = CMSForm::create( + $form = CMSForm::create( $this, 'AddForm', new FieldList( @@ -444,31 +444,31 @@ JS $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); // TODO Can't merge $FormAttributes in template at the moment $form->addExtraClass('add-form cms-add-form cms-edit-form cms-panel-padded center ' . $this->BaseCSSClasses()); - + return $form; } - + /** * Add a new group and return its details suitable for ajax. - * + * * @todo Move logic into Folder class, and use LeftAndMain->doAdd() default implementation. */ public function doAdd($data, $form) { $class = $this->stat('tree_class'); - + // check create permissions if(!singleton($class)->canCreate()) return Security::permissionFailure($this); // check addchildren permissions if( - singleton($class)->hasExtension('Hierarchy') + singleton($class)->hasExtension('Hierarchy') && isset($data['ParentID']) && is_numeric($data['ParentID']) && $data['ParentID'] ) { $parentRecord = DataObject::get_by_id($class, $data['ParentID']); if( - $parentRecord->hasMethod('canAddChildren') + $parentRecord->hasMethod('canAddChildren') && !$parentRecord->canAddChildren() ) return Security::permissionFailure($this); } else { @@ -478,8 +478,8 @@ JS $parent = (isset($data['ParentID']) && is_numeric($data['ParentID'])) ? (int)$data['ParentID'] : 0; $name = (isset($data['Name'])) ? basename($data['Name']) : _t('AssetAdmin.NEWFOLDER',"NewFolder"); if(!$parentRecord || !$parentRecord->ID) $parent = 0; - - // Get the folder to be created + + // Get the folder to be created if($parentRecord && $parentRecord->ID) $filename = $parentRecord->FullPath . $name; else $filename = ASSETS_PATH . '/' . $name; @@ -487,22 +487,22 @@ JS if(!file_exists(ASSETS_PATH)) { mkdir(ASSETS_PATH); } - + $record = new Folder(); $record->ParentID = $parent; $record->Name = $record->Title = basename($filename); - // Ensure uniqueness + // Ensure uniqueness $i = 2; $baseFilename = substr($record->Filename, 0, -1) . '-'; while(file_exists($record->FullPath)) { $record->Filename = $baseFilename . $i . '/'; $i++; } - + $record->Name = $record->Title = basename($record->Filename); $record->write(); - + mkdir($record->FullPath); chmod($record->FullPath, Filesystem::config()->file_create_mask); @@ -527,17 +527,17 @@ JS $this->setCurrentPageID(null); return new Folder(); } - + public function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $numChildrenMethod = null, $filterFunction = null, $minNodeCount = 30) { if (!$childrenMethod) $childrenMethod = 'ChildFolders'; if (!$numChildrenMethod) $numChildrenMethod = 'numChildFolders'; return parent::getSiteTreeFor($className, $rootID, $childrenMethod, $numChildrenMethod, $filterFunction, $minNodeCount); } - + public function getCMSTreeTitle() { return Director::absoluteBaseURL() . "assets"; } - + public function SiteTreeAsUL() { return $this->getSiteTreeFor($this->stat('tree_class'), null, 'ChildFolders', 'numChildFolders'); } @@ -552,17 +552,17 @@ JS */ public function doSync() { $message = Filesystem::sync(); - $this->response->addHeader('X-Status', rawurlencode($message)); - + $this->getResponse()->addHeader('X-Status', rawurlencode($message)); + return; } - + /** * ################################# * Garbage collection. * ################################# */ - + /** * Removes all unused thumbnails from the file store * and returns the status of the process to the user. @@ -570,42 +570,42 @@ JS public function deleteunusedthumbnails($request) { // Protect against CSRF on destructive action if(!SecurityToken::inst()->checkRequest($request)) return $this->httpError(400); - + $count = 0; $thumbnails = $this->getUnusedThumbnails(); - + if($thumbnails) { foreach($thumbnails as $thumbnail) { unlink(ASSETS_PATH . "/" . $thumbnail); $count++; } } - + $message = _t( - 'AssetAdmin.THUMBSDELETED', - '{count} unused thumbnails have been deleted', + 'AssetAdmin.THUMBSDELETED', + '{count} unused thumbnails have been deleted', array('count' => $count) ); - $this->response->addHeader('X-Status', rawurlencode($message)); + $this->getResponse()->addHeader('X-Status', rawurlencode($message)); return; } - + /** * Creates array containg all unused thumbnails. - * + * * Array is created in three steps: * 1. Scan assets folder and retrieve all thumbnails * 2. Scan all HTMLField in system and retrieve thumbnails from them. * 3. Count difference between two sets (array_diff) * - * @return array + * @return array */ private function getUnusedThumbnails() { $allThumbnails = array(); $usedThumbnails = array(); $dirIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(ASSETS_PATH)); $classes = ClassInfo::subclassesFor('SiteTree'); - + if($dirIterator) { foreach($dirIterator as $file) { if($file->isFile()) { @@ -619,26 +619,26 @@ JS } } } - + if($classes) { foreach($classes as $className) { $SNG_class = singleton($className); $objects = DataObject::get($className); - + if($objects !== NULL) { foreach($objects as $object) { foreach($SNG_class->db() as $fieldName => $fieldType) { if($fieldType == 'HTMLText') { $url1 = HTTP::findByTagAndAttribute($object->$fieldName,array('img' => 'src')); - + if($url1 != NULL) { $usedThumbnails[] = substr($url1[0], strpos($url1[0], '/assets/') + 8); } - + if($object->latestPublished > 0) { $object = Versioned::get_latest_version($className, $object->ID); $url2 = HTTP::findByTagAndAttribute($object->$fieldName, array('img' => 'src')); - + if($url2 != NULL) { $usedThumbnails[] = substr($url2[0], strpos($url2[0], '/assets/') + 8); } @@ -649,7 +649,7 @@ JS } } } - + return array_diff($allThumbnails, $usedThumbnails); } @@ -693,12 +693,12 @@ JS ) ); } - + } /** * Delete multiple {@link Folder} records (and the associated filesystem nodes). * Usually used through the {@link AssetAdmin} interface. - * + * * @package cms * @subpackage batchactions */ @@ -713,10 +713,10 @@ class AssetAdmin_DeleteBatchAction extends CMSBatchAction { 'modified'=>array(), 'deleted'=>array() ); - + foreach($records as $record) { $id = $record->ID; - + // Perform the action if($record->canDelete()) $record->delete(); diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index 9003b85e..da7fc24c 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -4,29 +4,29 @@ * * This class creates a 2-frame layout - left-tree and right-form - to sit beneath the main * admin menu. - * + * * @package cms * @subpackage controller * @todo Create some base classes to contain the generic functionality that will be replicated. */ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionProvider { - + private static $url_segment = 'pages'; - + private static $url_rule = '/$Action/$ID/$OtherID'; - + // Maintain a lower priority than other administration sections // so that Director does not think they are actions of CMSMain private static $url_priority = 39; - + private static $menu_title = 'Edit Page'; - + private static $menu_priority = 10; - + private static $tree_class = "SiteTree"; - + private static $subitem_class = "Member"; - + /** * Amount of results showing on a single page. * @@ -34,7 +34,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr * @var int */ private static $page_length = 15; - + private static $allowed_actions = array( 'archive', 'buildbrokenlinks', @@ -65,20 +65,20 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr * @config */ private static $enabled_legacy_actions = array(); - + public function init() { // set reading lang if(SiteTree::has_extension('Translatable') && !$this->getRequest()->isAjax()) { Translatable::choose_site_locale(array_keys(Translatable::get_existing_content_languages('SiteTree'))); } - + parent::init(); Versioned::reading_stage("Stage"); - + Requirements::css(CMS_DIR . '/css/screen.css'); Requirements::customCSS($this->generatePageIconsCss()); - + Requirements::combine_files( 'cmsmain.js', array_merge( @@ -97,7 +97,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr CMSBatchActionHandler::register('publish', 'CMSBatchAction_Publish'); CMSBatchActionHandler::register('unpublish', 'CMSBatchAction_Unpublish'); - + // Check legacy actions $legacy = $this->config()->enabled_legacy_actions; @@ -144,7 +144,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr public function ShowSwitchView() { return true; } - + /** * Overloads the LeftAndMain::ShowView. Allows to pass a page as a parameter, so we are able * to switch view also for archived versions. @@ -153,7 +153,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr if(!$page) { $page = $this->currentPage(); } - + if($page) { $nav = SilverStripeNavigator::get_for_record($page); return $nav['items']; @@ -305,10 +305,10 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $this->extend('updateExtraTreeTools', $html); return $html; } - + /** * Returns a Form for page searching for use in templates. - * + * * Can be modified from a decorator by a 'updateSearchForm' method * * @return Form @@ -318,7 +318,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $content = new TextField('q[Term]', _t('CMSSearch.FILTERLABELTEXT', 'Search')); $dateHeader = new HeaderField('q[Date]', _t('CMSSearch.PAGEFILTERDATEHEADING', 'Last edited'), 4); $dateFrom = new DateField( - 'q[LastEditedFrom]', + 'q[LastEditedFrom]', _t('CMSSearch.FILTERDATEFROM', 'From') ); $dateFrom->setConfig('showcalendar', true); @@ -328,17 +328,17 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr ); $dateTo->setConfig('showcalendar', true); $pageFilter = new DropdownField( - 'q[FilterClass]', - _t('CMSMain.PAGES', 'Page status'), + 'q[FilterClass]', + _t('CMSMain.PAGES', 'Page status'), CMSSiteTreeFilter::get_all_filters() ); $pageClasses = new DropdownField( - 'q[ClassName]', - _t('CMSMain.PAGETYPEOPT', 'Page type', 'Dropdown for limiting search to a page type'), + 'q[ClassName]', + _t('CMSMain.PAGETYPEOPT', 'Page type', 'Dropdown for limiting search to a page type'), $this->getPageTypes() ); $pageClasses->setEmptyString(_t('CMSMain.PAGETYPEANYOPT','Any')); - + // Group the Datefields $dateGroup = new FieldGroup( $dateHeader, @@ -346,7 +346,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $dateTo ); $dateGroup->setFieldHolderTemplate('FieldGroup_DefaultFieldHolder')->addExtraClass('stacked'); - + // Create the Field list $fields = new FieldList( $content, @@ -354,7 +354,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $pageFilter, $pageClasses ); - + // Create the Search and Reset action $actions = new FieldList( FormAction::create('doSearch', _t('CMSMain_left_ss.APPLY_FILTER', 'Search')) @@ -366,7 +366,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr foreach($actions->dataFields() as $action) { $action->setUseButtonTag(true); } - + // Create the form $form = Form::create($this, 'SearchForm', $fields, $actions) ->addExtraClass('cms-search-form') @@ -374,19 +374,19 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr ->setFormAction($this->Link()) ->disableSecurityToken() ->unsetValidator(); - + // Load the form with previously sent search data $form->loadDataFrom($this->getRequest()->getVars()); // Allow decorators to modify the form $this->extend('updateSearchForm', $form); - + return $form; } - + /** * Returns a sorted array suitable for a dropdown with pagetypes and their translated name - * + * * @return array */ protected function getPageTypes() { @@ -397,7 +397,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr asort($pageTypes); return $pageTypes; } - + public function doSearch($data, $form) { return $this->getsubtree($this->getRequest()); } @@ -421,7 +421,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr /** * Create serialized JSON string with site tree hints data to be injected into * 'data-hints' attribute of root node of jsTree. - * + * * @return String Serialized JSON */ public function SiteTreeHints() { @@ -506,18 +506,18 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr if($instance->stat('need_permission') && !$this->can(singleton($class)->stat('need_permission'))) continue; $addAction = $instance->i18n_singular_name(); - + // Get description (convert 'Page' to 'SiteTree' for correct localization lookups) $description = _t((($class == 'Page') ? 'SiteTree' : $class) . '.DESCRIPTION'); if(!$description) { $description = $instance->uninherited('description'); } - + if($class == 'Page' && !$description) { $description = singleton('SiteTree')->uninherited('description'); } - + $result->push(new ArrayData(array( 'ClassName' => $class, 'AddAction' => $addAction, @@ -527,9 +527,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr 'Title' => singleton($class)->i18n_singular_name(), ))); } - + $result = $result->sort('AddAction'); - + return $result; } @@ -545,12 +545,12 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr if($id instanceof $treeClass) { return $id; - } + } else if($id && is_numeric($id)) { if($this->getRequest()->getVar('Version')) { $versionID = (int) $this->getRequest()->getVar('Version'); } - + if($versionID) { $record = Versioned::get_version($treeClass, $id, $versionID); } else { @@ -566,7 +566,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $record = DataObject::get_by_id($treeClass, $id); if($record) Versioned::set_reading_mode(''); } - + // Then, try getting a deleted record if(!$record) { $record = Versioned::get_latest_version($treeClass, $id); @@ -577,7 +577,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr * we should not check their locale matches the Translatable::get_current_locale, * here as long as we all the HTTPRequest is init with right locale. * This bit breaks the all FileIFrameField functions if the field is used in CMS - * and its relevent ajax calles, like loading the tree dropdown for TreeSelectorField. + * and its relevent ajax calles, like loading the tree dropdown for TreeSelectorField. */ /* if($record && SiteTree::has_extension('Translatable') && $record->Locale && $record->Locale != Translatable::get_current_locale()) { $record = null; @@ -589,7 +589,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr return $this->getNewItem($id); } } - + /** * @param Int $id * @param FieldList $fields @@ -599,7 +599,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr if(!$id) $id = $this->currentPageID(); $form = parent::getEditForm($id); - + // TODO Duplicate record fetching (see parent implementation) $record = $this->getRecord($id); if($record && !$record->canView()) return Security::permissionFailure($this); @@ -626,14 +626,14 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr if($stageLink) $stageLinkField->setValue($stageLink); } } - + // Added in-line to the form, but plucked into different view by LeftAndMain.Preview.js upon load if(in_array('CMSPreviewable', class_implements($record)) && !$fields->fieldByName('SilverStripeNavigator')) { $navField = new LiteralField('SilverStripeNavigator', $this->getSilverStripeNavigator()); $navField->setAllowHTML(true); $fields->push($navField); } - + // getAllCMSActions can be used to completely redefine the action list if($record->hasMethod('getAllCMSActions')) { $actions = $record->getAllCMSActions(); @@ -656,14 +656,14 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr // Use