diff --git a/code/AssetAdmin.php b/code/AssetAdmin.php index 4e87d253..90952e47 100755 --- a/code/AssetAdmin.php +++ b/code/AssetAdmin.php @@ -76,8 +76,6 @@ class AssetAdmin extends LeftAndMain { Requirements::css(SAPPHIRE_DIR . "/css/ComplexTableField.css"); Requirements::javascript(CMS_DIR . "/javascript/AssetAdmin.js"); - Requirements::javascript(CMS_DIR . "/javascript/AssetAdmin_left.js"); - Requirements::javascript(CMS_DIR . "/javascript/AssetAdmin_right.js"); Requirements::javascript(CMS_DIR . "/javascript/CMSMain_upload.js"); Requirements::javascript(CMS_DIR . "/javascript/Upload.js"); @@ -235,6 +233,8 @@ JS foreach($newFiles as $newFile) { $fileIDs[] = $newFile; $fileObj = DataObject::get_one('File', "\"File\".\"ID\"=$newFile"); + // notify file object after uploading + if (method_exists($fileObj, 'onAfterUpload')) $fileObj->onAfterUpload(); $fileNames[] = $fileObj->Name; } @@ -254,6 +254,18 @@ JS HTML; } + + /** + * Custom currentPage() method to handle opening the 'root' folder + */ + public function currentPage() { + $id = $this->currentPageID(); + if($id && is_numeric($id)) { + return DataObject::get_by_id($this->stat('tree_class'), $id); + } else if($id == 'root') { + return singleton($this->stat('tree_class')); + } + } /** * Return the form that displays the details of a folder, including a file list and fields for editing the folder name. @@ -485,24 +497,18 @@ JS; if(!$parentObj || !$parentObj->ID) $parent = 0; } - $p = new Folder(); - $p->ParentID = $parent; - $p->Title = $name; - $p->Name = $name; - // Get the folder to be created - if(isset($parentObj->ID)) $filename = $parentObj->FullPath . $p->Name; - else $filename = ASSETS_PATH . '/' . $p->Name; - + if(isset($parentObj->ID)) $filename = $parentObj->FullPath . $name; + else $filename = ASSETS_PATH . '/' . $name; + // Ensure uniqueness $i = 2; $baseFilename = $filename . '-'; while(file_exists($filename)) { $filename = $baseFilename . $i; - $p->Name = $p->Title = basename($filename); $i++; } - + // Actually create if(!file_exists(ASSETS_PATH)) { mkdir(ASSETS_PATH); @@ -510,8 +516,12 @@ JS; mkdir($filename); chmod($filename, Filesystem::$file_create_mask); + // Create object + $p = new Folder(); + $p->ParentID = $parent; + $p->Name = $p->Title = basename($filename); $p->write(); - + if(isset($_REQUEST['returnID'])) { return $p->ID; } else { @@ -519,25 +529,6 @@ JS; } } - /** - * Return the given tree item to the client. - * If called by ajax, this will be some javascript commands. - * Otherwise, it will redirect back. - */ - public function returnItemToUser($p) { - if(!empty($_REQUEST['ajax'])) { - $parentID = (int) $p->ParentID; - return <<ID, "$p->Title", "$p->class"); - tree.getTreeNodeByIdx($parentID).appendTreeNode(newNode); - newNode.selectTreeNode(); -JS; - } else { - Director::redirectBack(); - } - } - /** * @return Form */ @@ -573,13 +564,11 @@ JS; foreach($ids as $id) { if(is_numeric($id)) { $record = DataObject::get_by_id($this->stat('tree_class'), $id); - if(!$record) { - Debug::message( "Record appears to be null" ); + if($record) { + $script .= $this->deleteTreeNodeJS($record); + $record->delete(); + $record->destroy(); } - $record->delete(); - $record->destroy(); - - $script .= $this->deleteTreeNodeJS($record); } } @@ -724,4 +713,4 @@ JS; } } -?> \ No newline at end of file +?> diff --git a/code/AssetTableField.php b/code/AssetTableField.php index 6c2abf55..cc0e4780 100755 --- a/code/AssetTableField.php +++ b/code/AssetTableField.php @@ -16,10 +16,14 @@ class AssetTableField extends ComplexTableField { "delete", //"export", ); + + /** + * Indicates whether a search is being executed on this object + */ + protected $searchingFor = null; + function __construct($controller, $name, $sourceClass, $fieldList, $detailFormFields, $sourceFilter = "", $sourceSort = "", $sourceJoin = "") { parent::__construct($controller, $name, $sourceClass, $fieldList, $detailFormFields, $sourceFilter, $sourceSort, $sourceJoin); - - Requirements::javascript(CMS_DIR . '/javascript/AssetTableField.js'); $SNG_file = singleton('File'); @@ -31,6 +35,7 @@ class AssetTableField extends ComplexTableField { if(strpos($fieldName, '.') === false) $searchFilters[] = "\"$fieldName\" LIKE '%{$SQL_search}%'"; } $this->sourceFilter = '(' . implode(' OR ', $searchFilters) . ')'; + $this->searchingFor = $_REQUEST['FileSearch']; } $this->sourceSort = 'Title'; @@ -38,15 +43,36 @@ class AssetTableField extends ComplexTableField { } function FieldHolder() { + $ret = parent::FieldHolder(); + + Requirements::javascript(CMS_DIR . '/javascript/AssetTableField.js'); Requirements::javascript('cms/javascript/ImageEditor/Activator.js'); - return parent::FieldHolder(); + return $ret; } function setFolder($folder) { $this->folder = $folder; $this->sourceFilter .= ($this->sourceFilter) ? " AND " : ""; - $this->sourceFilter .= " \"ParentID\" = '" . $folder->ID . "' AND \"ClassName\" <> 'Folder'"; + + // If you are searching for files then show all those from subfolders + if($this->searchingFor) { + $folderIDs = $nextIDSet = array($folder->ID); + $folderClasses = "'" . implode("','", ClassInfo::subclassesFor("Folder")) . "'"; + + while($nextIDSet) { + // TO DO: In 2.4 this should be refactored to use the new data mapper. + $nextIDSet = DB::query("SELECT ID FROM `File` WHERE ParentID IN (" + . implode(", " , $nextIDSet) . ") AND ClassName IN ($folderClasses)")->column(); + if($nextIDSet) $folderIDs = array_merge($folderIDs, $nextIDSet); + } + + $this->sourceFilter .= " ParentID IN (" . implode(", ", $folderIDs) . ") AND ClassName <> 'Folder'"; + + // Otherwise just show the direct contents + } else { + $this->sourceFilter .= " ParentID = '" . $folder->ID . "' AND ClassName <> 'Folder'"; + } } function Folder() { @@ -140,7 +166,7 @@ class AssetTableField extends ComplexTableField { */ function SearchForm() { $searchFields = new FieldGroup( - new TextField('FileSearch', _t('MemberTableField.SEARCH', 'Search')), + new TextField('FileSearch', _t('MemberTableField.SEARCH', 'Search'), $this->searchingFor), new HiddenField("ctf[ID]", '', $this->ID), new HiddenField('FileFieldName', '', $this->name) ); @@ -160,4 +186,4 @@ class AssetTableField extends ComplexTableField { } -?> \ No newline at end of file +?> diff --git a/code/CMSMain.php b/code/CMSMain.php index 1372d293..a0c93632 100644 --- a/code/CMSMain.php +++ b/code/CMSMain.php @@ -62,6 +62,8 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr * SiteTree Columns that can be filtered using the the Site Tree Search button */ static $site_tree_filter_options = array( + 'Title' => array('CMSMain.TITLE', 'Title'), + 'MenuTitle' => array('CMSMain.MENUTITLE', 'Navigation Label'), 'ClassName' => array('CMSMain.PAGETYPE', 'Page Type'), 'Status' => array('CMSMain.STATUS', 'Status'), 'MetaDescription' => array('CMSMain.METADESC', 'Description'), @@ -70,10 +72,12 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr static function T_SiteTreeFilterOptions(){ return array( + 'Title' => _t('CMSMain.TITLEOPT', 'Title', 0, 'The dropdown title in CMSMain left SiteTreeFilterOptions'), + 'MenuTitle' => _t('CMSMain.MENUTITLEOPT', 'Navigation Label', 0, 'The dropdown title in CMSMain left SiteTreeFilterOptions'), 'ClassName' => _t('CMSMain.PAGETYPEOPT', 'Page Type', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"), 'Status' => _t('CMSMain.STATUSOPT', 'Status', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"), 'MetaDescription' => _t('CMSMain.METADESCOPT', 'Description', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"), - 'MetaKeywords' => _t('CMSMain.METAKEYWORDSOPT', 'Keywords', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions"), + 'MetaKeywords' => _t('CMSMain.METAKEYWORDSOPT', 'Keywords', 0, "The dropdown title in CMSMain left SiteTreeFilterOptions") ); } @@ -1057,6 +1061,7 @@ JS; } } + $oldID = $record->ID; $record->delete(); $record->destroy(); @@ -1066,13 +1071,14 @@ JS; $liveRecord = Versioned::get_one_by_stage( $this->stat('tree_class'), 'Live', "\"{$this->stat('tree_class')}\".\"ID\"={$id}"); if($liveRecord) { - $title = Convert::raw2js($record->TreeTitle()); - FormResponse::add("$('sitetree').setNodeTitle($record->OldID, '$title');"); - FormResponse::add("$('Form_EditForm').reloadIfSetTo($record->OldID);"); + $liveRecord->IsDeletedFromStage = true; + $title = Convert::raw2js($liveRecord->TreeTitle()); + FormResponse::add("$('sitetree').setNodeTitle($oldID, '$title');"); + FormResponse::add("$('Form_EditForm').reloadIfSetTo($oldID);"); } else { FormResponse::add("var node = $('sitetree').getTreeNodeByIdx('$id');"); FormResponse::add("if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node);"); - FormResponse::add("$('Form_EditForm').reloadIfSetTo($record->OldID);"); + FormResponse::add("$('Form_EditForm').reloadIfSetTo($oldID);"); } } } @@ -1483,4 +1489,4 @@ function cmsMainMarkingFilterFunction($node) { } } -?> \ No newline at end of file +?> diff --git a/code/CommentAdmin.php b/code/CommentAdmin.php index 32604b4d..bffd2383 100644 --- a/code/CommentAdmin.php +++ b/code/CommentAdmin.php @@ -71,11 +71,13 @@ class CommentAdmin extends LeftAndMain { "Name" => _t('CommentAdmin.AUTHOR', 'Author'), "Comment" => _t('CommentAdmin.COMMENT', 'Comment'), "Parent.Title" => _t('CommentAdmin.PAGE', 'Page'), + "CommenterURL" => _t('CommentAdmin.COMMENTERURL', 'URL'), "Created" => _t('CommentAdmin.DATEPOSTED', 'Date Posted') ); $popupFields = new FieldSet( new TextField('Name', _t('CommentAdmin.NAME', 'Name')), + new TextField('CommenterURL', _t('CommentAdmin.COMMENTERURL', 'URL')), new TextareaField('Comment', _t('CommentAdmin.COMMENT', 'Comment')) ); @@ -290,4 +292,4 @@ JS; } } -?> \ No newline at end of file +?> diff --git a/code/CommentTableField.php b/code/CommentTableField.php index 4882228b..6aff494d 100644 --- a/code/CommentTableField.php +++ b/code/CommentTableField.php @@ -23,8 +23,14 @@ class CommentTableField extends ComplexTableField { if(!empty($_REQUEST['CommentSearch'])) { $this->sourceFilter[] = "( \"Name\" LIKE '%$search%' OR \"Comment\" LIKE '%$search%')"; } + } + + function FieldHolder() { + $ret = parent::FieldHolder(); Requirements::javascript(CMS_DIR . '/javascript/CommentTableField.js'); + + return $ret; } function Items() { @@ -138,8 +144,10 @@ class CommentTableField extends ComplexTableField { } function SearchForm() { + $query = isset($_GET['CommentSearch']) ? $_GET['CommentSearch'] : null; + $searchFields = new FieldGroup( - new TextField('CommentSearch', _t('CommentTableField.SEARCH', 'Search')), + new TextField('CommentSearch', _t('CommentTableField.SEARCH', 'Search'), $query), new HiddenField("ctf[ID]",'',$this->mode), new HiddenField('CommentFieldName','',$this->name) ); diff --git a/code/LeftAndMain.php b/code/LeftAndMain.php index 1405b5f2..76bd3796 100644 --- a/code/LeftAndMain.php +++ b/code/LeftAndMain.php @@ -182,6 +182,7 @@ class LeftAndMain extends Controller { Requirements::javascript(THIRDPARTY_DIR . '/hover.js'); Requirements::javascript(THIRDPARTY_DIR . '/layout_helpers.js'); Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang'); + Requirements::add_i18n_javascript(CMS_DIR . '/javascript/lang'); Requirements::javascript(THIRDPARTY_DIR . '/scriptaculous/effects.js'); Requirements::javascript(THIRDPARTY_DIR . '/scriptaculous/dragdrop.js'); @@ -496,7 +497,7 @@ class LeftAndMain extends Controller { public function returnItemToUser($p) { if(Director::is_ajax()) { // Prepare the object for insertion. - $parentID = (int)$p->ParentID; + $parentID = (int) $p->ParentID; $id = $p->ID ? $p->ID : "new-$p->class-$p->ParentID"; $treeTitle = Convert::raw2js($p->TreeTitle()); $hasChildren = (is_numeric($id) && $p->AllChildren() && $p->AllChildren()->Count()) ? ' unexpanded' : ''; @@ -506,7 +507,9 @@ class LeftAndMain extends Controller { var tree = $('sitetree'); var newNode = tree.createTreeNode("$id", "$treeTitle", "{$p->class}{$hasChildren}"); node = tree.getTreeNodeByIdx($parentID); - if(!node){ node = tree.getTreeNodeByIdx(0); } + if(!node) { + node = tree.getTreeNodeByIdx(0); + } node.open(); node.appendTreeNode(newNode); newNode.selectTreeNode(); @@ -515,12 +518,10 @@ JS; return FormResponse::respond(); } else { - Director::redirect("admin/show/" . $p->ID); + Director::redirect('admin/' . self::$url_segment . '/show/' . $p->ID); } - } - /** * Save and Publish page handler */ @@ -844,7 +845,7 @@ JS; } public function EditForm() { - if(isset($_REQUEST['ID'])) { + if(isset($_REQUEST['ID']) && is_numeric($_REQUEST['ID'])) { $record = DataObject::get_by_id($this->stat('tree_class'), $_REQUEST['ID']); } else { $record = $this->CurrentPage(); diff --git a/code/MemberTableField.php b/code/MemberTableField.php index ce7b49de..78f63657 100755 --- a/code/MemberTableField.php +++ b/code/MemberTableField.php @@ -98,8 +98,8 @@ class MemberTableField extends ComplexTableField { } elseif(is_numeric($group)) { $this->group = DataObject::get_by_id('Group', $group); } - } elseif(is_numeric($_REQUEST['ctf'][$this->Name()]['ID'])) { - $this->group = DataObject::get_by_id('Group', $_REQUEST['ctf'][$this->Name()]['ID']); + } else if(isset($_REQUEST['ctf']) && is_numeric($_REQUEST['ctf'][$this->Name()]["ID"])) { + $this->group = DataObject::get_by_id('Group', $_REQUEST['ctf'][$this->Name()]["ID"]); } foreach(self::$addedFields as $key => $value) { @@ -119,9 +119,6 @@ class MemberTableField extends ComplexTableField { } parent::__construct($controller, $name, $sourceClass, $fieldList); - - Requirements::javascript(CMS_DIR . '/javascript/MemberTableField.js'); - Requirements::javascript(CMS_DIR . '/javascript/MemberTableField_popup.js'); $SQL_search = isset($_REQUEST['MemberSearch']) ? Convert::raw2sql($_REQUEST['MemberSearch']) : null; if(!empty($_REQUEST['MemberSearch'])) { @@ -136,9 +133,18 @@ class MemberTableField extends ComplexTableField { $this->setFieldListCsv($csvFieldList); $this->setPageSize($this->stat('page_size')); } + + function FieldHolder() { + $ret = parent::FieldHolder(); + + Requirements::javascript(CMS_DIR . '/javascript/MemberTableField.js'); + Requirements::javascript(CMS_DIR . "/javascript/MemberTableField_popup.js"); + + return $ret; + } function sourceID() { - return $this->group->ID; + return ($this->group) ? $this->group->ID : 0; } function AddLink() { @@ -146,9 +152,12 @@ class MemberTableField extends ComplexTableField { } function SearchForm() { + $groupID = (isset($this->group)) ? $this->group->ID : 0; + $query = isset($_GET['MemberSearch']) ? $_GET['MemberSearch'] : null; + $searchFields = new FieldGroup( - new TextField('MemberSearch', _t('MemberTableField.SEARCH', 'Search')), - new HiddenField('ctf[ID]', '', $this->group->ID), + new TextField('MemberSearch', _t('MemberTableField.SEARCH', 'Search'), $query), + new HiddenField("ctf[ID]", '', $groupID), new HiddenField('MemberFieldName', '', $this->name), new HiddenField('MemberDontShowPassword', '', $this->hidePassword) ); @@ -290,8 +299,9 @@ class MemberTableField extends ComplexTableField { $fields->push(new TextField($fieldName)); } } - $fields->push(new HiddenField('ctf[ID]', null, $this->group->ID)); - + if($this->group) { + $fields->push(new HiddenField('ctf[ID]', null, $this->group->ID)); + } $actions = new FieldSet( new FormAction('addtogroup', _t('MemberTableField.ADD','Add')) ); @@ -358,14 +368,16 @@ class MemberTableField extends ComplexTableField { // We use the group to get the members, as they already have the bulk of the look up functions $start = isset($_REQUEST['ctf'][$this->Name()]['start']) ? $_REQUEST['ctf'][$this->Name()]['start'] : 0; - - $this->sourceItems = $this->group->Members( - $this->pageSize, // limit - $start, // offset - $this->sourceFilter, - $this->sourceSort - ); + $this->sourceItems = false; + if($this->group) { + $this->sourceItems = $this->group->Members( + $this->pageSize, // limit + $start, // offset + $this->sourceFilter, + $this->sourceSort + ); + } // Because we are not used $this->upagedSourceItems any more, and the DataObjectSet is usually the source // that a large member set runs out of memory. we disable it here. //$this->unpagedSourceItems = $this->group->Members('', '', $this->sourceFilter, $this->sourceSort); @@ -395,11 +407,13 @@ class MemberTableField extends ComplexTableField { */ class MemberTableField_Popup extends ComplexTableField_Popup { - function __construct($controller, $name, $fields, $sourceClass, $readonly=false, $validator = null) { - parent::__construct($controller, $name, $fields, $sourceClass, $readonly, $validator); - + function forTemplate() { + $ret = parent::forTemplate(); + Requirements::javascript(CMS_DIR . '/javascript/MemberTableField.js'); Requirements::javascript(CMS_DIR . '/javascript/MemberTableField_popup.js'); + + return $ret; } } diff --git a/code/ModelAdmin.php b/code/ModelAdmin.php index 2b004107..2b16320a 100644 --- a/code/ModelAdmin.php +++ b/code/ModelAdmin.php @@ -128,8 +128,8 @@ abstract class ModelAdmin extends LeftAndMain { Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery/plugins/livequery/jquery.livequery.js'); - Requirements::javascript(THIRDPARTY_DIR . '/jquery/ui/ui.core.js'); - Requirements::javascript(THIRDPARTY_DIR . '/jquery/ui/ui.tabs.js'); + //Requirements::javascript(THIRDPARTY_DIR . '/jquery/ui/ui.core.js'); + //Requirements::javascript(THIRDPARTY_DIR . '/jquery/ui/ui.tabs.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery/plugins/form/jquery.form.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery/plugins/effen/jquery.fn.js'); Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery_improvements.js'); @@ -332,7 +332,7 @@ class ModelAdmin_CollectionController extends Controller { $form = new Form($this, "SearchForm", $fields, new FieldSet( - new FormAction('search', _t('MemberTableField.SEARCH')), + new FormAction('search', _t('MemberTableField.SEARCH', 'Search')), $clearAction = new ResetFormAction('clearsearch', _t('ModelAdmin.CLEAR_SEARCH','Clear Search')) ), $validator diff --git a/code/SecurityAdmin.php b/code/SecurityAdmin.php index a5833310..586a6ba7 100644 --- a/code/SecurityAdmin.php +++ b/code/SecurityAdmin.php @@ -42,16 +42,20 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { Requirements::css(THIRDPARTY_DIR . "/greybox/greybox.css"); Requirements::css(SAPPHIRE_DIR . "/css/ComplexTableField.css"); - Requirements::javascript(CMS_DIR . "/javascript/SecurityAdmin.js"); - Requirements::javascript(CMS_DIR . "/javascript/SecurityAdmin_left.js"); - Requirements::javascript(CMS_DIR . "/javascript/SecurityAdmin_right.js"); - + Requirements::javascript(CMS_DIR . '/javascript/SecurityAdmin_left.js'); + Requirements::javascript(CMS_DIR . '/javascript/SecurityAdmin_right.js'); + Requirements::javascript(THIRDPARTY_DIR . "/greybox/AmiJS.js"); Requirements::javascript(THIRDPARTY_DIR . "/greybox/greybox.js"); } public function getEditForm($id) { - $record = DataObject::get_by_id($this->stat('tree_class'), $id); + $record = null; + + if($id && $id != 'root') { + $record = DataObject::get_by_id($this->stat('tree_class'), $id); + } + if(!$record) return false; $fields = $record->getCMSFields(); @@ -197,9 +201,11 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { $memberID = $this->urlParams['OtherID']; if(is_numeric($groupID) && is_numeric($memberID)) { $member = DataObject::get_by_id('Member', (int) $memberID); + if(!$member->canDelete()) return Security::permissionFailure($this); - + $member->Groups()->remove((int)$groupID); + FormResponse::add("reloadMemberTableField();"); } else { user_error("SecurityAdmin::removememberfromgroup: Bad parameters: Group=$groupID, Member=$memberID", E_USER_ERROR); @@ -209,24 +215,32 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { } /** - * Return the entire site tree as a nested set of ULs + * Return the entire site tree as a nested set of ULs. + * @return string Unordered list