diff --git a/README.md b/README.md index 31cf80ba..caa12d7e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://secure.travis-ci.org/silverstripe/silverstripe-cms.png?branch=3.1)](http://travis-ci.org/silverstripe/silverstripe-cms) -PHP5 Content Management System (CMS), see [http://silverstripe.org](http://silverstripe.org). Requires the [`framework`](http://github.com/silverstripe/sapphire) module and a [`silverstripe-installer`](http://github.com/silverstripe/silverstripe-installer) base project. +PHP5 Content Management System (CMS), see [http://silverstripe.org](http://silverstripe.org). Requires the [`framework`](http://github.com/silverstripe/silverstripe-framework) module and a [`silverstripe-installer`](http://github.com/silverstripe/silverstripe-installer) base project. ## Installation ## @@ -22,7 +22,7 @@ If you would like to make changes to the SilverStripe core codebase, we have an * [Requirements](http://doc.silverstripe.org/framework/en/installation/server-requirements) * [Changelogs](http://doc.silverstripe.org/framework/en/changelogs/) - * [Bugtracker: Framework](https://github.com/silverstripe/sapphire/issues) + * [Bugtracker: Framework](https://github.com/silverstripe/silverstripe-framework/issues) * [Bugtracker: CMS](https://github.com/silverstripe/silverstripe-cms/issues) * [Bugtracker: Installer](https://github.com/silverstripe/silverstripe-installer/issues) * [Forums](http://silverstripe.org/forums) diff --git a/_config/i18n.yml b/_config/i18n.yml new file mode 100644 index 00000000..4989e86b --- /dev/null +++ b/_config/i18n.yml @@ -0,0 +1,8 @@ +--- +Name: cmsi18n +Before: '/i18n' +After: '/i18n#basei18n' +--- +i18n: + module_priority: + - cms diff --git a/code/controllers/AssetAdmin.php b/code/controllers/AssetAdmin.php index 3626982a..c5453026 100644 --- a/code/controllers/AssetAdmin.php +++ b/code/controllers/AssetAdmin.php @@ -158,7 +158,7 @@ JS GridFieldLevelup::create($folder->ID)->setLinkSpec('admin/assets/show/%d') ); - $gridField = new GridField('File', $title, $this->getList(), $gridFieldConfig); + $gridField = GridField::create('File', $title, $this->getList(), $gridFieldConfig); $columns = $gridField->getConfig()->getComponentByType('GridFieldDataColumns'); $columns->setDisplayFields(array( 'StripThumbnail' => '', @@ -491,6 +491,7 @@ JS return $folder; } } + $this->setCurrentPageID(null); return new Folder(); } diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index fbe29135..87d7358a 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -1092,15 +1092,14 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr if($version) { $record->doRollbackTo($version); $message = _t( - 'CMSMain.ROLLEDBACKVERSION', - "Rolled back to version #%d. New version number is #%d", - array('version' => $data['Version'], 'versionnew' => $record->Version) + 'CMSMain.ROLLEDBACKVERSIONv2', + "Rolled back to version #%d.", + array('version' => $data['Version']) ); } else { $record->doRollbackTo('Live'); $message = _t( - 'CMSMain.ROLLEDBACKPUB',"Rolled back to published version. New version number is #{version}", - array('version' => $record->Version) + 'CMSMain.ROLLEDBACKPUBv2',"Rolled back to published version." ); } @@ -1260,7 +1259,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr rawurlencode(_t( 'CMSMain.RESTORED', "Restored '{title}' successfully", - array('title' => $restoredPage->TreeTitle) + array('title' => $restoredPage->Title) )) ); diff --git a/code/controllers/CMSPageHistoryController.php b/code/controllers/CMSPageHistoryController.php index d1402aca..9444f141 100644 --- a/code/controllers/CMSPageHistoryController.php +++ b/code/controllers/CMSPageHistoryController.php @@ -142,13 +142,16 @@ class CMSPageHistoryController extends CMSMain { ); $revert->setReadonly(true); - } - else { - $message = _t( - 'CMSPageHistoryController.VIEWINGVERSION', - "Currently viewing version {version}.", - array('version' => $versionID) - ); + } else { + if($record->isLatestVersion()) { + $message = _t('CMSPageHistoryController.VIEWINGLATEST', 'Currently viewing the latest version.'); + } else { + $message = _t( + 'CMSPageHistoryController.VIEWINGVERSION', + "Currently viewing version {version}.", + array('version' => $versionID) + ); + } } $fields->addFieldToTab('Root.Main', diff --git a/code/controllers/ContentController.php b/code/controllers/ContentController.php index 82e91355..2cd3f418 100644 --- a/code/controllers/ContentController.php +++ b/code/controllers/ContentController.php @@ -372,6 +372,10 @@ HTML; * This action is called by the installation system */ public function successfullyinstalled() { + // Return 410 Gone if this site is not actually a fresh installation + if (!file_exists(BASE_PATH . '/install.php')) { + $this->httpError(410); + } // The manifest should be built by now, so it's safe to publish the 404 page $fourohfour = Versioned::get_one_by_stage('ErrorPage', 'Stage', '"ErrorCode" = 404'); if($fourohfour) { diff --git a/code/model/SiteTree.php b/code/model/SiteTree.php index 50b5052b..293425a7 100644 --- a/code/model/SiteTree.php +++ b/code/model/SiteTree.php @@ -400,11 +400,13 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid ) { return; // There were no suitable matches at all. } + + $link = Convert::raw2att($page->Link()); if($content) { - return sprintf('%s', $page->Link(), $parser->parse($content)); + return sprintf('%s', $link, $parser->parse($content)); } else { - return $page->Link(); + return $link; } } @@ -444,7 +446,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * @return string */ public function PreviewLink($action = null) { - return $this->AbsoluteLink($action); + if($this->hasMethod('alternatePreviewLink')) { + return $this->alternatePreviewLink($action); + } else { + return $this->AbsoluteLink($action); + } } /** @@ -462,22 +468,19 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid public function RelativeLink($action = null) { if($this->ParentID && self::config()->nested_urls) { $base = $this->Parent()->RelativeLink($this->URLSegment); + } elseif(!$action && $this->URLSegment == RootURLController::get_homepage_link()) { + // Unset base for root-level homepages. + // Note: Homepages with action parameters (or $action === true) + // need to retain their URLSegment. + $base = null; } else { $base = $this->URLSegment; } - // Unset base for homepage URLSegments in their default language. - // Homepages with action parameters or in different languages - // need to retain their URLSegment. We can only do this if the homepage - // is on the root level. - if(!$action && $base == RootURLController::get_homepage_link() && !$this->ParentID) { - $base = null; - if(class_exists('Translatable') && $this->hasExtension('Translatable') && $this->Locale != Translatable::default_locale()){ - $base = $this->URLSegment; - } - } + $this->extend('updateRelativeLink', $base, $action); - // Legacy support + // Legacy support: If $action === true, retain URLSegment for homepages, + // but don't append any action if($action === true) $action = null; return Controller::join_links($base, '/', $action); @@ -1305,8 +1308,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if($this->ExtraMeta) { $tags .= $this->ExtraMeta . "\n"; } - - if(Permission::check('CMS_ACCESS_CMSMain') && in_array('CMSPreviewable', class_implements($this))) { + + if(Permission::check('CMS_ACCESS_CMSMain') && in_array('CMSPreviewable', class_implements($this)) && !$this instanceof ErrorPage) { $tags .= "ID}\" />\n"; $tags .= "CMSEditLink() . "\" />\n"; } @@ -2618,7 +2621,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if(is_string($data)) $data = array('text' => $data); $treeTitle .= sprintf( "%s", - Convert::raw2xml($class), + 'status-' . Convert::raw2xml($class), (isset($data['title'])) ? sprintf(' title="%s"', Convert::raw2xml($data['title'])) : '', Convert::raw2xml($data['text']) ); @@ -2654,7 +2657,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid if(!$this->canAddChildren()) $classes .= " nochildren"; - if(!$this->canEdit() && !$this->canAddChildren()) + if(!$this->canView() && !$this->canEdit() && !$this->canAddChildren()) $classes .= " disabled"; if(!$this->ShowInMenus) @@ -2758,7 +2761,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid 'name' => _t('SiteTree.VIEW_ALL_DESCRIPTION', 'View any page'), 'category' => _t('Permissions.CONTENT_CATEGORY', 'Content permissions'), 'sort' => -100, - 'help' => _t('SiteTree.VIEW_ALL_HELP', 'Ability to view any page on the site, regardless of the settings on the Access tab. Requires the "Access to Site Content" permission') + 'help' => _t('SiteTree.VIEW_ALL_HELP', 'Ability to view any page on the site, regardless of the settings on the Access tab. Requires the "Access to \'Pages\' section" permission') ), 'SITETREE_EDIT_ALL' => array( 'name' => _t('SiteTree.EDIT_ALL_DESCRIPTION', 'Edit any page'), diff --git a/code/model/SiteTreeExtension.php b/code/model/SiteTreeExtension.php index c800398f..f033e8ff 100644 --- a/code/model/SiteTreeExtension.php +++ b/code/model/SiteTreeExtension.php @@ -1,4 +1,5 @@ hasExtension('Translatable')) { - $fields->push(new HiddenField('locale', 'locale', Translatable::get_current_locale())); + $fields->push(new HiddenField('searchlocale', 'searchlocale', Translatable::get_current_locale())); } if(!$actions) { @@ -101,11 +101,18 @@ class SearchForm extends Form { if(!isset($data) || !is_array($data)) $data = $_REQUEST; // set language (if present) - if(class_exists('Translatable') && singleton('SiteTree')->hasExtension('Translatable') && isset($data['locale'])) { - $origLocale = Translatable::get_current_locale(); - Translatable::set_current_locale($data['locale']); + if(class_exists('Translatable')) { + if(singleton('SiteTree')->hasExtension('Translatable') && isset($data['searchlocale'])) { + if($data['searchlocale'] == "ALL") { + Translatable::disable_locale_filter(); + } else { + $origLocale = Translatable::get_current_locale(); + + Translatable::set_current_locale($data['searchlocale']); + } + } } - + $keywords = $data['Search']; $andProcessor = create_function('$matches',' @@ -137,8 +144,14 @@ class SearchForm extends Form { } // reset locale - if(class_exists('Translatable') && singleton('SiteTree')->hasExtension('Translatable') && isset($data['locale'])) { - Translatable::set_current_locale($origLocale); + if(class_exists('Translatable')) { + if(singleton('SiteTree')->hasExtension('Translatable') && isset($data['searchlocale'])) { + if($data['searchlocale'] == "ALL") { + Translatable::enable_locale_filter(); + } else { + Translatable::set_current_locale($origLocale); + } + } } return $results; diff --git a/javascript/CMSMain.AddForm.js b/javascript/CMSMain.AddForm.js index 2c9004cf..08e62d6b 100644 --- a/javascript/CMSMain.AddForm.js +++ b/javascript/CMSMain.AddForm.js @@ -98,8 +98,13 @@ if(state) parentId = parseInt(JSON.parse(state).ParentID, 10); } - var data = {selector: this.data('targetPanel'),pjax: this.data('pjax')}, - url = parentId ? ss.i18n.sprintf(this.data('urlAddpage'), parentId) : this.attr('href'); + var data = {selector: this.data('targetPanel'),pjax: this.data('pjax')}, url; + if(parentId) { + extraParams = this.data('extraParams') ? this.data('extraParams') : ''; + url = $.path.addSearchParams(ss.i18n.sprintf(this.data('urlAddpage'), parentId), extraParams); + } else { + url = this.attr('href'); + } $('.cms-container').loadPanel(url, null, data); e.preventDefault(); diff --git a/javascript/CMSMain.Tree.js b/javascript/CMSMain.Tree.js index 6d98c8aa..e866f440 100644 --- a/javascript/CMSMain.Tree.js +++ b/javascript/CMSMain.Tree.js @@ -9,15 +9,15 @@ 'items': function(node) { var menuitems = { - 'edit': { - 'label': ss.i18n._t('Tree.EditPage'), - 'action': function(obj) { - $('.cms-container').entwine('.ss').loadPanel(ss.i18n.sprintf( - self.data('urlEditpage'), obj.data('id') - )); + 'edit': { + 'label': ss.i18n._t('Tree.EditPage', 'Edit page', 100, 'Used in the context menu when right-clicking on a page node in the CMS tree'), + 'action': function(obj) { + $('.cms-container').entwine('.ss').loadPanel(ss.i18n.sprintf( + self.data('urlEditpage'), obj.data('id') + )); + } } - } - }; + }; // Add "show as list" if(!node.hasClass('nochildren')) { @@ -60,18 +60,21 @@ 'label': '' + klassData.title, '_class': 'class-' + klass, 'action': function(obj) { - $('.cms-container').entwine('.ss').loadPanel(ss.i18n.sprintf( - self.data('urlAddpage'), id, klass - )); + $('.cms-container').entwine('.ss').loadPanel( + $.path.addSearchParams( + ss.i18n.sprintf(self.data('urlAddpage'), id, klass), + self.data('extraParams') + ) + ); } }; }); if(hasAllowedChildren) { menuitems['addsubpage'] = { - 'label': ss.i18n._t('Tree.AddSubPage'), - 'submenu': menuAllowedChildren - }; + 'label': ss.i18n._t('Tree.AddSubPage', 'Add page under this page', 100, 'Used in the context menu when right-clicking on a page node in the CMS tree'), + 'submenu': menuAllowedChildren + }; } menuitems['duplicate'] = { @@ -80,16 +83,22 @@ { 'label': ss.i18n._t('Tree.ThisPageOnly'), 'action': function(obj) { - $('.cms-container').entwine('.ss').loadPanel(ss.i18n.sprintf( - self.data('urlDuplicate'), obj.data('id') - )); + $('.cms-container').entwine('.ss').loadPanel( + $.path.addSearchParams( + ss.i18n.sprintf(self.data('urlDuplicate'), obj.data('id')), + self.data('extraParams') + ) + ); } },{ 'label': ss.i18n._t('Tree.ThisPageAndSubpages'), 'action': function(obj) { - $('.cms-container').entwine('.ss').loadPanel(ss.i18n.sprintf( - self.data('urlDuplicatewithchildren'), obj.data('id') - )); + $('.cms-container').entwine('.ss').loadPanel( + $.path.addSearchParams( + ss.i18n.sprintf(self.data('urlDuplicatewithchildren'), obj.data('id')), + self.data('extraParams') + ) + ); } } ] diff --git a/javascript/CMSPageHistoryController.js b/javascript/CMSPageHistoryController.js index 2a66b397..d441ae8c 100644 --- a/javascript/CMSPageHistoryController.js +++ b/javascript/CMSPageHistoryController.js @@ -8,6 +8,7 @@ */ $.entwine('ss', function($){ + /** * Class: #Form_VersionsForm * @@ -19,24 +20,6 @@ * Constructor */ onmatch: function() { - var self = this; - - /** - * Event: :input[name=ShowUnpublished] change - * - * Changing the show unpublished checkbox toggles whether to show - * or hide the unpublished versions. Because those rows may be being - * compared this also ensures those rows are unselected. - */ - this.find(':input[name=ShowUnpublished]').bind('change', function(e) { - if($(this).attr("checked")) { - self.find("tr[data-published=false]").show(); - } - else { - self.find("tr[data-published=false]").hide()._unselect(); - } - }); - this._super(); }, onunmatch: function() { @@ -83,6 +66,41 @@ } }); + /** + * Class: :input[name=ShowUnpublished] + * + * Used for toggling whether to show or hide unpublished versions. + */ + $('#Form_VersionsForm input[name=ShowUnpublished]').entwine({ + onmatch: function() { + this.toggle(); + this._super(); + }, + onunmatch: function() { + this._super(); + }, + /** + * Event: :input[name=ShowUnpublished] change + * + * Changing the show unpublished checkbox toggles whether to show + * or hide the unpublished versions. Because those rows may be being + * compared this also ensures those rows are unselected. + */ + onchange: function() { + this.toggle(); + }, + toggle: function() { + var self = $(this); + var form = self.parents('form'); + + if(self.attr('checked')) { + form.find('tr[data-published=false]').show(); + } else { + form.find("tr[data-published=false]").hide()._unselect(); + } + } + }); + /** * Class: #Form_VersionsForm tr * diff --git a/lang/en.yml b/lang/en.yml index f0cda7bf..30c55b4b 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -101,8 +101,8 @@ en: RESTORE: Restore RESTORED: 'Restored ''{title}'' successfully' ROLLBACK: 'Roll back to this version' - ROLLEDBACKPUB: 'Rolled back to published version. New version number is #{version}' - ROLLEDBACKVERSION: 'Rolled back to version #%d. New version number is #%d' + ROLLEDBACKPUBv2: 'Rolled back to published version.' + ROLLEDBACKVERSIONv2: 'Rolled back to version #%d.' SAVE: Save SAVEDRAFT: 'Save Draft' TabContent: Content diff --git a/lang/lc_XX.yml b/lang/lc_XX.yml new file mode 100644 index 00000000..0758a584 --- /dev/null +++ b/lang/lc_XX.yml @@ -0,0 +1,54 @@ +lc_XX: + ContentController: + DRAFT_SITE_ACCESS_RESTRICTION: "U MUST LOG IN WIF UR CMS PASWORD IN ORDR 2 VIEW TEH DRAFT OR ARCHIVD CONTENT. CLICK HEAR 2 GO BAK 2 TEH PUBLISHD SIET." + ErrorPage: + CODE: "TEH ERRUR CODE" + Folder: + UNUSEDFILESTITLE: "UNUSD FILEZ" + RedirectorPage: + HASBEENSETUP: "A REDIRECTOR PAEG HAS BEEN SET UP WITHOUT ANYWHERE 2 REDIRECT 2." + HEADER: "DIS PAEG WILL REDIRECT USERS 2 ANOTHR PAEG" + OTHERURL: "UDDR WEBSITEZ URL" + REDIRECTTO: "REDIRECT 2" + REDIRECTTOEXTERNAL: "ANOTHR WEBSIET" + REDIRECTTOPAGE: "A PAEG ON UR WEBSEIT" + YOURPAGE: "PAEG ON UR WEBSEIT" + SiteTree: + ACCESSANYONE: "ANY1" + ACCESSHEADER: "WAT PEEPS CAN C DAT PAEG ON MY SITE?" + ACCESSLOGGEDIN: "LOGGD-IN USERS" + ACCESSONLYTHESE: "ONLY THEES PEEPS (CHOOSE FRUM LIST)" + ALLOWCOMMENTS: "ALLOW COMMENTZ ON DIS PAEG?" + APPEARSVIRTUALPAGES: "DIS CONTENT ALSO APPEARz ON TEH VIRTUAL PAGEZ IN DA %s SECSHUNS." + BUTTONCANCELDRAFT: "CANCEL DRAFT CHANGEZ" + BUTTONCANCELDRAFTDESC: "DELETE UR DRAFT AN REVERT 2 TEH CURRENTLY PUBLISHD PAEG" + BUTTONSAVEPUBLISH: "SAV N PUBLISH" + BUTTONUNPUBLISH: "UNPUBLISH" + BUTTONUNPUBLISHDESC: "REMOOV DIS PAEG FRUM TEH PUBLISHD SIET" + EDITANYONE: "ANYONE HOO CAN LOG-IN 2 TEH CMS" + EDITHEADER: "WAT PEEPS CAN EDIT DIS INSIDE TEH CMS?" + EDITONLYTHESE: "ONLY THEEZ PEEPS (CHOOSE FRUM LIST)" + HASBROKENLINKS: | + DIS PAEG HAS BROKD LINKZ. + + HTMLEDITORTITLE: "TEH CONTENT" + MENUTITLE: "NAVIGASHUN LABEL" + METADESC: "DESCRIPSHUN" + METAEXTRA: "CUSTOM META TAGZ" + METAKEYWORDS: "KEYWURDZ" + METATITLE: "TITLE" + PAGETITLE: "NAYM OV TEH PAEG" + PAGETYPE: "TYPE OV TEH PAEG" + SHOWINMENUS: "SHOU IN MENUZ?" + SHOWINSEARCH: "SHOU IN SEARCH?" + TABACCESS: "ACCESZ" + TABBEHAVIOUR: "BEHAVIOUR" + TABCONTENT: "CONTENT" + TABMETA: "META-DATA" + TOPLEVEL: | + SIET CONTENT (TOP LEVEL) + + VirtualPage: + CHOOSE: "CHOOSE PAEG 2 LINK 2" + EDITCONTENT: "kLICK HEER 2 EDIT TEH CONTENT" + HEADER: "DIS R A VIRTUAL PAEG" diff --git a/templates/BreadcrumbsTemplate.ss b/templates/BreadcrumbsTemplate.ss index b4314d31..beee98e2 100644 --- a/templates/BreadcrumbsTemplate.ss +++ b/templates/BreadcrumbsTemplate.ss @@ -1,5 +1,5 @@ <% if Pages %> <% loop Pages %> - <% if Last %>$Title.XML<% else %>$MenuTitle.XML »<% end_if %> + <% if Last %>$MenuTitle.XML<% else %>$MenuTitle.XML »<% end_if %> <% end_loop %> -<% end_if %> \ No newline at end of file +<% end_if %> diff --git a/templates/Includes/CMSMain_TreeView.ss b/templates/Includes/CMSMain_TreeView.ss index 79e9c543..338d9463 100644 --- a/templates/Includes/CMSMain_TreeView.ss +++ b/templates/Includes/CMSMain_TreeView.ss @@ -19,7 +19,7 @@ $ExtraTreeTools <% end_if %> -