diff --git a/_config/routes.yml b/_config/routes.yml index 1baa48fb..deed433b 100644 --- a/_config/routes.yml +++ b/_config/routes.yml @@ -1,6 +1,7 @@ --- Name: modelascontrollerroutes -After: framework/routes#rootroutes +Before: '*' +After: '#rootroutes' --- Director: rules: @@ -8,8 +9,8 @@ Director: '$URLSegment//$Action/$ID/$OtherID': 'ModelAsController' --- Name: legacycmsroutes -After: '*' +After: '#adminroutes' --- Director: rules: - 'admin/cms': '->admin/pages' \ No newline at end of file + 'admin/cms': '->admin/pages' diff --git a/code/controllers/AssetAdmin.php b/code/controllers/AssetAdmin.php index e71e6498..0fd1beab 100644 --- a/code/controllers/AssetAdmin.php +++ b/code/controllers/AssetAdmin.php @@ -95,7 +95,7 @@ JS // Don't filter list when a detail view is requested, // to avoid edge cases where the filtered list wouldn't contain the requested // record due to faulty session state (current folder not always encoded in URL, see #7408). - if($this->request->param('ID') == 'field') { + if(!$folder->ID && ($this->request->param('ID') == 'field')) { return $list; } @@ -336,6 +336,7 @@ JS 'mov' => _t('AssetAdmin.AppCategoryVideo', 'Video'), 'flash' => _t('AssetAdmin.AppCategoryFlash', 'Flash', 'The fileformat'), 'zip' => _t('AssetAdmin.AppCategoryArchive', 'Archive', 'A collection of files'), + 'doc' => _t('AssetAdmin.AppCategoryDocument', 'Document') ); $context->addField( $typeDropdown = new DropdownField( diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index 8672db4b..aa3612db 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -247,8 +247,11 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr function SearchForm() { // get all page types in a dropdown-compatible format - $pageTypes = SiteTree::page_type_classes(); - $pageTypes = array_combine($pageTypes, $pageTypes); + $pageTypeClasses = SiteTree::page_type_classes(); + $pageTypes = array(); + foreach ($pageTypeClasses as $pageTypeClass) { + $pageTypes[$pageTypeClass] = _t($pageTypeClass.'.SINGULARNAME', $pageTypeClass); + } asort($pageTypes); // get all filter instances @@ -284,7 +287,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr ) // new TextField('MetaTags', _t('CMSMain.SearchMetaTags', 'Meta tags')) ); - $dateGroup->subfieldParam = 'FieldHolder'; + $dateGroup->setFieldHolderTemplate('FieldGroup_DefaultFieldHolder')->addExtraClass('stacked'); $dateFrom->setConfig('showcalendar', true); $dateTo->setConfig('showcalendar', true); $classDropdown->setEmptyString(_t('CMSMain.PAGETYPEANYOPT','Any')); @@ -573,20 +576,18 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $fields->push($idField = new HiddenField("ID", false, $id)); // Necessary for different subsites - $fields->push($liveURLField = new HiddenField("AbsoluteLink", false, $record->AbsoluteLink())); - $fields->push($liveURLField = new HiddenField("LiveURLSegment")); - $fields->push($stageURLField = new HiddenField("StageURLSegment")); + $fields->push($liveLinkField = new HiddenField("AbsoluteLink", false, $record->AbsoluteLink())); + $fields->push($liveLinkField = new HiddenField("LiveLink")); + $fields->push($stageLinkField = new HiddenField("StageLink")); $fields->push(new HiddenField("TreeTitle", false, $record->TreeTitle)); - $fields->push(new HiddenField('Sort','', $record->Sort)); - if($record->ID && is_numeric( $record->ID ) ) { - $liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree\".\"ID\" = $record->ID"); - if($liveRecord) $liveURLField->setValue($liveRecord->AbsoluteLink()); - } - - if(!$deletedFromStage) { - $stageURLField->setValue(Controller::join_links($record->AbsoluteLink(), '?stage=Stage')); + $liveLink = $record->getAbsoluteLiveLink(); + if($liveLink) $liveLinkField->setValue($liveLink); + if(!$deletedFromStage) { + $stageLink = Controller::join_links($record->AbsoluteLink(), '?stage=Stage'); + if($stageLink) $stageLinkField->setValue($stageLink); + } } // Added in-line to the form, but plucked into different view by LeftAndMain.Preview.js upon load @@ -615,7 +616,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $form = new Form($this, "EditForm", $fields, $actions, $validator); $form->loadDataFrom($record); - $stageURLField->setValue(Controller::join_links($record->getStageURLSegment(), '?stage=Stage')); $form->disableDefaultAction(); $form->addExtraClass('cms-edit-form'); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); @@ -703,6 +703,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr 'Created' => _t('SiteTree.CREATED', 'Date Created'), 'LastEdited' => _t('SiteTree.LASTUPDATED', 'Last Updated'), ); + $gridField->getConfig()->getComponentByType('GridFieldSortableHeader')->setFieldSorting(array('getTreeTitle' => 'Title')); if(!$params) { $fields = array_merge(array('listChildrenLink' => ''), $fields); @@ -783,7 +784,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr $record->HasBrokenLink = 0; $record->HasBrokenFile = 0; - $record->writeWithoutVersion(); + if (!$record->ObsoleteClassName) $record->writeWithoutVersion(); // Update the class instance if necessary if(isset($data['ClassName']) && $data['ClassName'] != $record->ClassName) { @@ -1061,8 +1062,12 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr // Can be used in different contexts: In normal page edit view, in which case the redirect won't have any effect. // Or in history view, in which case a revert causes the CMS to re-load the edit view. + // The X-Pjax header forces a "full" content refresh on redirect. $url = Controller::join_links(singleton('CMSPageEditController')->Link('show'), $record->ID); $this->response->addHeader('X-ControllerURL', $url); + $this->request->addHeader('X-Pjax', 'Content'); + $this->response->addHeader('X-Pjax', 'Content'); + return $this->getResponseNegotiator()->respond($this->request); } diff --git a/code/controllers/CMSPageEditController.php b/code/controllers/CMSPageEditController.php index 5027f6d9..05df5f2d 100644 --- a/code/controllers/CMSPageEditController.php +++ b/code/controllers/CMSPageEditController.php @@ -9,4 +9,6 @@ class CMSPageEditController extends CMSMain { static $url_rule = '/$Action/$ID/$OtherID'; static $url_priority = 41; static $required_permission_codes = 'CMS_ACCESS_CMSMain'; + static $session_namespace = 'CMSMain'; + } diff --git a/code/controllers/CMSPageHistoryController.php b/code/controllers/CMSPageHistoryController.php index 3a076b65..43251753 100644 --- a/code/controllers/CMSPageHistoryController.php +++ b/code/controllers/CMSPageHistoryController.php @@ -11,6 +11,7 @@ class CMSPageHistoryController extends CMSMain { static $url_priority = 42; static $menu_title = 'History'; static $required_permission_codes = 'CMS_ACCESS_CMSMain'; + static $session_namespace = 'CMSMain'; static $allowed_actions = array( 'VersionsForm', diff --git a/code/controllers/CMSPageSettingsController.php b/code/controllers/CMSPageSettingsController.php index d8ff7d4d..592cad29 100644 --- a/code/controllers/CMSPageSettingsController.php +++ b/code/controllers/CMSPageSettingsController.php @@ -9,6 +9,7 @@ class CMSPageSettingsController extends CMSMain { static $url_rule = '/$Action/$ID/$OtherID'; static $url_priority = 42; static $required_permission_codes = 'CMS_ACCESS_CMSMain'; + static $session_namespace = 'CMSMain'; function getEditForm($id = null, $fields = null) { $record = $this->getRecord($id ? $id : $this->currentPageID()); diff --git a/code/controllers/CMSPagesController.php b/code/controllers/CMSPagesController.php index 5f401d7a..56aa2687 100644 --- a/code/controllers/CMSPagesController.php +++ b/code/controllers/CMSPagesController.php @@ -10,6 +10,7 @@ class CMSPagesController extends CMSMain { static $url_priority = 40; static $menu_title = 'Pages'; static $required_permission_codes = 'CMS_ACCESS_CMSMain'; + static $session_namespace = 'CMSMain'; function LinkPreview() { return false; @@ -22,14 +23,6 @@ class CMSPagesController extends CMSMain { return $this->request->getVar('view'); } - /** - * Doesn't deal with a single record, and we need - * to avoid session state from previous record edits leaking in here. - */ - public function currentPageID() { - return false; - } - public function isCurrentPage(DataObject $record) { return false; } diff --git a/code/controllers/CMSSiteTreeFilter.php b/code/controllers/CMSSiteTreeFilter.php index d75ebfbe..25067baa 100644 --- a/code/controllers/CMSSiteTreeFilter.php +++ b/code/controllers/CMSSiteTreeFilter.php @@ -71,13 +71,15 @@ abstract class CMSSiteTreeFilter extends Object { $parents[$pageArr['ParentID']] = true; $this->_cache_ids[$pageArr['ID']] = true; } - - if(!empty($parents)) { + + while(!empty($parents)) { $q = new SQLQuery(); $q->setSelect(array('"ID"','"ParentID"')) ->setFrom('"SiteTree"') ->setWhere('"ID" in ('.implode(',',array_keys($parents)).')'); + $parents = array(); + foreach($q->execute() as $row) { if ($row['ParentID']) $parents[$row['ParentID']] = true; $this->_cache_ids[$row['ID']] = true; @@ -194,11 +196,13 @@ class CMSSiteTreeFilter_Search extends CMSSiteTreeFilter { break; case 'LastEditedFrom': - $query->where("\"LastEdited\" >= '$SQL_val'"); + $fromDate = new DateField(null, null, $SQL_val); + $query->where("\"LastEdited\" >= '{$fromDate->dataValue()}'"); break; case 'LastEditedTo': - $query->where("\"LastEdited\" <= '$SQL_val'"); + $toDate = new DateField(null, null, $SQL_val); + $query->where("\"LastEdited\" <= '{$toDate->dataValue()}'"); break; case 'ClassName': diff --git a/code/controllers/ContentController.php b/code/controllers/ContentController.php index 847a54a8..a098365d 100644 --- a/code/controllers/ContentController.php +++ b/code/controllers/ContentController.php @@ -314,7 +314,7 @@ class ContentController extends Controller {
-
$viewPageIn
+ $viewPageIn $items
@@ -401,7 +401,7 @@ HTML; )); return array( - "Title" => DBField::create_field('Varchar', "Title", "Installation Successful"), + "Title" => _t("ContentController.INSTALL_SUCCESS", "Installation Successful!"), "Content" => $data->renderWith('Install_successfullyinstalled'), ); } diff --git a/code/controllers/SilverStripeNavigator.php b/code/controllers/SilverStripeNavigator.php index e8e07ab8..d202ac6d 100644 --- a/code/controllers/SilverStripeNavigator.php +++ b/code/controllers/SilverStripeNavigator.php @@ -320,7 +320,7 @@ class SilverStripeNavigatorItem_ArchiveLink extends SilverStripeNavigatorItem { } function getLink() { - return $this->record->AbsoluteLink() . '?archiveDate=' . $date; + return $this->record->AbsoluteLink() . '?archiveDate=' . $this->record->LastEdited; } function canView($member = null) { diff --git a/code/model/SiteConfig.php b/code/model/SiteConfig.php index 89ea9a85..b7573d88 100644 --- a/code/model/SiteConfig.php +++ b/code/model/SiteConfig.php @@ -1,15 +1,8 @@ Title = _t('SiteConfig.SITENAMEDEFAULT', "Your Site Name"); + $this->Tagline = _t('SiteConfig.TAGLINEDEFAULT', "your tagline here"); + + // Allow these defaults to be overridden + parent::populateDefaults(); + } + /** * Get the fields that are sent to the CMS. In * your extensions: updateCMSFields($fields) @@ -84,13 +86,6 @@ class SiteConfig extends DataObject implements PermissionProvider { $topLevelCreatorsOptionsField->setSource($editorsOptionsSource); - // Translatable doesn't handle updateCMSFields on DataObjects, - // so add it here to save the current Locale, - // because onBeforeWrite does not work. - if(class_exists('Translatable') && Object::has_extension('SiteConfig',"Translatable")){ - $fields->push(new HiddenField("Locale")); - } - if (!Permission::check('EDIT_SITECONFIG')) { $fields->makeFieldReadonly($viewersOptionsField); $fields->makeFieldReadonly($viewerGroupsField); @@ -161,22 +156,14 @@ class SiteConfig extends DataObject implements PermissionProvider { * Get the current sites SiteConfig, and creates a new one * through {@link make_site_config()} if none is found. * - * @param string $locale * @return SiteConfig */ - static function current_site_config($locale = null) { - if(class_exists('Translatable') && Object::has_extension('SiteConfig',"Translatable")){ - $locale = isset($locale) ? $locale : Translatable::get_current_locale(); - $siteConfig = Translatable::get_one_by_locale('SiteConfig', $locale); - } else { - $siteConfig = DataObject::get_one('SiteConfig'); - } + static function current_site_config() { + if ($siteConfig = DataObject::get_one('SiteConfig')) return $siteConfig; - if (!$siteConfig) $siteConfig = self::make_site_config($locale); - - return $siteConfig; + return self::make_site_config(); } - + /** * Setup a default SiteConfig record if none exists */ @@ -191,39 +178,16 @@ class SiteConfig extends DataObject implements PermissionProvider { /** * Create SiteConfig with defaults from language file. - * if Translatable is enabled on SiteConfig, see if one already exist - * and use those values for the translated defaults. * * @param string $locale * @return SiteConfig */ - static function make_site_config($locale = null) { - if(class_exists('Translatable') && !$locale) $locale = Translatable::get_current_locale(); - - $siteConfig = new SiteConfig(); - $siteConfig->Title = _t('SiteConfig.SITENAMEDEFAULT',"Your Site Name"); - $siteConfig->Tagline = _t('SiteConfig.TAGLINEDEFAULT',"your tagline here"); + static function make_site_config() { + $config = SiteConfig::create(); + $config->write(); + return $config; + } - if(class_exists('Translatable') && $siteConfig->hasExtension('Translatable')){ - Translatable::disable_locale_filter(); - $defaultConfig = SiteConfig::get()->first(); - Translatable::enable_locale_filter(); - - if($defaultConfig){ - return $defaultConfig->createTranslation($locale); - } - - // TODO Copy view/edit group settings - - // set the correct Locale - $siteConfig->Locale = $locale; - } - - $siteConfig->write(); - - return $siteConfig; - } - /** * Can a user view pages on this site? This method is only * called if a page is set to Inherit, but there is nothing diff --git a/code/model/SiteTree.php b/code/model/SiteTree.php index b4a25ef7..16d510a2 100644 --- a/code/model/SiteTree.php +++ b/code/model/SiteTree.php @@ -455,18 +455,18 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * Get the absolute URL for this page on the Live site. */ public function getAbsoluteLiveLink($includeStageEqualsLive = true) { + $oldStage = Versioned::current_stage(); + Versioned::reading_stage('Live'); $live = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $this->ID); - if($live) { $link = $live->AbsoluteLink(); - - if($includeStageEqualsLive) { - $link .= '?stage=Live'; - } - - return $link; - + if($includeStageEqualsLive) $link .= '?stage=Live'; + } else { + $link = null; } + + Versioned::reading_stage($oldStage); + return $link; } /** @@ -991,17 +991,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * Stub method to get the site config, provided so it's easy to override */ function getSiteConfig() { - $altConfig = false; + if($this->hasMethod('alternateSiteConfig')) { $altConfig = $this->alternateSiteConfig(); + if($altConfig) return $altConfig; } - if($altConfig) { - return $altConfig; - } elseif(class_exists('Translatable') && $this->hasExtension('Translatable')) { - return SiteConfig::current_site_config($this->Locale); - } else { - return SiteConfig::current_site_config(); - } + + return SiteConfig::current_site_config(); } /** @@ -1511,7 +1507,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid // deconstructs any inheritance trees already. $allowed = $parent->allowedChildren(); $subject = ($this instanceof VirtualPage) ? $this->CopyContentFrom() : $this; - if($subject->ID && !in_array($subject->ClassName, $allowed)) { + if(!in_array($subject->ClassName, $allowed)) { $result->error( _t( @@ -1803,7 +1799,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if($this->HasBrokenLink || $this->HasBrokenFile) { $statusMessage[] = _t('SiteTree.HASBROKENLINKS', "This page has broken links."); } - + $dependentNote = ''; $dependentTable = new LiteralField('DependentNote', '

'); @@ -1877,6 +1873,20 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid $tabMain->setTitle(_t('SiteTree.TABCONTENT', "Main Content")); + if($this->ObsoleteClassName) { + $obsoleteWarning = _t( + 'SiteTree.OBSOLETECLASS', + "This page is of obsolete type {type}. Saving will reset it's type and you may lose data", + array('type' => $this->ObsoleteClassName) + ); + + $fields->addFieldToTab( + "Root.Main", + new LiteralField("ObsoleteWarningHeader", "

$obsoleteWarning

"), + "Title" + ); + } + if(file_exists(BASE_PATH . '/install.php')) { $fields->addFieldToTab("Root.Main", new LiteralField("InstallWarningHeader", "

" . _t("SiteTree.REMOVE_INSTALL_WARNING", diff --git a/css/SilverStripeNavigator.css b/css/SilverStripeNavigator.css new file mode 100644 index 00000000..24d390cc --- /dev/null +++ b/css/SilverStripeNavigator.css @@ -0,0 +1,25 @@ +#SilverStripeNavigator { position: fixed; bottom: 0; left: 0; width: 100%; border-top: 2px solid #d4d0c8; background-color: #81858d; height: 22px; } + +#SilverStripeNavigator * { font-family: Arial,Helvetica,sans-serif; font-size: 10px !important; } + +#SilverStripeNavigator .holder { text-align: center; padding-top: 4px; padding-left: 3px; padding-right: 6px; color: white; border-top: 1px solid #555555; } + +#SilverStripeNavigator #logInStatus { float: right; } + +#SilverStripeNavigator #switchView { float: left; } + +#SilverStripeNavigator a { color: #fff; background-color: transparent; text-decoration: underline; } + +#SilverStripeNavigator a:hover { background-color: transparent; } + +#SilverStripeNavigator .bottomTabs a { margin-right: 8px; text-decoration: underline; } + +#SilverStripeNavigator .bottomTabs a.current { font-weight: bold; text-decoration: none; } + +#SilverStripeNavigatorMessage { font-family: 'Lucida Grande', Verdana, Arial, 'sans-serif'; position: absolute; right: 20px; top: 40px; padding: 10px; border-color: #c99; color: #fff; background-color: #c00; border: 1px solid #000; } + +#SilverStripeNavigatorLinkPopup { display: none; position: absolute; top: -60px; height: 50px; width: 350px; left: 200px; background-color: white; border: 1px solid black; z-index: 100; color: black; padding: 5px; } + +#SilverStripeNavigatorLinkPopup input { width: 250px; } + +#SilverStripeNavigatorLinkPopup a.close { color: blue; text-align: right; width: 80%; border: none !important; cursor: pointer; } diff --git a/css/screen.css b/css/screen.css index bcf6069d..677cb1a0 100644 --- a/css/screen.css +++ b/css/screen.css @@ -21,7 +21,7 @@ .cms-content-tools #cms-content-treeview .cms-tree a:hover > .text > .badge, .cms-content-tools #cms-content-treeview .cms-tree .jstree-clicked > .text > .badge { display: inline-block; } /** ------------------------------------------------------------------ URLSegment field ----------------------------------------------------------------- */ -.field.urlsegment.disabled { color: #444; padding-left: 0px; margin-left: 0px; background: none; border-color: transparent; } +.field.urlsegment.loading { background: url(../images/loading.gif) no-repeat 162px 8px; } .field.urlsegment .prefix, .field.urlsegment .preview { padding-top: 8px; display: inline-block; } .field.urlsegment .prefix { color: #777; } .field.urlsegment .cancel, .field.urlsegment .update, .field.urlsegment .edit { margin-left: 7px; } @@ -41,7 +41,7 @@ .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-state-active.content-treeview a, .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active.content-treeview a, .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active.content-treeview a { background-position: 1px -40px; } .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-state-active.content-galleryview a, .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active.content-galleryview a, .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active.content-galleryview a { background-position: -161px -40px; } .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-state-active.content-listview a, .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active.content-listview a, .cms .AssetAdmin .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active.content-listview a { background-position: -38px -40px; } -.cms .AssetAdmin .cms-content-toolbar .cms-page-add-button { background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f3f3f3), color-stop(100%, #d9d9d9)); background-image: -webkit-linear-gradient(#f3f3f3, #d9d9d9); background-image: -moz-linear-gradient(#f3f3f3, #d9d9d9); background-image: -o-linear-gradient(#f3f3f3, #d9d9d9); background-image: -ms-linear-gradient(#f3f3f3, #d9d9d9); background-image: linear-gradient(#f3f3f3, #d9d9d9); border-color: #c0c0c2; } +.cms .AssetAdmin .cms-content-toolbar .cms-page-add-button { background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f3f3f3), color-stop(100%, #d9d9d9)); background-image: -webkit-linear-gradient(#f3f3f3, #d9d9d9); background-image: -moz-linear-gradient(#f3f3f3, #d9d9d9); background-image: -o-linear-gradient(#f3f3f3, #d9d9d9); background-image: linear-gradient(#f3f3f3, #d9d9d9); border-color: #c0c0c2; } .cms .AssetAdmin .cms-content-toolbar .cms-page-add-button span.btn-icon-add { height: 17px; } .cms .AssetAdmin .cms-content-toolbar .cms-page-add-button span.ui-button-text { color: #393939; text-shadow: white 0 1px 1px; } .cms .AssetAdmin #Root_TreeView .cms-tree ul .class-Folder a span.text span.jstree-foldericon { background: url(../images/blue-folder-horizontal.png) no-repeat; width: 16px; height: 16px; float: left; display: block; margin-right: 4px; } diff --git a/images/loading.gif b/images/loading.gif new file mode 100644 index 00000000..e21f078c Binary files /dev/null and b/images/loading.gif differ diff --git a/javascript/CMSMain.Tree.js b/javascript/CMSMain.Tree.js index 49d522ac..73b41c5c 100644 --- a/javascript/CMSMain.Tree.js +++ b/javascript/CMSMain.Tree.js @@ -41,11 +41,6 @@ if(allowedChildren.hasOwnProperty('allowedchildren-0')) { menuitems['addsubpage'] = { 'label': ss.i18n._t('Tree.AddSubPage'), - 'action': function(obj) { - $('.cms-container').entwine('.ss').loadPanel(ss.i18n.sprintf( - self.data('urlAddpage'), id, 'Page' - )); - }, 'submenu': allowedChildren }; } diff --git a/javascript/SiteTreeURLSegmentField.js b/javascript/SiteTreeURLSegmentField.js index 2605ac5a..fc0a183b 100644 --- a/javascript/SiteTreeURLSegmentField.js +++ b/javascript/SiteTreeURLSegmentField.js @@ -94,10 +94,12 @@ } if (currentVal != updateVal) { + self.addClass('loading'); self.suggest(updateVal, function(data) { var newVal = decodeURIComponent(data.value); field.val(newVal); self.edit(title); + self.removeClass('loading'); }); } else { self.edit(); diff --git a/javascript/lang/sv_SE.js b/javascript/lang/sv_SE.js new file mode 100644 index 00000000..eef22abb --- /dev/null +++ b/javascript/lang/sv_SE.js @@ -0,0 +1,36 @@ +if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') { + if(typeof(console) != 'undefined') console.error('Class ss.i18n not defined'); +} else { + ss.i18n.addDictionary('sv_SE', { + 'CMSMAIN.WARNINGSAVEPAGESBEFOREADDING' : "Du måste spara en sida innan du kan lägga till undersidor.", + 'CMSMAIN.CANTADDCHILDREN' : "Du kan inte lägga till undersidor till den valda sidan.", + 'CMSMAIN.ERRORADDINGPAGE' : 'Ett fel uppstod när sidan skulle läggas till', + 'CMSMAIN.FILTEREDTREE' : 'Filtrerat träd för att visa enbart ändrade sidor', + 'CMSMAIN.ERRORFILTERPAGES' : 'Kunde inte filtrera trädet för att visa enbart ändrade sidor
%s', + 'CMSMAIN.ERRORUNFILTER' : 'Ofiltrerat träd', + 'CMSMAIN.PUBLISHINGPAGES' : 'Publicerar sidor...', + 'CMSMAIN.SELECTONEPAGE' : "Vänligen välj åtminståne 1 sida.", + 'CMSMAIN.ERRORPUBLISHING' : 'Ett fel uppstod när sidorna skulle publiceras', + 'CMSMAIN.REALLYDELETEPAGES' : "Vill du verkligen radera de %s markerade sidorna?", + 'CMSMAIN.DELETINGPAGES' : 'Raderar sidor...', + 'CMSMAIN.ERRORDELETINGPAGES': 'Ett fel uppstod när sidorna skulle raderas', + 'CMSMAIN.PUBLISHING' : 'Publicerar...', + 'CMSMAIN.RESTORING': 'Återställer...', + 'CMSMAIN.ERRORREVERTING': 'Ett fel uppstod vid återgång till publicerat innehåll', + 'CMSMAIN.SAVING' : 'sparar...', + 'CMSMAIN.SELECTMOREPAGES' : "Du har valt %s sidor.\n\nVill du verkligen utföra denna åtgärd?", + 'CMSMAIN.ALERTCLASSNAME': 'Sidtypen kommer att uppdateras efter att sidan sparats', + 'CMSMAIN.URLSEGMENTVALIDATION': 'URLar kan endast innehålla bokstäver, siffror och bindesträck.', + 'AssetAdmin.BATCHACTIONSDELETECONFIRM': "Vill du verkligen radera %s mappar?", + 'AssetTableField.REALLYDELETE': 'Vill du verkligen radera de markerade filerna?', + 'AssetTableField.MOVING': 'Flyttar %s fil(er)', + 'CMSMAIN.AddSearchCriteria': 'Lägg till kriterie', + 'WidgetAreaEditor.TOOMANY': 'Du har tyvärr nått max antal widgetar i detta område.', + 'AssetAdmin.ConfirmDelete': 'Vill du verkligen radera denna mapp och alla filer i den?', + 'Folder.Name': 'Mappnamn', + 'Tree.AddSubPage': 'Lägg till ny sida här', + 'Tree.EditPage': 'Editera', + 'CMSMain.ConfirmRestoreFromLive': "Vill du verkligen kopiera det publicerade innehållet till utkastsajten?", + 'CMSMain.RollbackToVersion': "Vill du verkligen gå tillbaka till version %s av denna sida?" + }); +} diff --git a/lang/en_GB.yml b/lang/en_GB.yml index e959902c..3c1dd1c5 100644 --- a/lang/en_GB.yml +++ b/lang/en_GB.yml @@ -8,6 +8,7 @@ en_GB: AppCategoryFlash: Flash AppCategoryImage: Image AppCategoryVideo: Video + AppCategoryDocument: Document BackToFolder: 'Back to folder' CREATED: Date CurrentFolderOnly: 'Limit to current folder?' diff --git a/lang/fr.yml b/lang/fr.yml index 86236a03..7765d2af 100644 --- a/lang/fr.yml +++ b/lang/fr.yml @@ -8,6 +8,7 @@ fr: AppCategoryFlash: Flash AppCategoryImage: Image AppCategoryVideo: Vidéo + AppCategoryDocument: Document BackToFolder: 'Revenir au dossier' CREATED: Date CurrentFolderOnly: 'Limiter au dossier actuel ?' diff --git a/scss/SilverStripeNavigator.scss b/scss/SilverStripeNavigator.scss new file mode 100644 index 00000000..029bc1bf --- /dev/null +++ b/scss/SilverStripeNavigator.scss @@ -0,0 +1,90 @@ + +#SilverStripeNavigator { + position: fixed; + bottom: 0; + left: 0; + width: 100%; + border-top: 2px solid #d4d0c8; + background-color:#81858d; + height: 22px; +} + +#SilverStripeNavigator * { + font-family: Arial,Helvetica,sans-serif; + font-size: 10px !important; +} + +#SilverStripeNavigator .holder { + text-align: center; + padding-top : 4px; + padding-left : 3px; + padding-right : 6px; + color: white; + border-top: 1px solid #555555; +} +#SilverStripeNavigator #logInStatus { + float: right; +} +#SilverStripeNavigator #switchView { + float: left; + +} + +#SilverStripeNavigator a { + color: #fff; + background-color: transparent; + text-decoration: underline; +} +#SilverStripeNavigator a:hover { + background-color: transparent; +} + +#SilverStripeNavigator .bottomTabs a { + margin-right: 8px; + text-decoration: underline; +} + +#SilverStripeNavigator .bottomTabs a.current { + font-weight:bold; + text-decoration: none; +} + +#SilverStripeNavigatorMessage { + font-family: 'Lucida Grande', Verdana, Arial, 'sans-serif'; + position: absolute; + right: 20px; + top: 40px; + padding: 10px; + border-color: #c99; + color: #fff; + background-color: #c00; + border: 1px solid #000; +} + +#SilverStripeNavigatorLinkPopup { + display: none; + position: absolute; + top: -60px; + height: 50px; + width: 350px; + left: 200px; + background-color: white; + border: 1px solid black; + z-index: 100; + color: black; + padding: 5px; +} + +#SilverStripeNavigatorLinkPopup input { + width: 250px; +} + +#SilverStripeNavigatorLinkPopup a.close { + color: blue; + text-align: right; + width: 80%; + border: none !important; + cursor: pointer; +} + + diff --git a/scss/_CMSMain.scss b/scss/_CMSMain.scss index 0ed6607b..3ee1b5db 100644 --- a/scss/_CMSMain.scss +++ b/scss/_CMSMain.scss @@ -93,12 +93,8 @@ * ----------------------------------------------------------------- */ .field.urlsegment { - &.disabled { - color: #444; - padding-left: 0px; - margin-left: 0px; - background: none; - border-color: transparent; + &.loading { + background: url(../images/loading.gif) no-repeat 162px 8px; } .prefix, diff --git a/templates/Includes/Install_successfullyinstalled.ss b/templates/Includes/Install_successfullyinstalled.ss index c3817ce0..44b01499 100644 --- a/templates/Includes/Install_successfullyinstalled.ss +++ b/templates/Includes/Install_successfullyinstalled.ss @@ -1,17 +1,18 @@ -

- <%t ContentController.InstallSuccessCongratulations "SilverStripe has been successfully installed." %> +

+ <%t ContentController.InstallSuccessCongratulations "SilverStripe has been successfully installed!" %>

<% if Project == 'tutorial' %> - <%t ContentController.PostInstallTutorialIntro 'This website is a simplistic version of a SilverStripe 2 site. To extend this, please take a look at {link}.' link='our new tutorials' %> + <%t ContentController.PostInstallTutorialIntro 'This website is a simplistic version of a SilverStripe 3 site. To extend this, please take a look at {link}.' link='our tutorials' %> <% end_if %> +

    <%t ContentController.Email "Email" %>: $Username
+     <%t ContentController.Password "Password" %>: $Password

+

- <%t ContentController.StartEditing 'You can start editing your site\'s content by opening the CMS.' link="admin/" %> -
-     <%t ContentController.Email "Email" %>: $Username
-     <%t ContentController.Password "Password" %>: $Password
+ <%t ContentController.StartEditing "You can start editing your site's content by opening the CMS." link="admin/" %>

+

diff --git a/tests/controller/CMSMainTest.php b/tests/controller/CMSMainTest.php index 9b0e2fbc..14e5f74c 100644 --- a/tests/controller/CMSMainTest.php +++ b/tests/controller/CMSMainTest.php @@ -4,6 +4,7 @@ * @subpackage tests */ class CMSMainTest extends FunctionalTest { + static $fixture_file = 'CMSMainTest.yml'; protected $autoFollowRedirection = false; @@ -221,6 +222,44 @@ class CMSMainTest extends FunctionalTest { $this->session()->inst_set('loggedInAs', NULL); } + function testCreationOfRestrictedPage(){ + $adminUser = $this->objFromFixture('Member', 'admin'); + $adminUser->logIn(); + + // Create toplevel page + $this->get('admin/pages/add'); + $response = $this->post( + 'admin/pages/add/AddForm', + array('ParentID' => '0', 'PageType' => 'CMSMainTest_ClassA', 'Locale' => 'en_US', 'action_doAdd' => 1) + ); + $this->assertFalse($response->isError()); + preg_match('/edit\/show\/(\d*)/', $response->getHeader('Location'), $matches); + $newPageId = $matches[1]; + + // Create allowed child + $this->get('admin/pages/add'); + $response = $this->post( + 'admin/pages/add/AddForm', + array('ParentID' => $newPageId, 'PageType' => 'CMSMainTest_ClassB', 'Locale' => 'en_US', 'action_doAdd' => 1) + ); + $this->assertFalse($response->isError()); + $this->assertNull($response->getBody()); + + // Create disallowed child + $this->get('admin/pages/add'); + $response = $this->post( + 'admin/pages/add/AddForm', + array('ParentID' => $newPageId, 'PageType' => 'Page', 'Locale' => 'en_US', 'action_doAdd' => 1) + ); + $this->assertFalse($response->isError()); + $this->assertContains( + _t('SiteTree.PageTypeNotAllowed', array('type' => 'Page')), + $response->getBody() + ); + + $this->session()->inst_set('loggedInAs', NULL); + } + function testBreadcrumbs() { $page3 = $this->objFromFixture('Page', 'page3'); $page31 = $this->objFromFixture('Page', 'page31'); @@ -239,3 +278,11 @@ class CMSMainTest extends FunctionalTest { $this->session()->inst_set('loggedInAs', null); } } + +class CMSMainTest_ClassA extends Page implements TestOnly { + static $allowed_children = array('CMSMainTest_ClassB'); +} + +class CMSMainTest_ClassB extends Page implements TestOnly { + +} \ No newline at end of file diff --git a/tests/model/SiteTreeTest.php b/tests/model/SiteTreeTest.php index f8134aa3..c8a74551 100644 --- a/tests/model/SiteTreeTest.php +++ b/tests/model/SiteTreeTest.php @@ -356,6 +356,23 @@ class SiteTreeTest extends SapphireTest { $this->assertEquals('about-us/edit', $about->RelativeLink('edit'), 'Matches URLSegment plus parameter on top level'); $this->assertEquals('about-us/tom&jerry', $about->RelativeLink('tom&jerry'), 'Doesnt url encode parameter'); } + + function testAbsoluteLiveLink() { + $parent = $this->objFromFixture('Page', 'about'); + $child = $this->objFromFixture('Page', 'staff'); + + SiteTree::enable_nested_urls(); + + $child->publish('Stage', 'Live'); + $parent->URLSegment = 'changed-on-live'; + $parent->write(); + $parent->publish('Stage', 'Live'); + $parent->URLSegment = 'changed-on-draft'; + $parent->write(); + + $this->assertStringEndsWith('changed-on-live/my-staff/', $child->getAbsoluteLiveLink(false)); + $this->assertStringEndsWith('changed-on-live/my-staff/?stage=Live', $child->getAbsoluteLiveLink()); + } function testDeleteFromStageOperatesRecursively() { SiteTree::set_enforce_strict_hierarchy(false); diff --git a/tests/model/VirtualPageTest.php b/tests/model/VirtualPageTest.php index ba4ef7ad..cd47dfbb 100644 --- a/tests/model/VirtualPageTest.php +++ b/tests/model/VirtualPageTest.php @@ -10,7 +10,7 @@ class VirtualPageTest extends SapphireTest { ); protected $requiredExtensions = array( - 'Page' => array('VirtualPageTest_PageExtension') + 'SiteTree' => array('VirtualPageTest_PageExtension') ); function setUp() {