Merge remote-tracking branch 'origin/3.0'

This commit is contained in:
Ingo Schommer 2012-09-07 17:21:47 +02:00
commit 5bfb994496
26 changed files with 323 additions and 130 deletions

View File

@ -1,6 +1,7 @@
--- ---
Name: modelascontrollerroutes Name: modelascontrollerroutes
After: framework/routes#rootroutes Before: '*'
After: '#rootroutes'
--- ---
Director: Director:
rules: rules:
@ -8,7 +9,7 @@ Director:
'$URLSegment//$Action/$ID/$OtherID': 'ModelAsController' '$URLSegment//$Action/$ID/$OtherID': 'ModelAsController'
--- ---
Name: legacycmsroutes Name: legacycmsroutes
After: '*' After: '#adminroutes'
--- ---
Director: Director:
rules: rules:

View File

@ -95,7 +95,7 @@ JS
// Don't filter list when a detail view is requested, // Don't filter list when a detail view is requested,
// to avoid edge cases where the filtered list wouldn't contain the 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). // 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; return $list;
} }
@ -336,6 +336,7 @@ JS
'mov' => _t('AssetAdmin.AppCategoryVideo', 'Video'), 'mov' => _t('AssetAdmin.AppCategoryVideo', 'Video'),
'flash' => _t('AssetAdmin.AppCategoryFlash', 'Flash', 'The fileformat'), 'flash' => _t('AssetAdmin.AppCategoryFlash', 'Flash', 'The fileformat'),
'zip' => _t('AssetAdmin.AppCategoryArchive', 'Archive', 'A collection of files'), 'zip' => _t('AssetAdmin.AppCategoryArchive', 'Archive', 'A collection of files'),
'doc' => _t('AssetAdmin.AppCategoryDocument', 'Document')
); );
$context->addField( $context->addField(
$typeDropdown = new DropdownField( $typeDropdown = new DropdownField(

View File

@ -247,8 +247,11 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
function SearchForm() { function SearchForm() {
// get all page types in a dropdown-compatible format // get all page types in a dropdown-compatible format
$pageTypes = SiteTree::page_type_classes(); $pageTypeClasses = SiteTree::page_type_classes();
$pageTypes = array_combine($pageTypes, $pageTypes); $pageTypes = array();
foreach ($pageTypeClasses as $pageTypeClass) {
$pageTypes[$pageTypeClass] = _t($pageTypeClass.'.SINGULARNAME', $pageTypeClass);
}
asort($pageTypes); asort($pageTypes);
// get all filter instances // get all filter instances
@ -284,7 +287,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
) )
// new TextField('MetaTags', _t('CMSMain.SearchMetaTags', 'Meta tags')) // new TextField('MetaTags', _t('CMSMain.SearchMetaTags', 'Meta tags'))
); );
$dateGroup->subfieldParam = 'FieldHolder'; $dateGroup->setFieldHolderTemplate('FieldGroup_DefaultFieldHolder')->addExtraClass('stacked');
$dateFrom->setConfig('showcalendar', true); $dateFrom->setConfig('showcalendar', true);
$dateTo->setConfig('showcalendar', true); $dateTo->setConfig('showcalendar', true);
$classDropdown->setEmptyString(_t('CMSMain.PAGETYPEANYOPT','Any')); $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)); $fields->push($idField = new HiddenField("ID", false, $id));
// Necessary for different subsites // Necessary for different subsites
$fields->push($liveURLField = new HiddenField("AbsoluteLink", false, $record->AbsoluteLink())); $fields->push($liveLinkField = new HiddenField("AbsoluteLink", false, $record->AbsoluteLink()));
$fields->push($liveURLField = new HiddenField("LiveURLSegment")); $fields->push($liveLinkField = new HiddenField("LiveLink"));
$fields->push($stageURLField = new HiddenField("StageURLSegment")); $fields->push($stageLinkField = new HiddenField("StageLink"));
$fields->push(new HiddenField("TreeTitle", false, $record->TreeTitle)); $fields->push(new HiddenField("TreeTitle", false, $record->TreeTitle));
$fields->push(new HiddenField('Sort','', $record->Sort));
if($record->ID && is_numeric( $record->ID ) ) { if($record->ID && is_numeric( $record->ID ) ) {
$liveRecord = Versioned::get_one_by_stage('SiteTree', 'Live', "\"SiteTree\".\"ID\" = $record->ID"); $liveLink = $record->getAbsoluteLiveLink();
if($liveRecord) $liveURLField->setValue($liveRecord->AbsoluteLink()); if($liveLink) $liveLinkField->setValue($liveLink);
}
if(!$deletedFromStage) { if(!$deletedFromStage) {
$stageURLField->setValue(Controller::join_links($record->AbsoluteLink(), '?stage=Stage')); $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 // 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 = new Form($this, "EditForm", $fields, $actions, $validator);
$form->loadDataFrom($record); $form->loadDataFrom($record);
$stageURLField->setValue(Controller::join_links($record->getStageURLSegment(), '?stage=Stage'));
$form->disableDefaultAction(); $form->disableDefaultAction();
$form->addExtraClass('cms-edit-form'); $form->addExtraClass('cms-edit-form');
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); $form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
@ -703,6 +703,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
'Created' => _t('SiteTree.CREATED', 'Date Created'), 'Created' => _t('SiteTree.CREATED', 'Date Created'),
'LastEdited' => _t('SiteTree.LASTUPDATED', 'Last Updated'), 'LastEdited' => _t('SiteTree.LASTUPDATED', 'Last Updated'),
); );
$gridField->getConfig()->getComponentByType('GridFieldSortableHeader')->setFieldSorting(array('getTreeTitle' => 'Title'));
if(!$params) { if(!$params) {
$fields = array_merge(array('listChildrenLink' => ''), $fields); $fields = array_merge(array('listChildrenLink' => ''), $fields);
@ -783,7 +784,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
$record->HasBrokenLink = 0; $record->HasBrokenLink = 0;
$record->HasBrokenFile = 0; $record->HasBrokenFile = 0;
$record->writeWithoutVersion(); if (!$record->ObsoleteClassName) $record->writeWithoutVersion();
// Update the class instance if necessary // Update the class instance if necessary
if(isset($data['ClassName']) && $data['ClassName'] != $record->ClassName) { 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. // 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. // 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); $url = Controller::join_links(singleton('CMSPageEditController')->Link('show'), $record->ID);
$this->response->addHeader('X-ControllerURL', $url); $this->response->addHeader('X-ControllerURL', $url);
$this->request->addHeader('X-Pjax', 'Content');
$this->response->addHeader('X-Pjax', 'Content');
return $this->getResponseNegotiator()->respond($this->request); return $this->getResponseNegotiator()->respond($this->request);
} }

View File

@ -9,4 +9,6 @@ class CMSPageEditController extends CMSMain {
static $url_rule = '/$Action/$ID/$OtherID'; static $url_rule = '/$Action/$ID/$OtherID';
static $url_priority = 41; static $url_priority = 41;
static $required_permission_codes = 'CMS_ACCESS_CMSMain'; static $required_permission_codes = 'CMS_ACCESS_CMSMain';
static $session_namespace = 'CMSMain';
} }

