diff --git a/README.md b/README.md index a1f9833df..dd3f498ee 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## SilverStripe Framework -[![Build Status](https://secure.travis-ci.org/silverstripe/sapphire.png)](http://travis-ci.org/silverstripe/sapphire) +[![Build Status](https://secure.travis-ci.org/silverstripe/sapphire.png?branch=3.0)](https://travis-ci.org/silverstripe/sapphire) PHP5 framework forming the base for the SilverStripe CMS ([http://silverstripe.org](http://silverstripe.org)). Requires a [`silverstripe-installer`](http://github.com/silverstripe/silverstripe-installer) base project. Typically used alongside the [`cms`](http://github.com/silverstripe/silverstripe-cms) module. @@ -28,7 +28,7 @@ For other ways to contribute, see the [code contribution guidelines](http://doc. ## License ## - Copyright (c) 2007-2011, SilverStripe Limited - www.silverstripe.com + Copyright (c) 2007-2012, SilverStripe Limited - www.silverstripe.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/admin/_config.php b/admin/_config.php index 1297c918e..f446d8157 100644 --- a/admin/_config.php +++ b/admin/_config.php @@ -13,7 +13,7 @@ HtmlEditorConfig::get('cms')->setOptions(array( 'use_native_selects' => false, 'valid_elements' => "@[id|class|style|title],a[id|rel|rev|dir|tabindex|accesskey|type|name|href|target|title" . "|class],-strong/-b[class],-em/-i[class],-strike[class],-u[class],#p[id|dir|class|align|style],-ol[class]," - . "-ul[class],-li[class],br,img[id|dir|longdesc|usemap|class|src|border|alt=|title|width|height|align]," + . "-ul[class],-li[class],br,img[id|dir|longdesc|usemap|class|src|border|alt=|title|width|height|align|data*]," . "-sub[class],-sup[class],-blockquote[dir|class]," . "-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|dir|id|style]," . "-tr[id|dir|class|rowspan|width|height|align|valign|bgcolor|background|bordercolor|style]," @@ -25,7 +25,7 @@ HtmlEditorConfig::get('cms')->setOptions(array( . "-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|dir|class|align|style],hr[class]," . "dd[id|class|title|dir],dl[id|class|title|dir],dt[id|class|title|dir],@[id,style,class]", 'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name" - . "|usemap],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling]," + . "|usemap|data*],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling]," . "object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]", 'spellchecker_rpc_url' => THIRDPARTY_DIR . '/tinymce-spellchecker/rpc.php' )); diff --git a/admin/code/CMSProfileController.php b/admin/code/CMSProfileController.php index 4f765c1e0..734624780 100644 --- a/admin/code/CMSProfileController.php +++ b/admin/code/CMSProfileController.php @@ -2,7 +2,9 @@ class CMSProfileController extends LeftAndMain { static $url_segment = 'myprofile'; + static $menu_title = 'My Profile'; + static $required_permission_codes = false; static $tree_class = 'Member'; diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index fd2cc7179..b6f11ec01 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -1371,6 +1371,30 @@ class LeftAndMain extends Controller implements PermissionProvider { public function SiteConfig() { return (class_exists('SiteConfig')) ? SiteConfig::current_site_config() : null; } + + /** + * The href for the anchor on the Silverstripe logo. + * Set by calling LeftAndMain::set_application_link() + * + * @var String + */ + static $application_link = 'http://www.silverstripe.org/'; + + /** + * Sets the href for the anchor on the Silverstripe logo in the menu + * + * @param String $link + */ + public static function set_application_link($link) { + self::$application_link = $link; + } + + /** + * @return String + */ + public function ApplicationLink() { + return self::$application_link; + } /** * The application name. Customisable by calling diff --git a/admin/javascript/LeftAndMain.js b/admin/javascript/LeftAndMain.js index ae0c02309..ea2223eda 100644 --- a/admin/javascript/LeftAndMain.js +++ b/admin/javascript/LeftAndMain.js @@ -928,14 +928,14 @@ jQuery.noConflict(); if(!this.data('uiTabs')) this.tabs({ active: (activeTab.index() != -1) ? activeTab.index() : 0, - beforeLoad: function(e, settings) { + beforeLoad: function(e, ui) { // Overwrite ajax loading to use CMS logic instead var makeAbs = $.path.makeUrlAbsolute, baseUrl = $('base').attr('href'), - isSame = (makeAbs(settings.url, baseUrl) == makeAbs(document.location.href)); + isSame = (makeAbs(ui.ajaxSettings.url, baseUrl) == makeAbs(document.location.href)); - if(!isSame) $('.cms-container').loadPanel(settings.url); - $(this).tabs('select', settings.tab.index()); + if(!isSame) $('.cms-container').loadPanel(ui.ajaxSettings.url); + $(this).tabs('select', ui.tab.index()); return false; }, diff --git a/admin/templates/Includes/LeftAndMain_Menu.ss b/admin/templates/Includes/LeftAndMain_Menu.ss index e7d301dae..e8ffe74f3 100644 --- a/admin/templates/Includes/LeftAndMain_Menu.ss +++ b/admin/templates/Includes/LeftAndMain_Menu.ss @@ -1,7 +1,7 @@
' . @@ -584,16 +596,16 @@ class Security extends Controller { 'Form' => $this->ChangePasswordForm(), )); } elseif(Member::currentUser()) { - // let a logged in user change his password + // Logged in user requested a password change form. $customisedController = $controller->customise(array( 'Content' => '
' . _t('Security.CHANGEPASSWORDBELOW', 'You can change your password below.') . '
', 'Form' => $this->ChangePasswordForm())); } else { - // show an error message if the auto login hash is invalid and the + // show an error message if the auto login token is invalid and the // user is not logged in - if(isset($_REQUEST['h'])) { + if(!isset($_REQUEST['t']) || !$member) { $customisedController = $controller->customise( array('Content' => _t( diff --git a/security/SecurityToken.php b/security/SecurityToken.php index d4a7bb8aa..444f87718 100644 --- a/security/SecurityToken.php +++ b/security/SecurityToken.php @@ -227,7 +227,7 @@ class SecurityToken extends Object implements TemplateGlobalProvider { */ protected function generate() { $generator = new RandomGenerator(); - return $generator->generateHash('sha1'); + return $generator->randomToken('sha1'); } public static function get_template_global_variables() { @@ -299,4 +299,4 @@ class NullSecurityToken extends SecurityToken { public function generate() { return null; } -} \ No newline at end of file +} diff --git a/templates/Includes/GridFieldEditButton.ss b/templates/Includes/GridFieldEditButton.ss index bfcc265b0..5ad45ea7a 100644 --- a/templates/Includes/GridFieldEditButton.ss +++ b/templates/Includes/GridFieldEditButton.ss @@ -1 +1 @@ -edit \ No newline at end of file +<% _t('EDIT', 'Edit') %> diff --git a/tests/behat/README.md b/tests/behat/README.md new file mode 100644 index 000000000..e072aec9f --- /dev/null +++ b/tests/behat/README.md @@ -0,0 +1 @@ +See https://github.com/silverstripe-labs/silverstripe-behat-extension \ No newline at end of file diff --git a/tests/behat/_manifest_exclude b/tests/behat/_manifest_exclude new file mode 100644 index 000000000..e69de29bb diff --git a/tests/behat/features/bootstrap/FeatureContext.php b/tests/behat/features/bootstrap/FeatureContext.php new file mode 100644 index 000000000..ea6f10054 --- /dev/null +++ b/tests/behat/features/bootstrap/FeatureContext.php @@ -0,0 +1,38 @@ +useContext('BasicContext', new BasicContext($parameters)); + $this->useContext('LoginContext', new LoginContext($parameters)); + $this->useContext('CmsFormsContext', new CmsFormsContext($parameters)); + $this->useContext('CmsUiContext', new CmsUiContext($parameters)); + + parent::__construct($parameters); + } +} diff --git a/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsFormsContext.php b/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsFormsContext.php new file mode 100644 index 000000000..62974c029 --- /dev/null +++ b/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsFormsContext.php @@ -0,0 +1,72 @@ +context = $parameters; + } + + /** + * Get Mink session from MinkContext + */ + public function getSession($name = null) + { + return $this->getMainContext()->getSession($name); + } + + /** + * @Then /^I should see an edit page form$/ + */ + public function stepIShouldSeeAnEditPageForm() + { + $page = $this->getSession()->getPage(); + + $form = $page->find('css', '#Form_EditForm'); + assertNotNull($form, 'I should see an edit page form'); + } + + /** + * @When /^I fill in the content form with "([^"]*)"$/ + */ + public function stepIFillInTheContentFormWith($content) + { + $this->getSession()->evaluateScript("tinyMCE.get('Form_EditForm_Content').setContent('$content')"); + } + + /** + * @Then /^the content form should contain "([^"]*)"$/ + */ + public function theContentFormShouldContain($content) + { + $this->getMainContext()->assertElementContains('#Form_EditForm_Content', $content); + } +} diff --git a/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php b/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php new file mode 100644 index 000000000..85200c835 --- /dev/null +++ b/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php @@ -0,0 +1,314 @@ +context = $parameters; + } + + /** + * Get Mink session from MinkContext + */ + public function getSession($name = null) + { + return $this->getMainContext()->getSession($name); + } + + /** + * @Then /^I should see the CMS$/ + */ + public function iShouldSeeTheCms() + { + $page = $this->getSession()->getPage(); + $cms_element = $page->find('css', '.cms'); + assertNotNull($cms_element, 'CMS not found'); + } + + /** + * @Then /^I should see a "([^"]*)" notice$/ + */ + public function iShouldSeeANotice($notice) + { + $this->getMainContext()->assertElementContains('.notice-wrap', $notice); + } + + /** + * @Then /^I should see a "([^"]*)" message$/ + */ + public function iShouldSeeAMessage($message) + { + $this->getMainContext()->assertElementContains('.message', $message); + } + + protected function getCmsTabsElement() + { + $this->getSession()->wait(5000, "window.jQuery('.cms-content-header-tabs').size() > 0"); + + $page = $this->getSession()->getPage(); + $cms_content_header_tabs = $page->find('css', '.cms-content-header-tabs'); + assertNotNull($cms_content_header_tabs, 'CMS tabs not found'); + + return $cms_content_header_tabs; + } + + protected function getCmsContentToolbarElement() + { + $this->getSession()->wait( + 5000, + "window.jQuery('.cms-content-toolbar').size() > 0 " + . "&& window.jQuery('.cms-content-toolbar').children().size() > 0" + ); + + $page = $this->getSession()->getPage(); + $cms_content_toolbar_element = $page->find('css', '.cms-content-toolbar'); + assertNotNull($cms_content_toolbar_element, 'CMS content toolbar not found'); + + return $cms_content_toolbar_element; + } + + protected function getCmsTreeElement() + { + $this->getSession()->wait(5000, "window.jQuery('.cms-tree').size() > 0"); + + $page = $this->getSession()->getPage(); + $cms_tree_element = $page->find('css', '.cms-tree'); + assertNotNull($cms_tree_element, 'CMS tree not found'); + + return $cms_tree_element; + } + + protected function getGridfieldTable($title) + { + $page = $this->getSession()->getPage(); + $table_elements = $page->findAll('css', '.ss-gridfield-table'); + assertNotNull($table_elements, 'Table elements not found'); + + $table_element = null; + foreach ($table_elements as $table) { + $table_title_element = $table->find('css', '.title'); + if ($table_title_element->getText() === $title) { + $table_element = $table; + break; + } + } + assertNotNull($table_element, sprintf('Table `%s` not found', $title)); + + return $table_element; + } + + /** + * @Given /^I should see a "([^"]*)" button in CMS Content Toolbar$/ + */ + public function iShouldSeeAButtonInCmsContentToolbar($text) + { + $cms_content_toolbar_element = $this->getCmsContentToolbarElement(); + + $element = $cms_content_toolbar_element->find('named', array('link_or_button', "'$text'")); + assertNotNull($element, sprintf('%s button not found', $text)); + } + + /** + * @When /^I should see "([^"]*)" in CMS Tree$/ + */ + public function stepIShouldSeeInCmsTree($text) + { + $cms_tree_element = $this->getCmsTreeElement(); + + $element = $cms_tree_element->find('named', array('content', "'$text'")); + assertNotNull($element, sprintf('%s not found', $text)); + } + + /** + * @When /^I should not see "([^"]*)" in CMS Tree$/ + */ + public function stepIShouldNotSeeInCmsTree($text) + { + $cms_tree_element = $this->getCmsTreeElement(); + + $element = $cms_tree_element->find('named', array('content', "'$text'")); + assertNull($element, sprintf('%s found', $text)); + } + + /** + * @When /^I expand the "([^"]*)" CMS Panel$/ + */ + public function iExpandTheCmsPanel() + { + // TODO Make dynamic, currently hardcoded to first panel + $page = $this->getSession()->getPage(); + + $panel_toggle_element = $page->find('css', '.cms-content > .cms-panel > .cms-panel-toggle > .toggle-expand'); + assertNotNull($panel_toggle_element, 'Panel toggle not found'); + + if ($panel_toggle_element->isVisible()) { + $panel_toggle_element->click(); + } + } + + /** + * @When /^I click the "([^"]*)" CMS tab$/ + */ + public function iClickTheCmsTab($tab) + { + $this->getSession()->wait(5000, "window.jQuery('.ui-tabs-nav').size() > 0"); + + $page = $this->getSession()->getPage(); + $tabsets = $page->findAll('css', '.ui-tabs-nav'); + assertNotNull($tabsets, 'CMS tabs not found'); + + $tab_element = null; + foreach($tabsets as $tabset) { + if($tab_element) continue; + $tab_element = $tabset->find('named', array('link_or_button', "'$tab'")); + } + assertNotNull($tab_element, sprintf('%s tab not found', $tab)); + + $tab_element->click(); + } + + /** + * @Then /^the "([^"]*)" table should contain "([^"]*)"$/ + */ + public function theTableShouldContain($table, $text) + { + $table_element = $this->getGridfieldTable($table); + + $element = $table_element->find('named', array('content', "'$text'")); + assertNotNull($element, sprintf('Element containing `%s` not found in `%s` table', $text, $table)); + } + + /** + * @Then /^the "([^"]*)" table should not contain "([^"]*)"$/ + */ + public function theTableShouldNotContain($table, $text) + { + $table_element = $this->getGridfieldTable($table); + + $element = $table_element->find('named', array('content', "'$text'")); + assertNull($element, sprintf('Element containing `%s` not found in `%s` table', $text, $table)); + } + + /** + * @Given /^I click on "([^"]*)" in the "([^"]*)" table$/ + */ + public function iClickOnInTheTable($text, $table) + { + $table_element = $this->getGridfieldTable($table); + + $element = $table_element->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $text)); + assertNotNull($element, sprintf('Element containing `%s` not found', $text)); + $element->click(); + } + + /** + * @Then /^I can see the preview panel$/ + */ + public function iCanSeeThePreviewPanel() + { + $this->getMainContext()->assertElementOnPage('.cms-preview'); + } + + /** + * @Given /^the preview contains "([^"]*)"$/ + */ + public function thePreviewContains($content) + { + $driver = $this->getSession()->getDriver(); + $driver->switchToIFrame('cms-preview-iframe'); + + $this->getMainContext()->assertPageContainsText($content); + $driver->switchToWindow(); + } + + /** + * @Given /^the preview does not contain "([^"]*)"$/ + */ + public function thePreviewDoesNotContain($content) + { + $driver = $this->getSession()->getDriver(); + $driver->switchToIFrame('cms-preview-iframe'); + + $this->getMainContext()->assertPageNotContainsText($content); + $driver->switchToWindow(); + } + + /** + * Workaround for chosen.js dropdowns which hide the original dropdown field. + * + * @When /^(?:|I )fill in "(?P