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() {