View File

@ -11,6 +11,7 @@ class CMSPageHistoryController extends CMSMain {
static $url_priority = 42; static $url_priority = 42;
static $menu_title = 'History'; static $menu_title = 'History';
static $required_permission_codes = 'CMS_ACCESS_CMSMain'; static $required_permission_codes = 'CMS_ACCESS_CMSMain';
static $session_namespace = 'CMSMain';
static $allowed_actions = array( static $allowed_actions = array(
'VersionsForm', 'VersionsForm',

View File

@ -9,6 +9,7 @@ class CMSPageSettingsController extends CMSMain {
static $url_rule = '/$Action/$ID/$OtherID'; static $url_rule = '/$Action/$ID/$OtherID';
static $url_priority = 42; static $url_priority = 42;
static $required_permission_codes = 'CMS_ACCESS_CMSMain'; static $required_permission_codes = 'CMS_ACCESS_CMSMain';
static $session_namespace = 'CMSMain';
function getEditForm($id = null, $fields = null) { function getEditForm($id = null, $fields = null) {
$record = $this->getRecord($id ? $id : $this->currentPageID()); $record = $this->getRecord($id ? $id : $this->currentPageID());

View File

@ -10,6 +10,7 @@ class CMSPagesController extends CMSMain {
static $url_priority = 40; static $url_priority = 40;
static $menu_title = 'Pages'; static $menu_title = 'Pages';
static $required_permission_codes = 'CMS_ACCESS_CMSMain'; static $required_permission_codes = 'CMS_ACCESS_CMSMain';
static $session_namespace = 'CMSMain';
function LinkPreview() { function LinkPreview() {
return false; return false;
@ -22,14 +23,6 @@ class CMSPagesController extends CMSMain {
return $this->request->getVar('view'); 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) { public function isCurrentPage(DataObject $record) {
return false; return false;
} }

View File

@ -72,12 +72,14 @@ abstract class CMSSiteTreeFilter extends Object {
$this->_cache_ids[$pageArr['ID']] = true; $this->_cache_ids[$pageArr['ID']] = true;
} }
if(!empty($parents)) { while(!empty($parents)) {
$q = new SQLQuery(); $q = new SQLQuery();
$q->setSelect(array('"ID"','"ParentID"')) $q->setSelect(array('"ID"','"ParentID"'))
->setFrom('"SiteTree"') ->setFrom('"SiteTree"')
->setWhere('"ID" in ('.implode(',',array_keys($parents)).')'); ->setWhere('"ID" in ('.implode(',',array_keys($parents)).')');
$parents = array();
foreach($q->execute() as $row) { foreach($q->execute() as $row) {
if ($row['ParentID']) $parents[$row['ParentID']] = true; if ($row['ParentID']) $parents[$row['ParentID']] = true;
$this->_cache_ids[$row['ID']] = true; $this->_cache_ids[$row['ID']] = true;
@ -194,11 +196,13 @@ class CMSSiteTreeFilter_Search extends CMSSiteTreeFilter {
break; break;
case 'LastEditedFrom': case 'LastEditedFrom':
$query->where("\"LastEdited\" >= '$SQL_val'"); $fromDate = new DateField(null, null, $SQL_val);
$query->where("\"LastEdited\" >= '{$fromDate->dataValue()}'");
break; break;
case 'LastEditedTo': case 'LastEditedTo':
$query->where("\"LastEdited\" <= '$SQL_val'"); $toDate = new DateField(null, null, $SQL_val);
$query->where("\"LastEdited\" <= '{$toDate->dataValue()}'");
break; break;
case 'ClassName': case 'ClassName':

View File

@ -314,7 +314,7 @@ class ContentController extends Controller {
</div> </div>
<div id="switchView" class="bottomTabs"> <div id="switchView" class="bottomTabs">
<div class="blank">$viewPageIn </div> $viewPageIn
$items $items
</div> </div>
</div> </div>
@ -401,7 +401,7 @@ HTML;
)); ));
return array( return array(
"Title" => DBField::create_field('Varchar', "Title", "Installation Successful"), "Title" => _t("ContentController.INSTALL_SUCCESS", "Installation Successful!"),
"Content" => $data->renderWith('Install_successfullyinstalled'), "Content" => $data->renderWith('Install_successfullyinstalled'),
); );
} }

View File

@ -320,7 +320,7 @@ class SilverStripeNavigatorItem_ArchiveLink extends SilverStripeNavigatorItem {
} }
function getLink() { function getLink() {
return $this->record->AbsoluteLink() . '?archiveDate=' . $date; return $this->record->AbsoluteLink() . '?archiveDate=' . $this->record->LastEdited;
} }
function canView($member = null) { function canView($member = null) {

View File

@ -1,15 +1,8 @@
<?php <?php
/** /**
* Sitewide configuration. * Sitewide configuration.
* *
* h2. Translation
*
* To enable translation of configurations alongside the {@link Translatable} extension.
* This also allows assigning language-specific toplevel permissions for viewing and editing
* pages, in addition to the normal `TRANSLATE_*`/`TRANSLATE_ALL` permissions.
*
* Object::add_extension('SiteConfig', 'Translatable');
*
* @author Tom Rix * @author Tom Rix
* @package cms * @package cms
*/ */
@ -35,6 +28,15 @@ class SiteConfig extends DataObject implements PermissionProvider {
self::$disabled_themes[$theme] = $theme; self::$disabled_themes[$theme] = $theme;
} }
function populateDefaults()
{
$this->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 * Get the fields that are sent to the CMS. In
* your extensions: updateCMSFields($fields) * your extensions: updateCMSFields($fields)
@ -84,13 +86,6 @@ class SiteConfig extends DataObject implements PermissionProvider {
$topLevelCreatorsOptionsField->setSource($editorsOptionsSource); $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')) { if (!Permission::check('EDIT_SITECONFIG')) {
$fields->makeFieldReadonly($viewersOptionsField); $fields->makeFieldReadonly($viewersOptionsField);
$fields->makeFieldReadonly($viewerGroupsField); $fields->makeFieldReadonly($viewerGroupsField);
@ -161,20 +156,12 @@ class SiteConfig extends DataObject implements PermissionProvider {
* Get the current sites SiteConfig, and creates a new one * Get the current sites SiteConfig, and creates a new one
* through {@link make_site_config()} if none is found. * through {@link make_site_config()} if none is found.
* *
* @param string $locale
* @return SiteConfig * @return SiteConfig
*/ */
static function current_site_config($locale = null) { static function current_site_config() {
if(class_exists('Translatable') && Object::has_extension('SiteConfig',"Translatable")){ if ($siteConfig = DataObject::get_one('SiteConfig')) return $siteConfig;
$locale = isset($locale) ? $locale : Translatable::get_current_locale();
$siteConfig = Translatable::get_one_by_locale('SiteConfig', $locale);
} else {
$siteConfig = DataObject::get_one('SiteConfig');
}
if (!$siteConfig) $siteConfig = self::make_site_config($locale); return self::make_site_config();
return $siteConfig;
} }
/** /**
@ -191,37 +178,14 @@ class SiteConfig extends DataObject implements PermissionProvider {
/** /**
* Create SiteConfig with defaults from language file. * 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 * @param string $locale
* @return SiteConfig * @return SiteConfig
*/ */
static function make_site_config($locale = null) { static function make_site_config() {
if(class_exists('Translatable') && !$locale) $locale = Translatable::get_current_locale(); $config = SiteConfig::create();
$config->write();
$siteConfig = new SiteConfig(); return $config;
$siteConfig->Title = _t('SiteConfig.SITENAMEDEFAULT',"Your Site Name");
$siteConfig->Tagline = _t('SiteConfig.TAGLINEDEFAULT',"your tagline here");
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;
} }
/** /**

View File

@ -455,18 +455,18 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* Get the absolute URL for this page on the Live site. * Get the absolute URL for this page on the Live site.
*/ */
public function getAbsoluteLiveLink($includeStageEqualsLive = true) { 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); $live = Versioned::get_one_by_stage('SiteTree', 'Live', '"SiteTree"."ID" = ' . $this->ID);
if($live) { if($live) {
$link = $live->AbsoluteLink(); $link = $live->AbsoluteLink();
if($includeStageEqualsLive) $link .= '?stage=Live';
if($includeStageEqualsLive) { } else {
$link .= '?stage=Live'; $link = null;
} }
Versioned::reading_stage($oldStage);
return $link; return $link;
}
} }
/** /**
@ -991,18 +991,14 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* Stub method to get the site config, provided so it's easy to override * Stub method to get the site config, provided so it's easy to override
*/ */
function getSiteConfig() { function getSiteConfig() {
$altConfig = false;
if($this->hasMethod('alternateSiteConfig')) { if($this->hasMethod('alternateSiteConfig')) {
$altConfig = $this->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();
} }
}
/** /**
* @deprecated 3.0 Use prepopulate_permission_cache() instead (without the extraneous "p" in "prepopulate") * @deprecated 3.0 Use prepopulate_permission_cache() instead (without the extraneous "p" in "prepopulate")
@ -1511,7 +1507,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
// deconstructs any inheritance trees already. // deconstructs any inheritance trees already.
$allowed = $parent->allowedChildren(); $allowed = $parent->allowedChildren();
$subject = ($this instanceof VirtualPage) ? $this->CopyContentFrom() : $this; $subject = ($this instanceof VirtualPage) ? $this->CopyContentFrom() : $this;
if($subject->ID && !in_array($subject->ClassName, $allowed)) { if(!in_array($subject->ClassName, $allowed)) {
$result->error( $result->error(
_t( _t(
@ -1877,6 +1873,20 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$tabMain->setTitle(_t('SiteTree.TABCONTENT', "Main Content")); $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", "<p class=\"message warning\">$obsoleteWarning</p>"),
"Title"
);
}
if(file_exists(BASE_PATH . '/install.php')) { if(file_exists(BASE_PATH . '/install.php')) {
$fields->addFieldToTab("Root.Main", new LiteralField("InstallWarningHeader", $fields->addFieldToTab("Root.Main", new LiteralField("InstallWarningHeader",
"<p class=\"message warning\">" . _t("SiteTree.REMOVE_INSTALL_WARNING", "<p class=\"message warning\">" . _t("SiteTree.REMOVE_INSTALL_WARNING",

View File

@ -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; }

View File

@ -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; } .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 ----------------------------------------------------------------- */ /** ------------------------------------------------------------------ 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, .field.urlsegment .preview { padding-top: 8px; display: inline-block; }
.field.urlsegment .prefix { color: #777; } .field.urlsegment .prefix { color: #777; }
.field.urlsegment .cancel, .field.urlsegment .update, .field.urlsegment .edit { margin-left: 7px; } .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-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-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-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.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 .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; } .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; }

BIN
images/loading.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 B

View File

@ -41,11 +41,6 @@
if(allowedChildren.hasOwnProperty('allowedchildren-0')) { if(allowedChildren.hasOwnProperty('allowedchildren-0')) {
menuitems['addsubpage'] = { menuitems['addsubpage'] = {
'label': ss.i18n._t('Tree.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 'submenu': allowedChildren
}; };
} }

View File

@ -94,10 +94,12 @@
} }
if (currentVal != updateVal) { if (currentVal != updateVal) {
self.addClass('loading');
self.suggest(updateVal, function(data) { self.suggest(updateVal, function(data) {
var newVal = decodeURIComponent(data.value); var newVal = decodeURIComponent(data.value);
field.val(newVal); field.val(newVal);
self.edit(title); self.edit(title);
self.removeClass('loading');
}); });
} else { } else {
self.edit(); self.edit();

36
javascript/lang/sv_SE.js Normal file
View File

@ -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<br />%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?"
});
}

View File

@ -8,6 +8,7 @@ en_GB:
AppCategoryFlash: Flash AppCategoryFlash: Flash
AppCategoryImage: Image AppCategoryImage: Image
AppCategoryVideo: Video AppCategoryVideo: Video
AppCategoryDocument: Document
BackToFolder: 'Back to folder' BackToFolder: 'Back to folder'
CREATED: Date CREATED: Date
CurrentFolderOnly: 'Limit to current folder?' CurrentFolderOnly: 'Limit to current folder?'

View File

@ -8,6 +8,7 @@ fr:
AppCategoryFlash: Flash AppCategoryFlash: Flash
AppCategoryImage: Image AppCategoryImage: Image
AppCategoryVideo: Vidéo AppCategoryVideo: Vidéo
AppCategoryDocument: Document
BackToFolder: 'Revenir au dossier' BackToFolder: 'Revenir au dossier'
CREATED: Date CREATED: Date
CurrentFolderOnly: 'Limiter au dossier actuel ?' CurrentFolderOnly: 'Limiter au dossier actuel ?'

View File

@ -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;
}

View File

@ -93,12 +93,8 @@
* ----------------------------------------------------------------- */ * ----------------------------------------------------------------- */
.field.urlsegment { .field.urlsegment {
&.disabled { &.loading {
color: #444; background: url(../images/loading.gif) no-repeat 162px 8px;
padding-left: 0px;
margin-left: 0px;
background: none;
border-color: transparent;
} }
.prefix, .prefix,

View File

@ -1,17 +1,18 @@
<p style="margin: 1em 0"> <p>
<b><%t ContentController.InstallSuccessCongratulations "SilverStripe has been successfully installed." %></b> <%t ContentController.InstallSuccessCongratulations "SilverStripe has been successfully installed!" %>
</p> </p>
<% if Project == 'tutorial' %> <% 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='<a href="http://doc.silverstripe.org/doku.php?id=tutorials">our new tutorials</a>' %> <%t ContentController.PostInstallTutorialIntro 'This website is a simplistic version of a SilverStripe 3 site. To extend this, please take a look at {link}.' link='<a href="http://doc.silverstripe.org/framework/en/tutorials">our tutorials</a>' %>
<% end_if %> <% end_if %>
<p><strong>&nbsp; &nbsp; <%t ContentController.Email "Email" %>: $Username</strong></br>
<strong>&nbsp; &nbsp; <%t ContentController.Password "Password" %>: $Password</strong></p>
<p> <p>
<%t ContentController.StartEditing 'You can start editing your site\'s content by opening <a href="{link}">the CMS</a>.' link="admin/" %> <%t ContentController.StartEditing "You can start editing your site's content by opening <a href=\"{link}\">the CMS</a>." link="admin/" %>
<br />
&nbsp; &nbsp; <%t ContentController.Email "Email" %>: $Username<br />
&nbsp; &nbsp; <%t ContentController.Password "Password" %>: $Password<br />
</p> </p>
<div style="background:#fcf8f2; border-radius:4px; border: 1px solid #ffc28b; padding:5px; margin:5px;"> <div style="background:#fcf8f2; border-radius:4px; border: 1px solid #ffc28b; padding:5px; margin:5px;">
<img src="cms/images/dialogs/alert.gif" style="border: none; margin-right: 10px; float: left; height:48px; width:48px" /> <img src="cms/images/dialogs/alert.gif" style="border: none; margin-right: 10px; float: left; height:48px; width:48px" />
<p style="color: #cb6a1c; margin-bottom:0;"> <p style="color: #cb6a1c; margin-bottom:0;">

View File

@ -4,6 +4,7 @@
* @subpackage tests * @subpackage tests
*/ */
class CMSMainTest extends FunctionalTest { class CMSMainTest extends FunctionalTest {
static $fixture_file = 'CMSMainTest.yml'; static $fixture_file = 'CMSMainTest.yml';
protected $autoFollowRedirection = false; protected $autoFollowRedirection = false;
@ -221,6 +222,44 @@ class CMSMainTest extends FunctionalTest {
$this->session()->inst_set('loggedInAs', NULL); $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() { function testBreadcrumbs() {
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture('Page', 'page3');
$page31 = $this->objFromFixture('Page', 'page31'); $page31 = $this->objFromFixture('Page', 'page31');
@ -239,3 +278,11 @@ class CMSMainTest extends FunctionalTest {
$this->session()->inst_set('loggedInAs', null); $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 {
}

View File

@ -357,6 +357,23 @@ class SiteTreeTest extends SapphireTest {
$this->assertEquals('about-us/tom&jerry', $about->RelativeLink('tom&jerry'), 'Doesnt url encode parameter'); $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() { function testDeleteFromStageOperatesRecursively() {
SiteTree::set_enforce_strict_hierarchy(false); SiteTree::set_enforce_strict_hierarchy(false);
$pageAbout = $this->objFromFixture('Page', 'about'); $pageAbout = $this->objFromFixture('Page', 'about');

View File

@ -10,7 +10,7 @@ class VirtualPageTest extends SapphireTest {
); );
protected $requiredExtensions = array( protected $requiredExtensions = array(
'Page' => array('VirtualPageTest_PageExtension') 'SiteTree' => array('VirtualPageTest_PageExtension')
); );
function setUp() { function setUp() {