Merge pull request #1 from silverstripe/master

Syncing back because I suck at Git
This commit is contained in:
Will Morgan 2013-05-08 03:45:51 -07:00
commit 17e31fc609
49 changed files with 604 additions and 238 deletions

View File

@ -551,7 +551,7 @@ jQuery.noConflict();
this.redraw();
this.restoreTabState(typeof state.data.tabState !== 'undefined' ? state.data.tabState : null);
this.restoreTabState((state && typeof state.data.tabState !== 'undefined') ? state.data.tabState : null);
return newContentEls;
},

View File

@ -74,8 +74,9 @@ global $database;
// No database provided
if(!isset($database) || !$database) {
// if SS_DATABASE_CHOOSE_NAME
if(defined('SS_DATABASE_CHOOSE_NAME') && SS_DATABASE_CHOOSE_NAME) {
if(defined('SS_DATABASE_NAME')) {
$database = SS_DATABASE_NAME;
} else if(defined('SS_DATABASE_CHOOSE_NAME') && SS_DATABASE_CHOOSE_NAME) {
$loopCount = (int)SS_DATABASE_CHOOSE_NAME;
$databaseDir = BASE_PATH;
for($i=0;$i<$loopCount-1;$i++) $databaseDir = dirname($databaseDir);

View File

@ -42,6 +42,7 @@ class HTTP {
public static function absoluteURLs($html) {
$html = str_replace('$CurrentPageURL', $_SERVER['REQUEST_URI'], $html);
return HTTP::urlRewriter($html, function($url) {
if(stripos($url, 'mailto:') === 0) return $url;
return Director::absoluteURL($url, true);
});
}

View File

@ -15,6 +15,7 @@
class SS_ClassManifest {
const CONF_FILE = '_config.php';
const CONF_DIR = '_config';
protected $base;
protected $tests;
@ -28,6 +29,7 @@ class SS_ClassManifest {
protected $interfaces = array();
protected $implementors = array();
protected $configs = array();
protected $configDirs = array();
/**
* @return TokenisedRegularExpression
@ -128,6 +130,7 @@ class SS_ClassManifest {
$this->interfaces = $data['interfaces'];
$this->implementors = $data['implementors'];
$this->configs = $data['configs'];
$this->configDirs = $data['configDirs'];
} else {
$this->regenerate($cache);
}
@ -254,6 +257,10 @@ class SS_ClassManifest {
foreach($this->configs as $configPath) {
$modules[basename(dirname($configPath))] = dirname($configPath);
}
foreach($this->configDirs as $configDir) {
$path = preg_replace('/\/_config$/', '', dirname($configDir));
$modules[basename($path)] = $path;
}
return $modules;
}
@ -265,7 +272,7 @@ class SS_ClassManifest {
public function regenerate($cache = true) {
$reset = array(
'classes', 'roots', 'children', 'descendants', 'interfaces',
'implementors', 'configs'
'implementors', 'configs', 'configDirs'
);
// Reset the manifest so stale info doesn't cause errors.
@ -278,7 +285,8 @@ class SS_ClassManifest {
'name_regex' => '/^(_config.php|[^_].*\.php)$/',
'ignore_files' => array('index.php', 'main.php', 'cli-script.php'),
'ignore_tests' => !$this->tests,
'file_callback' => array($this, 'handleFile')
'file_callback' => array($this, 'handleFile'),
'dir_callback' => array($this, 'handleDir')
));
$finder->find($this->base);
@ -292,12 +300,19 @@ class SS_ClassManifest {
'descendants' => $this->descendants,
'interfaces' => $this->interfaces,
'implementors' => $this->implementors,
'configs' => $this->configs
'configs' => $this->configs,
'configDirs' => $this->configDirs
);
$this->cache->save($data, $this->cacheKey);
}
}
public function handleDir($basename, $pathname, $depth) {
if ($basename == self::CONF_DIR) {
$this->configDirs[] = $pathname;
}
}
public function handleFile($basename, $pathname, $depth) {
if ($basename == self::CONF_FILE) {
$this->configs[] = $pathname;

View File

@ -39,7 +39,7 @@ Used in side panels and action tabs
.cms table.ss-gridfield-table tbody { background: #FFF; }
.cms table.ss-gridfield-table tbody tr { cursor: pointer; }
.cms table.ss-gridfield-table tbody td { width: auto; max-width: 500px; word-wrap: break-word; }
.cms table.ss-gridfield-table tbody td.col-buttons { width: auto; padding: 0 8px; text-align: right; white-space: nowrap; }
.cms table.ss-gridfield-table tbody td.col-buttons { width: 1px; padding: 0 8px; text-align: right; white-space: nowrap; }
.cms table.ss-gridfield-table tbody td.col-listChildrenLink { width: 16px; border-right: none; text-indent: -9999em; padding: 0; }
.cms table.ss-gridfield-table tbody td.col-listChildrenLink .list-children-link { background: transparent url(../images/sitetree_ss_default_icons.png) no-repeat 3px -4px; display: block; }
.cms table.ss-gridfield-table tbody td.col-getTreeTitle span.item { color: #0073c1; }
@ -72,7 +72,7 @@ Used in side panels and action tabs
.cms table.ss-gridfield-table tr th { font-weight: bold; font-size: 12px; color: #FFF; padding: 5px; border-right: 1px solid rgba(0, 0, 0, 0.1); }
.cms table.ss-gridfield-table tr th div.fieldgroup, .cms table.ss-gridfield-table tr th div.fieldgroup-field { width: 100%; position: relative; }
.cms table.ss-gridfield-table tr th div.fieldgroup { min-width: 200px; padding-right: 0; }
.cms table.ss-gridfield-table tr th div.fieldgroup.filter-buttons { min-width: 0; box-shadow: none; border: none; }
.cms table.ss-gridfield-table tr th div.fieldgroup.filter-buttons { min-width: 49px; box-shadow: none; border: none; }
.cms table.ss-gridfield-table tr th div.fieldgroup.filter-buttons div { width: auto; display: inline; }
.cms table.ss-gridfield-table tr th.main { white-space: nowrap; border-top: 1px solid #a4b4bf; border-left: 1px solid #a4b4bf; color: #fff; background: #98aab6; border-bottom: 1px solid rgba(0, 0, 0, 0.1); }
.cms table.ss-gridfield-table tr th.main span { text-shadow: 0px -1px 0 rgba(0, 0, 0, 0.2); padding-left: 8px; padding-right: 8px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; -o-text-overflow: ellipsis; margin-right: 8px; }

View File

@ -101,7 +101,7 @@ abstract class BulkLoader extends ViewableData {
*
* {@see Member::$unique_identifier_field}.
*
* If multiple checks are specified, the first one "wins".
* If multiple checks are specified, the first non-empty field "wins".
*
* <code>
* <?php

View File

@ -162,15 +162,12 @@ class CsvBulkLoader extends BulkLoader {
*/
public function findExistingObject($record) {
$SNG_objectClass = singleton($this->objectClass);
// checking for existing records (only if not already found)
foreach($this->duplicateChecks as $fieldName => $duplicateCheck) {
if(is_string($duplicateCheck)) {
$SQL_fieldName = Convert::raw2sql($duplicateCheck);
if(!isset($record[$fieldName])) {
return false;
//user_error("CsvBulkLoader:processRecord: Couldn't find duplicate identifier '{$fieldName}'
//in columns", E_USER_ERROR);
if(!isset($record[$fieldName]) || empty($record[$fieldName])) { //skip current duplicate check if field value is empty
continue;
}
$SQL_fieldValue = Convert::raw2sql($record[$fieldName]);
$existingRecord = DataObject::get_one($this->objectClass, "\"$SQL_fieldName\" = '{$SQL_fieldValue}'");
@ -184,17 +181,16 @@ class CsvBulkLoader extends BulkLoader {
user_error("CsvBulkLoader::processRecord():"
. " {$duplicateCheck['callback']} not found on importer or object class.", E_USER_ERROR);
}
if($existingRecord) return $existingRecord;
if($existingRecord) {
return $existingRecord;
}
} else {
user_error('CsvBulkLoader::processRecord(): Wrong format for $duplicateChecks', E_USER_ERROR);
}
}
return false;
}
/**
* Determine wether any loaded files should be parsed
* with a header-row (otherwise we rely on {@link self::$columnMap}.

View File

@ -8,6 +8,7 @@
* Resizing of preview to common screen widths ("desktop", "tablet" and "smartphone")
* Decluttered "Edit Page" buttons by moving minor actions into a "more options" panel
* Auto-detect CMS changes and highlight the save button for better informancy
* New context action "Show children as list" on tree for better management on large sites
* Display "last edited" and "last published" data for pages in CMS
* CMS form fields now support help text through `setDescription()`, both inline and as tooltips
* Removed SiteTree "MetaTitle" and "MetaKeywords" fields
@ -36,6 +37,81 @@
## Upgrading
### Statics in custom Page classes need to be "private"
**Requires action on every SilverStripe installation.**
Typical error message: `Access level to ErrorPage::$db must be public`
Related to the configuration change described above, many statics in core are now
marked with `private` visibility. While PHP allows making variables more visible
(e.g. from "private" to "public"), it complains if you try to restrict visibility in subclasses.
The core framework extends from the `Page` class in your own codebase (`mysite/`),
which means you need to change those statics to `private` yourself.
The same rules apply to controllers subclassd from `Page_Controller`.
Before:
:::php
<?php
class Page extends SiteTree {
static $db = array('MyVar' => 'Text');
}
class Page_Controller extends ContentController {
static $allowed_actions = array('myaction');
}
After:
:::php
<?php
class Page extends SiteTree {
private static $db = array('MyVar' => 'Text');
}
class Page_Controller extends ContentController {
private static $allowed_actions = array('myaction');
}
Most statics defined in `SiteTree` and `DataObject` are affected, for example:
`$db`, `$has_one`, `$has_many`, `$many_many`, `$defaults`, `$allowed_children`.
The same goes for statics defined in `ContentController`, e.g. `$allowed_actions`.
Classes which are not further extended by the core (e.g. all custom `DataObject` subclasses)
are not affected by this change, although we recommend to mark those inherited statics
as `private` as well, to make it clear that they should be accessed through the Config API.
### default_cast is now Text
In order to reduce the chance of accidentally allowing XSS attacks, the value of default_cast
has been changed in 3.1 from HTMLText to Text. This means that any values used in a template
that haven't been explicitly cast as safe will be escaped (`<` replaced with `&lt;` etc).
When upgrading, if methods return HTML fragments they need to explicitly cast them
as such. This can either be done by returning an HTMLText object, like:
:::php
return DBField::create_field('HTMLText', '<div></div>');
or by defining the casting of the accessor method, like:
:::php
class Page extends SiteTree {
private static $casting = array(
'MyDiv' => 'HTMLText'
)
function MyDiv() {
return '<div></div>';
}
}
SSViewer#process (and as a result ViewableData#renderWith) have been changed to already return
explicitly cast HTMLText instances, so functions that return the result of these methods won't
have to do any additional casting.
Note that this change means that if code was testing the result via is_string, that is no longer
reliable.
### Static properties are immutable and private, you must use Config API.
A common SilverStripe pattern is to use a static variable on a class to define a configuration parameter.
@ -138,77 +214,6 @@ for details.
For more information about how to use the config system, see the ["Configuration" topic](/topic/configuration).
### Statics in custom Page classes need to be "private"
Related to the configuration change described above, many statics in core are now
marked with `private` visibility. While PHP allows making variables more visible
(e.g. from "private" to "public"), it complains if you try to restrict visibility in subclasses.
The core framework extends from the `Page` class in your own codebase (`mysite/`),
which means you need to change those statics to `private` yourself.
The same rules apply to controllers subclassd from `Page_Controller`.
Before:
:::php
<?php
class Page extends SiteTree {
static $db = array('MyVar' => 'Text');
}
class Page_Controller extends ContentController {
static $allowed_actions = array('myaction');
}
After:
:::php
<?php
class Page extends SiteTree {
private static $db = array('MyVar' => 'Text');
}
class Page_Controller extends ContentController {
private static $allowed_actions = array('myaction');
}
Most statics defined in `SiteTree` and `DataObject` are affected, for example:
`$db`, `$has_one`, `$has_many`, `$many_many`, `$defaults`, `$allowed_children`.
The same goes for statics defined in `ContentController`, e.g. `$allowed_actions`.
Classes which are not further extended by the core (e.g. all custom `DataObject` subclasses)
are not affected by this change, although we recommend to mark those inherited statics
as `private` as well, to make it clear that they should be accessed through the Config API.
### default_cast is now Text
In order to reduce the chance of accidentally allowing XSS attacks, the value of default_cast
has been changed in 3.1 from HTMLText to Text. This means that any values used in a template
that haven't been explicitly cast as safe will be escaped (`<` replaced with `&lt;` etc).
When upgrading, if methods return HTML fragments they need to explicitly cast them
as such. This can either be done by returning an HTMLText object, like:
:::php
return DBField::create_field('HTMLText', '<div></div>');
or by defining the casting of the accessor method, like:
:::php
class Page extends SiteTree {
private static $casting = array(
'MyDiv' => 'HTMLText'
)
function MyDiv() {
return '<div></div>';
}
}
SSViewer#process (and as a result ViewableData#renderWith) have been changed to already return
explicitly cast HTMLText instances, so functions that return the result of these methods won't
have to do any additional casting.
Note that this change means that if code was testing the result via is_string, that is no longer
reliable.
### Deny URL access if `Controller::$allowed_actions` is undefined or empty array
In order to make controller access checks more consistent and easier to

View File

@ -0,0 +1,163 @@
# 3.1.0-beta3 #
## Overview ##
### CMS
* New context action "Show children as list" on tree for better management on large sites
* Display "last edited" and "last published" data for pages in CMS
* More legible and simplified tab and menu styling in the CMS
* Dropped support for Internet Explorer 7
### Framework
* Static properties are immutable and private, you must use Config API
* Statics in custom Page classes need to be "private"
* `$default_cast` is now `Text` instead of `HTMLText`, to secure templates from XSS by default
* Shortcodes are no longer supported in template files. They continue to work in DB fields and other
HTMLText-cast fields.
* `DataList` and `ArrayList` are now immutable, they'll return cloned instances on modification
* Removed legacy table APIs (e.g. `TableListField`), use GridField instead
* Deny URL access if `Controller::$allowed_actions` is undefined
* Removed support for "*" rules in `Controller::$allowed_actions`
* Removed support for overriding rules on parent classes through `Controller::$allowed_actions`
* `RestfulService` verifies SSL peers by default
* Optional integration with ImageMagick as a new image manipulation backend
## Upgrading
See [3.1.0 release notes](/changelogs/3.1.0)
## Changelog
### API Changes
* 2013-04-11 [c8e8b51](https://github.com/silverstripe/sapphire/commit/c8e8b51) used call_user_func_array in order to have an arbitrary number of parameter for getFormattedImage (fixes #1752) (g4b0)
* 2013-04-09 [14b997e](https://github.com/silverstripe/sapphire/commit/14b997e) Deprecated Object::add_extension() usage (as of 3.2) (Ingo Schommer)
* 2013-04-07 [6a95db0](https://github.com/silverstripe/sapphire/commit/6a95db0) Support inequalities in templates (s-m)
* 2013-04-06 [5238e9c](https://github.com/silverstripe/sapphire/commit/5238e9c) add onBeforeRollback() and onAfterRollback() hooks. (Will Rossiter)
* 2013-04-06 [1fc780c](https://github.com/silverstripe/sapphire/commit/1fc780c) Return a 404 error when no director rule is matched (Andrew Short)
* 2013-04-06 [cc09cce](https://github.com/silverstripe/silverstripe-cms/commit/cc09cce) remove static related classes, now staticpublisher module (Will Rossiter)
* 2013-04-06 [6e2906d](https://github.com/silverstripe/silverstripe-cms/commit/6e2906d) remove static related classes, now staticpublisher module (Will Rossiter)
* 2013-04-05 [ddb017a](https://github.com/silverstripe/sapphire/commit/ddb017a) Move LimitWordCount() to Varchar (Will Rossiter)
* 2013-03-30 [5ec85d0](https://github.com/silverstripe/sapphire/commit/5ec85d0) Don't allow dots in URL segments (Andrew Short)
* 2013-03-27 [e97c034](https://github.com/silverstripe/sapphire/commit/e97c034) i18n::$common_languages and i18n::$common_locales converted to Config API (Ingo Schommer)
* 2013-03-27 [828ac7f](https://github.com/silverstripe/sapphire/commit/828ac7f) Replaced SSViewer.custom_theme with SSViewer.theme_enabled (Ingo Schommer)
* 2013-03-21 [3334eaf](https://github.com/silverstripe/sapphire/commit/3334eaf) Marked statics private, use Config API instead (#8317) (Ingo Schommer)
* 2013-03-18 [51c8e86](https://github.com/silverstripe/silverstripe-cms/commit/51c8e86) Marked statics private, use Config API instead (#8317) (Ingo Schommer)
* 2013-03-12 [215628a](https://github.com/silverstripe/sapphire/commit/215628a) re factored Hierarchy class to use new ::get() syntax API: removed broken & unused method Hierarchy-&gt;partialTreeAsUL() (Zauberfisch)
* 2013-03-12 [743a186](https://github.com/silverstripe/sapphire/commit/743a186) Make SSViewer#process return HTMLText not string (Hamish Friedlander)
* 2013-03-12 [9bd6dd9](https://github.com/silverstripe/sapphire/commit/9bd6dd9) Make default_cast Text and not HTMLText (Hamish Friedlander)
* 2013-03-12 [168f071](https://github.com/silverstripe/sapphire/commit/168f071) Make HTMLValue replace-able via DI (Hamish Friedlander)
* 2013-03-08 [b81f39a](https://github.com/silverstripe/sapphire/commit/b81f39a) Handle uncaught ValidationException on CMS controller execution (Ingo Schommer)
* 2013-02-27 [9258485](https://github.com/silverstripe/sapphire/commit/9258485) Adding setURL to HTTPRequest object (Daniel Hensby)
* 2013-02-27 [e6fffb9](https://github.com/silverstripe/sapphire/commit/e6fffb9) Remove content-length setting in HTTPResponse (Ingo Schommer)
* 2013-02-27 [600d9cf](https://github.com/silverstripe/sapphire/commit/600d9cf) Make Object::config use late static binding (Hamish Friedlander)
* 2013-02-27 [904fd2d](https://github.com/silverstripe/sapphire/commit/904fd2d) Make Object::config use late static binding (Hamish Friedlander)
* 2013-02-15 [2352317](https://github.com/silverstripe/silverstripe-installer/commit/2352317) Filter composer files in IIS and Apache rules (fixes #8011) (Ingo Schommer)
* 2013-02-12 [10199f9](https://github.com/silverstripe/sapphire/commit/10199f9) Data corruption on Versioned due to lazy loading (Julian Seidenberg)
* 2012-12-13 [becc5ba](https://github.com/silverstripe/silverstripe-installer/commit/becc5ba) Block all yaml files by default, to reduce the change of information leakage (Hamish Friedlander)
### Features and Enhancements
* 2013-04-08 [f296439](https://github.com/silverstripe/sapphire/commit/f296439) Hints for scaffolded date/time fields (Ingo Schommer)
* 2013-04-03 [6eda25a](https://github.com/silverstripe/sapphire/commit/6eda25a) Allow specifying the secure domain to Director::forceSSL() (Sean Harvey)
* 2013-03-21 [dd6aaaf](https://github.com/silverstripe/sapphire/commit/dd6aaaf) Additional image generation functions now self-determine if a modification to the underlying image backend is necessary before generating additional image files. (Damian Mooyman)
* 2013-03-19 [01f46d0](https://github.com/silverstripe/sapphire/commit/01f46d0) Enforce max node counts to avoid excessive resource usage (Ingo Schommer)
* 2013-03-18 [5779097](https://github.com/silverstripe/sapphire/commit/5779097) Move temp data into a user-specific subfolder, to stop temp-permission bugs from occurring. (Sam Minnee)
* 2013-03-14 [ec93643](https://github.com/silverstripe/silverstripe-cms/commit/ec93643) Set correct ParentID when creating page from list view (Ingo Schommer)
* 2013-03-14 [1e1049b](https://github.com/silverstripe/silverstripe-cms/commit/1e1049b) "Show children as list" tree context action (Ingo Schommer)
* 2013-03-12 [d2650bb](https://github.com/silverstripe/sapphire/commit/d2650bb) Disable shortcodes in $Layout and $Content in SSViewer (Hamish Friedlander)
* 2013-03-12 [cd41a53](https://github.com/silverstripe/sapphire/commit/cd41a53) Let shortcodes be disabled in HTMLText & HTMLVarchar (Hamish Friedlander)
* 2013-03-12 [2dd0e3f](https://github.com/silverstripe/silverstripe-cms/commit/2dd0e3f) Restored duplicate and duplicated with children functionality, as in 2.4 See ticket #7602 (jean)
* 2013-03-05 [5af35a8](https://github.com/silverstripe/sapphire/commit/5af35a8) Allow multiline comments in SS3 templates (miiihi)
* 2013-02-19 [82dc98b](https://github.com/silverstripe/sapphire/commit/82dc98b) fixed styling bug with the text in the file upload drop area and moved allowed extensions up a tad (Jeremy Bridson)
* 2013-02-05 [083b6b2](https://github.com/silverstripe/sapphire/commit/083b6b2) Upload-&gt;replaceFile setting (Ingo Schommer)
### Bugfixes
* 2013-04-18 [8d26bdb](https://github.com/silverstripe/sapphire/commit/8d26bdb) We still need XML escaping on href attributes in HTML4Value (Hamish Friedlander)
* 2013-04-17 [4d70daa](https://github.com/silverstripe/sapphire/commit/4d70daa) HiddenFields and VisibleFields should always return extraFields (uniun)
* 2013-04-12 [685b82a](https://github.com/silverstripe/silverstripe-cms/commit/685b82a) #673 Do not prevent default browser behaviour when selecting page type on new page creation (jean)
* 2013-04-12 [0dfc6d5](https://github.com/silverstripe/sapphire/commit/0dfc6d5) Fixed incorrect variable usage in generation of PhoneNumberField form fields (Damian Mooyman)
* 2013-04-10 [29e6bd5](https://github.com/silverstripe/sapphire/commit/29e6bd5) Allow empty else- and else_if-blocks (s-m)
* 2013-04-10 [9da57b0](https://github.com/silverstripe/sapphire/commit/9da57b0) Fixed broken ErrorPage icons in CMS view (Damian Mooyman)
* 2013-04-09 [975c699](https://github.com/silverstripe/sapphire/commit/975c699) Edge case attempting to destroy uninitialized tabs (Loz Calver)
* 2013-04-08 [da515b8](https://github.com/silverstripe/silverstripe-cms/commit/da515b8) Use SSViewer.theme_enabled in CMS logic (Ingo Schommer)
* 2013-04-08 [c18f3fe](https://github.com/silverstripe/silverstripe-cms/commit/c18f3fe) Use onadd instead of onmatch on cms-add-form when creating new page #673 (jean)
* 2013-04-07 [7881f60](https://github.com/silverstripe/sapphire/commit/7881f60) nested SelectionGroups should only hide first level (Will Rossiter)
* 2013-04-06 [e619329](https://github.com/silverstripe/sapphire/commit/e619329) Decimal field change detection. (Will Rossiter)
* 2013-04-06 [6972222](https://github.com/silverstripe/sapphire/commit/6972222) Ensure FieldList::push() doesn't eliminate key (Will Rossiter)
* 2013-04-06 [1427a06](https://github.com/silverstripe/sapphire/commit/1427a06) remove_extension should work on parameterized extensions (Will Rossiter)
* 2013-04-05 [acf2ff8](https://github.com/silverstripe/sapphire/commit/acf2ff8) Fix for #1487 (s-m)
* 2013-04-05 [65cb182](https://github.com/silverstripe/sapphire/commit/65cb182) Don't sort when deleting records in ManyManyList::removeAll() (Sean Harvey)
* 2013-04-05 [cfafa19](https://github.com/silverstripe/sapphire/commit/cfafa19) Disallow group removal when member is edited in groups view (Ingo Schommer)
* 2013-04-05 [5119d9a](https://github.com/silverstripe/sapphire/commit/5119d9a) Only allow one concurrent ajax in TreeDropdownField (Ingo Schommer)
* 2013-04-04 [da87614](https://github.com/silverstripe/sapphire/commit/da87614) Skip autofocus on TreeDropdownField (Ingo Schommer)
* 2013-04-03 [6d59257](https://github.com/silverstripe/sapphire/commit/6d59257) Empty fields on SQLQuery-&gt;aggregate() with alias (Ingo Schommer)
* 2013-04-02 [5a8a067](https://github.com/silverstripe/sapphire/commit/5a8a067) Consistently quote orderby in DataQuery-&gt;ensureSelectContainsOrderbyColumns() (Ingo Schommer)
* 2013-04-01 [df4d742](https://github.com/silverstripe/sapphire/commit/df4d742) Saving of custom meta tags (fixes #8288) (Joseph Madden)
* 2013-03-29 [3aced11](https://github.com/silverstripe/sapphire/commit/3aced11) GridFieldFilterHeader only filters on last filter (Stig Lindqvist)
* 2013-03-28 [ff3b63f](https://github.com/silverstripe/sapphire/commit/ff3b63f) Remove unnecessary DISTINCT from ManyManyList-&gt;removeAll() (Ingo Schommer)
* 2013-03-29 [f2b4b95](https://github.com/silverstripe/sapphire/commit/f2b4b95) Set ModelAdmin tab targets to avoid creating new panels (Andrew Short)
* 2013-03-27 [c63d840](https://github.com/silverstripe/sapphire/commit/c63d840) fixed access to asset_preview_width in getFieldsForImage (g4b0)
* 2013-03-27 [7121fc3](https://github.com/silverstripe/sapphire/commit/7121fc3) Config isolation in Director::test() (Ingo Schommer)
* 2013-03-27 [f73a5c6](https://github.com/silverstripe/silverstripe-cms/commit/f73a5c6) VirtualPageTest memory errors due to Config API quirks (Ingo Schommer)
* 2013-03-27 [19a8545](https://github.com/silverstripe/sapphire/commit/19a8545) update deprecated 'live' jquery to 'on' (Naomi Guyer)
* 2013-03-26 [a415db9](https://github.com/silverstripe/sapphire/commit/a415db9) Clone Config_LRU incl. objects in array (Ingo Schommer)
* 2013-03-26 [70144ad](https://github.com/silverstripe/sapphire/commit/70144ad) Groups should be able to have titles longer than 50 characters (Fixes: open/5611) (Will Rossiter)
* 2013-03-25 [0ebd525](https://github.com/silverstripe/silverstripe-cms/commit/0ebd525) Unset "underneath page" title when switching to "top" in "add page" (Ingo Schommer)
* 2013-03-25 [3f2b6a5](https://github.com/silverstripe/sapphire/commit/3f2b6a5) Don't silently unset ParentID in "add page" dialog (Ingo Schommer)
* 2013-03-25 [0a283ea](https://github.com/silverstripe/sapphire/commit/0a283ea) Unset internal metadata on TreeDropdownField setValue() (Ingo Schommer)
* 2013-03-25 [07d99a5](https://github.com/silverstripe/sapphire/commit/07d99a5) Fallback for Session.cookie_path (Ingo Schommer)
* 2013-03-25 [fbb4d1c](https://github.com/silverstripe/silverstripe-installer/commit/fbb4d1c) Update Page/Page_Controller statics to match new 3.1 expectations. (Sam Minnee)
* 2013-03-24 [27b0cda](https://github.com/silverstripe/sapphire/commit/27b0cda) Localized HtmlEditorField Tabs (a2nt)
* 2013-03-24 [9b9f367](https://github.com/silverstripe/sapphire/commit/9b9f367) Database config values aren't escaped (Stephen Shkardoon)
* 2013-03-22 [d3e4863](https://github.com/silverstripe/sapphire/commit/d3e4863) Incorrect parsing of T_STRING values in class spec parsing (Andrew Short)
* 2013-03-22 [47edbfe](https://github.com/silverstripe/sapphire/commit/47edbfe) ConfigStaticManifest persisting access level after parsing a static (Hamish Friedlander)
* 2013-03-21 [69ae1f3](https://github.com/silverstripe/sapphire/commit/69ae1f3) Clean cache on Config-&gt;remove() (Ingo Schommer)
* 2013-03-21 [bb52f2a](https://github.com/silverstripe/sapphire/commit/bb52f2a) Allow FALSE in Config API, call remove() will NULL key on update() (Ingo Schommer)
* 2013-03-20 [2787d36](https://github.com/silverstripe/sapphire/commit/2787d36) "Insert Link" and other TinyMCE loading bugs (fixes #8327) (Ingo Schommer)
* 2013-03-20 [143317c](https://github.com/silverstripe/sapphire/commit/143317c) SQL Injection in CsvBulkLoader (fixes #6227) (Stephen Shkardoon)
* 2013-03-19 [0d57f7b](https://github.com/silverstripe/sapphire/commit/0d57f7b) processAll method respects $preview flag (Daniel Hensby)
* 2013-03-19 [3020576](https://github.com/silverstripe/sapphire/commit/3020576) Adding preview method to CsvBulkLoader (Daniel Hensby)
* 2013-03-19 [9ac104b](https://github.com/silverstripe/sapphire/commit/9ac104b) $_COOKIES is not un-magic_quotes'd (Stephen Shkardoon)
* 2013-03-19 [d9f4a36](https://github.com/silverstripe/sapphire/commit/d9f4a36) #8328 Expose previously selected values of TreeMultiSelectField so they are not wipped out when selecting more values at an higher level in hierarchy (jean)
* 2013-03-18 [5c933b4](https://github.com/silverstripe/silverstripe-cms/commit/5c933b4) SilverStripeNavigator shows wrong message. (uniun)
* 2013-03-18 [3543a93](https://github.com/silverstripe/sapphire/commit/3543a93) SplFixedArray causes segfaults in old versions of PHP (Hamish Friedlander)
* 2013-03-18 [59e66f3](https://github.com/silverstripe/silverstripe-cms/commit/59e66f3) Ticket #8318 Append the HTML used for expanding/collapsing the site tree column in template instead of creating it on the fly with js (jean)
* 2013-03-15 [cd27bf7](https://github.com/silverstripe/sapphire/commit/cd27bf7) Enforced requirement that ValidationException::getResult() is expected to consistently produce a valid ValidationResult object. (Damian Mooyman)
* 2013-03-15 [412f58b](https://github.com/silverstripe/sapphire/commit/412f58b) #8322 Use POST instead of GET when using LeftAndMain::savetreenode so large site trees can be reorganised as well (jean)
* 2013-03-14 [746904c](https://github.com/silverstripe/sapphire/commit/746904c) Respect previous tab choices in CMS on load (Ingo Schommer)
* 2013-03-13 [53595dc](https://github.com/silverstripe/sapphire/commit/53595dc) Parsing docblock comments in ConfigStaticManifest (Hamish Friedlander)
* 2013-03-13 [60b72ed](https://github.com/silverstripe/sapphire/commit/60b72ed) Parsing heredoc, nowdoc & comments in ConfigStaticManifest (Hamish Friedlander)
* 2013-03-13 [2ba26ba](https://github.com/silverstripe/silverstripe-cms/commit/2ba26ba) 8316 Prevents browser default behaviour when changing the pagetypes if creating a new page (jean)
* 2013-03-12 [dd6f33a](https://github.com/silverstripe/sapphire/commit/dd6f33a) Respect tree node limits, fix search result node display (Ingo Schommer)
* 2013-03-12 [e6352df](https://github.com/silverstripe/sapphire/commit/e6352df) Static polution with informational fields (Hamish Friedlander)
* 2013-03-12 [7f58730](https://github.com/silverstripe/sapphire/commit/7f58730) Avoid get_parent_class in ConfigStaticManifest (was loading all classes) (Hamish Friedlander)
* 2013-03-11 [bb30c1e](https://github.com/silverstripe/sapphire/commit/bb30c1e) Preserve alpha channel when cropping (Fred Condo)
* 2013-03-12 [252e6bc](https://github.com/silverstripe/sapphire/commit/252e6bc) Make multiple TemplateManifests not corrupt each other (Hamish Friedlander)
* 2013-03-11 [2f16951](https://github.com/silverstripe/sapphire/commit/2f16951) ampersand escaping (g4b0)
* 2013-03-09 [a965d3b](https://github.com/silverstripe/sapphire/commit/a965d3b) Fix grid field rendering when the list is null (ajshort)
* 2013-03-07 [00d01aa](https://github.com/silverstripe/sapphire/commit/00d01aa) fixed file icon for uppercase file extensions (Zauberfisch)
* 2013-03-07 [13b7386](https://github.com/silverstripe/sapphire/commit/13b7386) Removed XHTML XML declaration requirement (g4b0)
* 2013-03-02 [b537ee2](https://github.com/silverstripe/sapphire/commit/b537ee2) Fix ManyManyList-&gt;removeAll() when filters are applied to the query (ajshort)
* 2013-03-01 [9a1ccd8](https://github.com/silverstripe/sapphire/commit/9a1ccd8) Prevent opening preview when clicking the link for current page again (Loz Calver)
* 2013-02-27 [eb2e0d7](https://github.com/silverstripe/silverstripe-cms/commit/eb2e0d7) Request object now has URL changed (Daniel Hensby)
* 2013-02-27 [68ebc5d](https://github.com/silverstripe/silverstripe-cms/commit/68ebc5d) CMSMainTest to access batch_action config property properly (Hamish Friedlander)
* 2013-02-27 [80bd38e](https://github.com/silverstripe/sapphire/commit/80bd38e) DataObjectSchemaGenerationTest trying to modify config statics directly (Hamish Friedlander)
* 2013-02-26 [a8a10f8](https://github.com/silverstripe/sapphire/commit/a8a10f8) Transaction stub methods for better cross 2.x and 3.x compat (Ingo Schommer)
* 2013-02-20 [a03d1e6](https://github.com/silverstripe/sapphire/commit/a03d1e6) CMS messages touch the bottom of the inputs (Daniel Hensby)
* 2013-02-20 [a193666](https://github.com/silverstripe/sapphire/commit/a193666) handleAction methods should be protected now (Hamish Friedlander)
* 2013-02-19 [4e36020](https://github.com/silverstripe/sapphire/commit/4e36020) UnsavedRelationList aren't checked (Daniel Hensby)
* 2013-02-19 [1cf2259](https://github.com/silverstripe/sapphire/commit/1cf2259) Undefined var (Daniel Hensby)
* 2013-02-18 [16d0c18](https://github.com/silverstripe/sapphire/commit/16d0c18) Find Form actions in CompositeFields for access checks (Ingo Schommer)
* 2013-02-18 [8d32ae9](https://github.com/silverstripe/sapphire/commit/8d32ae9) setBody on SS_HTTPRequest is a function (Daniel Hensby)
* 2013-02-17 [c7b0666](https://github.com/silverstripe/silverstripe-cms/commit/c7b0666) Escape page titles in CommentAdmin table listing (Ingo Schommer)
* 2013-02-07 [54bc18b](https://github.com/silverstripe/sapphire/commit/54bc18b) fix for broken layout in insert media dialog - Trac #8232 (Jeremy Bridson)
* 2013-01-15 [50995fb](https://github.com/silverstripe/sapphire/commit/50995fb) Undefined `$allowed_actions` overrides parent definitions, stricter handling of $allowed_actions on Extension (Ingo Schommer)
* 2013-01-14 [f7cd316](https://github.com/silverstripe/sapphire/commit/f7cd316) Versioned_Version-&gt;relField() so fields can be used in GridField etc (Ingo Schommer)
* 2013-01-06 [eecd348](https://github.com/silverstripe/sapphire/commit/eecd348) Keep Member.PasswordEncryption setting on empty passwords (Ingo Schommer)
* 2012-10-10 [e2bf964](https://github.com/silverstripe/sapphire/commit/e2bf964) 7934 When lazy loading fields respect version of the record (jean)
* 2012-10-05 [1ffbb8f](https://github.com/silverstripe/sapphire/commit/1ffbb8f) Exclude framework/dev from text collection (fixes #4754) (Ingo Schommer)
* 2012-09-10 [17bd873](https://github.com/silverstripe/sapphire/commit/17bd873) 7853 Flush the content of drop down fields when closing html editor linker (links and images) (jean)

View File

@ -42,7 +42,7 @@ Here is an example where we display a basic gridfield with the default settings:
:::php
class GridController extends Page_Controller {
private static $allowed_actions = array('index');
private static $allowed_actions = array('index', 'AllPages');
public function index(SS_HTTPRequest $request) {
$this->Content = $this->AllPages();
@ -331,4 +331,4 @@ records, use the `DataObject->can...()` methods
## Related
* [ModelAdmin: A UI driven by GridField](/reference/modeladmin)
* [Tutorial 5: Dataobject Relationship Management](/tutorials/5-dataobject-relationship-management)
* [Tutorial 5: Dataobject Relationship Management](/tutorials/5-dataobject-relationship-management)

View File

@ -13,12 +13,12 @@ sentence in a longer piece of text.
* `[api:Date]`: A date field
* `[api:Decimal]`: A decimal number.
* `[api:Enum]`: An enumeration of a set of strings
* `[api:HTMLText]`: A variable-length string of up to 2 megabytes, designed to store HTML
* `[api:HTMLText]`: A variable-length string of up to 2MB, designed to store HTML
* `[api:HTMLVarchar]`: A variable-length string of up to 255 characters, designed to store HTML
* `[api:Int]`: An integer field.
* `[api:Percentage]`: A decimal number between 0 and 1 that represents a percentage.
* `[api:SS_Datetime]`: A date / time field
* `[api:Text]`: A variable-length string of up to 2 megabytes, designed to store raw text
* `[api:Text]`: A variable-length string of up to 2MB, designed to store raw text
* `[api:Time]`: A time field
* `[api:Varchar]`: A variable-length string of up to 255 characters, designed to store raw text
@ -83,12 +83,15 @@ Example: Flagging an object of type `MyObject` (see above) if it's date is in th
## Casting HTML Text
The database field types `[api:HTMLVarchar]` and `[api:Varchar]` are exactly the same in the database. However, the
templating engine knows to escape the `[api:Varchar]` field and not the `[api:HTMLVarchar]` field. So, it's important you
use the right field if you don't want to be putting $FieldType.XML everywhere.
The database field types `[api:HTMLVarchar]`/`[api:HTMLText]` and `[api:Varchar]`/`[api:Text]`
are exactly the same in the database. However, the templating engine knows to escape
fields without the `HTML` prefix automatically in templates,
to prevent them from rendering HTML interpreted by browsers.
This escaping prevents attacks like CSRF or XSS (see "[security](/topics/security)"),
which is important if these fields store user-provided data.
If you're going to put HTML content into the field, please use the field type with the HTML prefix. Otherwise, you're
going to risk double-escaping your data, forgetting to escape your data, and generally creating a confusing situation.
You can disable this auto-escaping by using the `$MyField.RAW` escaping hints,
or explicitly request escaping of HTML content via `$MyHtmlField.XML`.
## Related

View File

@ -114,6 +114,7 @@ This is my `_ss_environment.php` file. I have it placed in `/var`, as each of th
| `SS_DATABASE_SUFFIX`| A suffix to add to the database name.|
| `SS_DATABASE_PREFIX`| A prefix to add to the database name.|
| `SS_DATABASE_TIMEZONE`| Set the database timezone to something other than the system timezone.
| `SS_DATABASE_NAME` | Set the database name. Assumes the `$database` global variable in your config is missing or empty. |
| `SS_DATABASE_CHOOSE_NAME`| Boolean/Int. If set, then the system will choose a default database name for you if one isn't give in the $database variable. The database name will be "SS_" followed by the name of the folder into which you have installed SilverStripe. If this is enabled, it means that the phpinstaller will work out of the box without the installer needing to alter any files. This helps prevent accidental changes to the environment. If `SS_DATABASE_CHOOSE_NAME` is an integer greater than one, then an ancestor folder will be used for the database name. This is handy for a site that's hosted from /sites/examplesite/www or /buildbot/allmodules-2.3/build. If it's 2, the parent folder will be chosen; if it's 3 the grandparent, and so on.|
| `SS_ENVIRONMENT_TYPE`| The environment type: dev, test or live.|
| `SS_DEFAULT_ADMIN_USERNAME`| The username of the default admin - this is a non-database user with administrative privileges.|

View File

@ -5,7 +5,9 @@
Editing and formatting content is the bread and butter of every content management system,
which is why SilverStripe has a tight integration with our preferred editor library, [TinyMCE](http://tinymce.com).
On top of the base functionality, we use our own insertion dialogs to ensure
you can effectively select and upload files.
you can effectively select and upload files. In addition to the markup managed by TinyMCE,
we use [shortcodes](/reference/shortcodes) to store information about inserted
images or media elements.
## Usage
@ -151,7 +153,12 @@ documentation, or browse through plugins that come with the Framework at `thirdp
The `[api:HtmlEditorField]` API also handles inserting images and media
files into the managed HTML content. It can be used both for referencing
files on the webserver filesystem (through the `[api:File]` and `[api:Image]` APIs),
as well as hotlinking files from the web.
as well as hotlinking files from the web.
We use [shortcodes](/reference/shortcodes) to store information about inserted images or media elements.
The `[api:ShortcodeParser]` API post-processes the HTML content on rendering,
and replaces the shortcodes accordingly. It also takes care of care of placing the
shortcode replacements relative to its surrounding markup (e.g. left/right alignment).
## oEmbed: Embedding media through external services
@ -168,6 +175,27 @@ a cache, append `?flush=1` to a URL.
To disable oEmbed usage, set the `Oembed.enabled` configuration property to "false".
### Doctypes
Since TinyMCE generates markup, it needs to know which doctype your documents
will be rendered in. You can set this through the [element_format](http://www.tinymce.com/wiki.php/Configuration:element_format) configuration variable. It defaults to the stricter 'xhtml'
setting, for example rendering self closing tags like `<br/>` instead of `<br>`.
In case you want to adhere to HTML4 instead, use the following configuration:
:::php
HtmlEditorConfig::get('cms')->setOption('element_format', 'html');
By default, TinyMCE and SilverStripe will generate valid HTML5 markup,
but it will strip out HTML5 tags like `<article>` or `<figure>`.
If you plan to use those, add them to the [valid_elements](http://www.tinymce.com/wiki.php/Configuration:valid_elements)
configuration setting.
Also, the `[api:SS_HTMLValue]` API underpinning the HTML processing parses the markup
into a temporary object tree which can be traversed and modified before saving.
The built-in parser only supports HTML4 and XHTML syntax. In order to successfully
process HTML5 tags, please use the
['silverstripe/html5' module](https://github.com/silverstripe/silverstripe-html5).
## Recipes
### Customizing the "Insert" panels

View File

@ -872,7 +872,7 @@ class File extends DataObject {
// TODO Merge this with Upload_Validator
$extension = $this->getExtension();
$allowed = array_map('strtolower', $this->config()->allowed_extensions);
if($extension && !in_array(strtolower($extension), $allowed)) {
if(!in_array(strtolower($extension), $allowed)) {
$exts = $allowed;
sort($exts);
$message = sprintf(

View File

@ -59,6 +59,13 @@ class ConfirmedPasswordField extends FormField {
*/
public $showOnClickTitle;
/**
* Child fields (_Password, _ConfirmPassword)
*
* @var FieldList
*/
public $children;
/**
* @param string $name
* @param string $title

View File

@ -15,7 +15,7 @@
* Example:
* <code>
* $field = new DatetimeField('Name', 'Label');
* $field->setConfig('datavalueformat', 'YYYY-MM-dd HH:mm'); // global setting
* $field->setConfig('datavalueformat', 'yyyy-MM-dd HH:mm'); // global setting
* $field->getDateField()->setConfig('showcalendar', 1); // field-specific setting
* </code>
*
@ -46,7 +46,7 @@ class DatetimeField extends FormField {
* @var array
*/
private static $default_config = array(
'datavalueformat' => 'YYYY-MM-dd HH:mm:ss',
'datavalueformat' => 'yyyy-MM-dd HH:mm:ss',
'usertimezone' => null,
'datetimeorder' => '%s %s',
);

View File

@ -164,7 +164,7 @@ class Form extends RequestHandler {
throw new InvalidArgumentException('$actions must be a valid FieldList instance');
}
if($validator && !$validator instanceof Validator) {
throw new InvalidArgumentException('$validator must be a Valdidator instance');
throw new InvalidArgumentException('$validator must be a Validator instance');
}
$fields->setForm($this);
@ -556,7 +556,7 @@ class Form extends RequestHandler {
* @return FieldList
*/
public function HiddenFields() {
return $this->fields->HiddenFields();
return $this->Fields()->HiddenFields();
}
/**
@ -564,7 +564,7 @@ class Form extends RequestHandler {
* Useful when making your own simplified form layouts.
*/
public function VisibleFields() {
return $this->fields->VisibleFields();
return $this->Fields()->VisibleFields();
}
/**

View File

@ -95,7 +95,7 @@ class HtmlEditorField extends TextareaField {
}
public function saveInto(DataObjectInterface $record) {
if($record->escapeTypeForField($this->name) != 'xml') {
if($record->hasField($this->name) && $record->escapeTypeForField($this->name) != 'xml') {
throw new Exception (
'HtmlEditorField->saveInto(): This field should save into a HTMLText or HTMLVarchar field.'
);

View File

@ -31,7 +31,6 @@ class PhoneNumberField extends FormField {
$fields = new FieldGroup( $this->name );
$fields->setID("{$this->name}_Holder");
list($countryCode, $areaCode, $phoneNumber, $extension) = $this->parseValue();
$hasTitle = false;
if ($this->value=="") {
$countryCode=$this->countryCode;
@ -51,7 +50,7 @@ class PhoneNumberField extends FormField {
}
if($this->ext !== null) {
$field->push(new NumericField( $this->name.'[Extension]', 'ext', $extension, 6));
$fields->push(new NumericField( $this->name.'[Extension]', 'ext', $extension, 6));
}
$description = $this->getDescription();
@ -62,7 +61,7 @@ class PhoneNumberField extends FormField {
$field->setReadonly($this->isReadonly());
}
return $field;
return $fields;
}
public function setValue( $value ) {

View File

@ -281,7 +281,7 @@ class UploadField extends FileField {
));
// we do this in a second customise to have the access to the previous customisations
return $file->customise(array(
'UploadFieldFileButtons' => $file->renderWith($this->getTemplateFileButtons())
'UploadFieldFileButtons' => (string)$file->renderWith($this->getTemplateFileButtons())
));
}

View File

@ -52,7 +52,7 @@ abstract class SS_HTMLValue extends ViewableData {
// Then replace the saved attributes with their original versions
$res = preg_replace_callback('/__HTMLVALUE_(\d+)/', function($matches) use ($attrs) {
return $attrs[$matches[0]];
return Convert::raw2att($attrs[$matches[0]]);
}, $res);
return $res;

View File

@ -4,11 +4,10 @@
* @package framework
* @subpackage model
*/
class Double extends DBField {
class Double extends Float {
public function requireField() {
// HACK: MSSQL does not support double so we're usinf float instead
// HACK: MSSQL does not support double so we're using float instead
// @todo This should go into MSSQLDatabase ideally somehow
if(DB::getConn() instanceof MySQLDatabase) {
DB::requireField($this->tableName, $this->name, "double");
@ -16,36 +15,4 @@ class Double extends DBField {
DB::requireField($this->tableName, $this->name, "float");
}
}
public function Nice() {
return number_format($this->value, 2);
}
/**
* Returns the value to be set in the database to blank this field.
* Usually it's a choice between null, 0, and ''
*/
public function nullValue() {
return 0;
}
/**
* Return an encoding of the given value suitable for inclusion in a SQL statement.
* If necessary, this should include quotes.
*/
public function prepValueForDB($value) {
if($value === true) {
return 1;
}
if(!$value || !is_numeric($value)) {
if(strpos($value, '[') === false) {
return '0';
} else {
return Convert::raw2sql($value);
}
} else {
return Convert::raw2sql($value);
}
}
}

View File

@ -182,7 +182,7 @@ class BBCodeParser extends TextParser {
$this->content = preg_replace("/\n\s*\n/", "</p><p>", $this->content);
$this->content = str_replace("\n", "<br />", $this->content);
if(BBCodeParser::smiliesAllowed()) {
if($this->config()->allow_smilies) {
$smilies = array(
'#(?<!\w):D(?!\w)#i' => " <img src='".BBCodeParser::smilies_location(). "/grin.gif'> ", // :D
'#(?<!\w):\)(?!\w)#i' => " <img src='".BBCodeParser::smilies_location(). "/smile.gif'> ", // :)

View File

@ -151,7 +151,7 @@ class ShortcodeParser {
(?:
(?:\'([^\']+)\') | # Value surrounded by \'
(?:"([^"]+)") | # Value surrounded by "
(\w+) # Bare value
([^\s,\]]+) # Bare value
)
';

View File

@ -165,7 +165,7 @@ $gf_grid_x: 16px;
// The last column (buttons) should always shrink to fit.
// Overwritten for IE7, which doesnt support this.
&.col-buttons {
width: auto;
width: 1px;
padding:0 $gf_grid_x/2;
text-align: right;
white-space: nowrap;
@ -343,7 +343,7 @@ $gf_grid_x: 16px;
min-width: $gf_grid_x*12.5;
padding-right:0;
&.filter-buttons{
min-width:0;
min-width:49px;
box-shadow: none;
border: none;
div{

View File

@ -69,7 +69,8 @@ class Group extends DataObject {
$parentidfield = DropdownField::create( 'ParentID',
$this->fieldLabel('Parent'),
Group::get()->exclude('ID', $this->ID)->map('ID', 'Breadcrumbs')
)->setEmptyString(' ')
)->setEmptyString(' '),
new TextareaField('Description', $this->fieldLabel('Description'))
),
$permissionsTab = new Tab('Permissions', _t('SecurityAdmin.PERMISSIONS', 'Permissions'),

View File

@ -809,7 +809,7 @@ class Security extends Controller {
public static function set_password_encryption_algorithm($algorithm) {
Deprecation::notice('3.2', 'Use the "Security.password_encryption_algorithm" config setting instead');
self::config()->encryption_algorithm = $algorithm;
self::config()->password_encryption_algorithm = $algorithm;
}
/**
@ -818,7 +818,7 @@ class Security extends Controller {
*/
public static function get_password_encryption_algorithm() {
Deprecation::notice('3.2', 'Use the "Security.password_encryption_algorithm" config setting instead');
return self::config()->encryption_algorithm;
return self::config()->password_encryption_algorithm;
}
/**

View File

@ -5,9 +5,9 @@
</head>
<body>
<p class="body">
<div class="body">
$Body
</p>
</div>
</body>
</html>
</html>

View File

@ -187,6 +187,18 @@ class HTTPTest extends SapphireTest {
});
}
public function testEmailLinks() {
$this->withBaseURL('http://www.silverstripe.org/', function($test){
// links
$test->assertEquals(
'<a href=\'mailto:admin@silverstripe.org\'>Email Us</a>',
HTTP::absoluteURLs('<a href=\'mailto:admin@silverstripe.org\'>Email Us</a>')
);
});
}
/**
* Run a test while mocking the base url with the provided value
* @param string $url The base URL to use for this test

View File

@ -107,7 +107,10 @@ class ClassManifestTest extends SapphireTest {
}
public function testGetModules() {
$expect = array("module" => "{$this->base}/module");
$expect = array(
"module" => "{$this->base}/module",
"moduleb" => "{$this->base}/moduleb"
);
$this->assertEquals($expect, $this->manifest->getModules());
$this->assertEquals($expect, $this->manifestTests->getModules());
}

View File

@ -111,7 +111,10 @@ class NamespacedClassManifestTest extends SapphireTest {
}
public function testGetModules() {
$expect = array("module" => "{$this->base}/module");
$expect = array(
"module" => "{$this->base}/module",
"moduleb" => "{$this->base}/moduleb"
);
$this->assertEquals($expect, $this->manifest->getModules());
}
}

View File

@ -151,7 +151,10 @@ class CsvBulkLoaderTest extends SapphireTest {
$loader = new CsvBulkLoader('CsvBulkLoaderTest_Player');
$filepath = $this->getCurrentAbsolutePath() . '/CsvBulkLoaderTest_PlayersWithId.csv';
$loader->duplicateChecks = array(
'ExternalIdentifier' => 'ExternalIdentifier'
'ExternalIdentifier' => 'ExternalIdentifier',
'NonExistantIdentifier' => 'ExternalIdentifier',
'ExternalIdentifier' => 'ExternalIdentifier',
'AdditionalIdentifier' => 'ExternalIdentifier'
);
$results = $loader->load($filepath);
$createdPlayers = $results->Created();

View File

@ -1,4 +1,5 @@
"ExternalIdentifier","FirstName","Biography","Birthday"
222b,"John","","31/01/1988"
222b,"John","He's a good guy",""
9000a,"Jamie","Pretty old\, with an escaped comma","31/01/1882"
"ExternalIdentifier","FirstName","Biography","Birthday"," AdditionalIdentifier "
222b,"John","","31/01/1988",""
222b,"John","He's a good guy","",""
9000a,"Jamie","Pretty old\, with an escaped comma","31/01/1882",""
,"Fiona","A wise woman","","sql'unsafeid"
Can't render this file because it contains an unexpected character in line 1 and column 81.

View File

@ -58,4 +58,13 @@ class SS_HTML4ValueTest extends SapphireTest {
);
}
public function testAttributeEscaping() {
$value = new SS_HTML4Value();
$value->setContent('<a href="[]"></a>');
$this->assertEquals('<a href="[]"></a>', $value->getContent(), "'[' character isn't escaped");
$value->setContent('<a href="&quot;"></a>');
$this->assertEquals('<a href="&quot;"></a>', $value->getContent(), "'\"' character is escaped");
}
}

View File

@ -150,13 +150,13 @@ class ShortcodeParserTest extends SapphireTest {
}
public function testUnquotedArguments() {
$this->assertEquals('', $this->parser->parse('[test_shortcode,foo=bar,baz = buz]'));
$this->assertEquals(array('foo' => 'bar', 'baz' => 'buz'), $this->arguments);
$this->assertEquals('', $this->parser->parse('[test_shortcode,foo=bar!,baz = buz123]'));
$this->assertEquals(array('foo' => 'bar!', 'baz' => 'buz123'), $this->arguments);
}
public function testSpacesForDelimiter() {
$this->assertEquals('', $this->parser->parse('[test_shortcode foo=bar baz = buz]'));
$this->assertEquals(array('foo' => 'bar', 'baz' => 'buz'), $this->arguments);
$this->assertEquals('', $this->parser->parse('[test_shortcode foo=bar! baz = buz123]'));
$this->assertEquals(array('foo' => 'bar!', 'baz' => 'buz123'), $this->arguments);
}
public function testSelfClosingTag() {

View File

@ -0,0 +1,6 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head></head>
<body></body>
</html>

View File

@ -0,0 +1,7 @@
<!doctype html>
<!--[if lte IE 8]> <html class='old-ie'> <![endif]-->
<!--[if gt IE 8]> <html class='new-ie'> <![endif]-->
<!--[if !IE]><!--> <html class='no-ie'> <!--<![endif]-->
<head></head>
<body></body>
</html>

View File

@ -0,0 +1,6 @@
<!--[if lte IE 8]> <html class='old-ie'> <![endif]-->
<!--[if gt IE 8]> <html class='new-ie'> <![endif]-->
<!--[if !IE]><!--> <html class='no-ie'> <!--<![endif]-->
<head></head>
<body></body>
</html>

View File

@ -0,0 +1,4 @@
<html>
<head></head>
<body></body>
</html>

View File

@ -448,6 +448,14 @@ after')
$this->assertEquals('ACD', $this->render('A<% if 4 > 4 %>B<% else %>C<% end_if %>D'));
$this->assertEquals('ACD', $this->render('A<% if 4 < 4 %>B<% else %>C<% end_if %>D'));
// empty else_if and else tags, if this would not be supported,
// the output would stop after A, thereby failing the assert
$this->assertEquals('AD', $this->render('A<% if IsSet %><% else %><% end_if %>D'));
$this->assertEquals('AD',
$this->render('A<% if NotSet %><% else_if IsSet %><% else %><% end_if %>D'));
$this->assertEquals('AD',
$this->render('A<% if NotSet %><% else_if AlsoNotSet %><% else %><% end_if %>D'));
// Bare words with ending space
$this->assertEquals('ABC',
$this->render('A<% if "RawVal" == RawVal %>B<% end_if %>C'));
@ -1054,43 +1062,98 @@ after')
$origEnv = Config::inst()->get('Director', 'environment_type');
Config::inst()->update('Director', 'environment_type', 'dev');
Config::inst()->update('SSViewer', 'source_file_comments', true);
$view = new SSViewer(array('SSViewerTestCommentsFullSource'));
$data = new ArrayData(array());
$result = $view->process($data);
$expected = '<!doctype html>
<html><!-- template ' . FRAMEWORK_PATH . '/tests/templates/SSViewerTestCommentsFullSource.ss -->
<head></head>
<body></body>
<!-- end template ' . FRAMEWORK_PATH . '/tests/templates/SSViewerTestCommentsFullSource.ss --></html>
';
$this->assertEquals($result, $expected);
$view = new SSViewer(array('SSViewerTestCommentsPartialSource'));
$data = new ArrayData(array());
$result = $view->process($data);
$expected = '<!-- template ' . FRAMEWORK_PATH . '/tests/templates/SSViewerTestCommentsPartialSource.ss -->'
. '<div class=\'typography\'></div><!-- end template ' . FRAMEWORK_PATH
. '/tests/templates/SSViewerTestCommentsPartialSource.ss -->';
$this->assertEquals($result, $expected);
$view = new SSViewer(array('SSViewerTestCommentsWithInclude'));
$data = new ArrayData(array());
$result = $view->process($data);
$expected = '<!-- template ' . FRAMEWORK_PATH . '/tests/templates/SSViewerTestCommentsWithInclude.ss -->'
. '<div class=\'typography\'><!-- include \'SSViewerTestCommentsInclude\' --><!-- template '
. FRAMEWORK_PATH . '/tests/templates/SSViewerTestCommentsInclude.ss -->Included<!-- end template '
. FRAMEWORK_PATH . '/tests/templates/SSViewerTestCommentsInclude.ss -->'
. '<!-- end include \'SSViewerTestCommentsInclude\' --></div><!-- end template ' . FRAMEWORK_PATH
. '/tests/templates/SSViewerTestCommentsWithInclude.ss -->';
$this->assertEquals($result, $expected);
$f = FRAMEWORK_PATH . '/tests/templates/SSViewerTestComments';
$templates = array(
array(
'name' => 'SSViewerTestCommentsFullSource',
'expected' => ""
. "<!doctype html>"
. "<!-- template $f/SSViewerTestCommentsFullSource.ss -->"
. "<html>"
. "\t<head></head>"
. "\t<body></body>"
. "</html>"
. "<!-- end template $f/SSViewerTestCommentsFullSource.ss -->",
),
array(
'name' => 'SSViewerTestCommentsFullSourceHTML4Doctype',
'expected' => ""
. "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\t\t\"http://www.w3.org/TR/html4/strict.dtd\">"
. "<!-- template $f/SSViewerTestCommentsFullSourceHTML4Doctype.ss -->"
. "<html>"
. "\t<head></head>"
. "\t<body></body>"
. "</html>"
. "<!-- end template $f/SSViewerTestCommentsFullSourceHTML4Doctype.ss -->",
),
array(
'name' => 'SSViewerTestCommentsFullSourceNoDoctype',
'expected' => ""
. "<html><!-- template $f/SSViewerTestCommentsFullSourceNoDoctype.ss -->"
. "\t<head></head>"
. "\t<body></body>"
. "<!-- end template $f/SSViewerTestCommentsFullSourceNoDoctype.ss --></html>",
),
array(
'name' => 'SSViewerTestCommentsFullSourceIfIE',
'expected' => ""
. "<!doctype html>"
. "<!-- template $f/SSViewerTestCommentsFullSourceIfIE.ss -->"
. "<!--[if lte IE 8]> <html class='old-ie'> <![endif]-->"
. "<!--[if gt IE 8]> <html class='new-ie'> <![endif]-->"
. "<!--[if !IE]><!--> <html class='no-ie'> <!--<![endif]-->"
. "\t<head></head>"
. "\t<body></body>"
. "</html>"
. "<!-- end template $f/SSViewerTestCommentsFullSourceIfIE.ss -->",
),
array(
'name' => 'SSViewerTestCommentsFullSourceIfIENoDoctype',
'expected' => ""
. "<!--[if lte IE 8]> <html class='old-ie'> <![endif]-->"
. "<!--[if gt IE 8]> <html class='new-ie'> <![endif]-->"
. "<!--[if !IE]><!--> <html class='no-ie'>"
. "<!-- template $f/SSViewerTestCommentsFullSourceIfIENoDoctype.ss -->"
. " <!--<![endif]-->"
. "\t<head></head>"
. "\t<body></body>"
. "<!-- end template $f/SSViewerTestCommentsFullSourceIfIENoDoctype.ss --></html>",
),
array(
'name' => 'SSViewerTestCommentsPartialSource',
'expected' =>
"<!-- template $f/SSViewerTestCommentsPartialSource.ss -->"
. "<div class='typography'></div>"
. "<!-- end template $f/SSViewerTestCommentsPartialSource.ss -->",
),
array(
'name' => 'SSViewerTestCommentsWithInclude',
'expected' =>
"<!-- template $f/SSViewerTestCommentsWithInclude.ss -->"
. "<div class='typography'>"
. "<!-- include 'SSViewerTestCommentsInclude' -->"
. "<!-- template $f/SSViewerTestCommentsInclude.ss -->"
. "Included"
. "<!-- end template $f/SSViewerTestCommentsInclude.ss -->"
. "<!-- end include 'SSViewerTestCommentsInclude' -->"
. "</div>"
. "<!-- end template $f/SSViewerTestCommentsWithInclude.ss -->",
),
);
foreach ($templates as $template) {
$this->_renderWithSourceFileComments($template['name'], $template['expected']);
}
Config::inst()->update('SSViewer', 'source_file_comments', false);
Config::inst()->update('Director', 'environment_type', $origEnv);
}
private function _renderWithSourceFileComments($name, $expected) {
$viewer = new SSViewer(array($name));
$data = new ArrayData(array());
$result = $viewer->process($data);
$expected = str_replace(array("\r", "\n"), '', $expected);
$result = str_replace(array("\r", "\n"), '', $result);
$this->assertEquals($result, $expected);
}
public function testLoopIteratorIterator() {
$list = new PaginatedList(new ArrayList());

View File

@ -62,10 +62,10 @@
var content = jQuery(o.content);
content.find('.ss-htmleditorfield-file.embed').each(function() {
var el = jQuery(this);
var shortCode = '[embed width=' + el.data('width')
+ ' height=' + el.data('height')
+ ' class=' + el.data('cssclass')
+ ' thumbnail=' + el.data('thumbnail')
var shortCode = '[embed width="' + el.data('width') + '"'
+ ' height="' + el.data('height') + '"'
+ ' class="' + el.data('cssclass') + '"'
+ ' thumbnail="' + el.data('thumbnail') + '"'
+ ']' + el.data('url')
+ '[/embed]';
el.replaceWith(shortCode);

View File

@ -1535,7 +1535,7 @@ class SSTemplateParser extends Parser {
}
/* ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' Template:$TemplateMatcher */
/* ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' Template:$TemplateMatcher? */
protected $match_ElseIfPart_typestack = array('ElseIfPart');
function match_ElseIfPart ($stack = array()) {
$matchrule = "ElseIfPart"; $result = $this->construct($matchrule, $matchrule, null);
@ -1557,12 +1557,19 @@ class SSTemplateParser extends Parser {
if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; }
else { $_240 = FALSE; break; }
$res_239 = $result;
$pos_239 = $this->pos;
$matcher = 'match_'.$this->expression($result, $stack, 'TemplateMatcher'); $key = $matcher; $pos = $this->pos;
$subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
if ($subres !== FALSE) {
$this->store( $result, $subres, "Template" );
}
else { $_240 = FALSE; break; }
else {
$result = $res_239;
$this->pos = $pos_239;
unset( $res_239 );
unset( $pos_239 );
}
$_240 = TRUE; break;
}
while(0);
@ -1571,7 +1578,7 @@ class SSTemplateParser extends Parser {
}
/* ElsePart: '<%' < 'else' > '%>' Template:$TemplateMatcher */
/* ElsePart: '<%' < 'else' > '%>' Template:$TemplateMatcher? */
protected $match_ElsePart_typestack = array('ElsePart');
function match_ElsePart ($stack = array()) {
$matchrule = "ElsePart"; $result = $this->construct($matchrule, $matchrule, null);
@ -1585,12 +1592,19 @@ class SSTemplateParser extends Parser {
if (( $subres = $this->whitespace( ) ) !== FALSE) { $result["text"] .= $subres; }
if (( $subres = $this->literal( '%>' ) ) !== FALSE) { $result["text"] .= $subres; }
else { $_248 = FALSE; break; }
$res_247 = $result;
$pos_247 = $this->pos;
$matcher = 'match_'.$this->expression($result, $stack, 'TemplateMatcher'); $key = $matcher; $pos = $this->pos;
$subres = ( $this->packhas( $key, $pos ) ? $this->packread( $key, $pos ) : $this->packwrite( $key, $pos, $this->$matcher(array_merge($stack, array($result))) ) );
if ($subres !== FALSE) {
$this->store( $result, $subres, "Template" );
}
else { $_248 = FALSE; break; }
else {
$result = $res_247;
$this->pos = $pos_247;
unset( $res_247 );
unset( $pos_247 );
}
$_248 = TRUE; break;
}
while(0);
@ -1661,14 +1675,14 @@ class SSTemplateParser extends Parser {
function If_ElseIfPart(&$res, $sub) {
$res['php'] .=
'else if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL .
$sub['Template']['php'] . PHP_EOL .
(isset($sub['Template']) ? $sub['Template']['php'] : '') . PHP_EOL .
'}';
}
function If_ElsePart(&$res, $sub) {
$res['php'] .=
'else { ' . PHP_EOL .
$sub['Template']['php'] . PHP_EOL .
(isset($sub['Template']) ? $sub['Template']['php'] : '') . PHP_EOL .
'}';
}
@ -4576,23 +4590,47 @@ class SSTemplateParser extends Parser {
// Get the result
$code = $result['php'];
}
// Include top level debugging comments if desired
if($includeDebuggingComments && $templateName && stripos($code, "<?xml") === false) {
// If this template is a full HTML page, then put the comments just inside the HTML tag to prevent any IE
// glitches
if(stripos($code, "<html") !== false) {
$code = preg_replace('/(<html[^>]*>)/i', "\\1<!-- template $templateName -->", $code);
$code = preg_replace('/(<\/html[^>]*>)/i', "<!-- end template $templateName -->\\1", $code);
} else {
$code = str_replace('<?php' . PHP_EOL, '<?php' . PHP_EOL . '$val .= \'<!-- template ' . $templateName .
' -->\';' . "\n", $code);
$code .= "\n" . '$val .= \'<!-- end template ' . $templateName . ' -->\';';
}
$code = $parser->includeDebuggingComments($code, $templateName);
}
return $code;
}
/**
* @param string $code
* @return string $code
*/
protected function includeDebuggingComments($code, $templateName) {
// If this template contains a doctype, put it right after it,
// if not, put it after the <html> tag to avoid IE glitches
if(stripos($code, "<!doctype") !== false) {
$code = preg_replace('/(<!doctype[^>]*("[^"]")*[^>]*>)/im', "$1\r\n<!-- template $templateName -->", $code);
$code .= "\r\n" . '$val .= \'<!-- end template ' . $templateName . ' -->\';';
} elseif(stripos($code, "<html") !== false) {
$code = preg_replace_callback('/(.*)(<html[^>]*>)(.*)/i', function($matches) use ($templateName) {
if (stripos($matches[3], '<!--') === false && stripos($matches[3], '-->') !== false) {
// after this <html> tag there is a comment close but no comment has been opened
// this most likely means that this <html> tag is inside a comment
// we should not add a comment inside a comment (invalid html)
// lets append it at the end of the comment
// an example case for this is the html5boilerplate: <!--[if IE]><html class="ie"><![endif]-->
return $matches[0];
} else {
// all other cases, add the comment and return it
return "{$matches[1]}{$matches[2]}<!-- template $templateName -->{$matches[3]}";
}
}, $code);
$code = preg_replace('/(<\/html[^>]*>)/i', "<!-- end template $templateName -->$1", $code);
} else {
$code = str_replace('<?php' . PHP_EOL, '<?php' . PHP_EOL . '$val .= \'<!-- template ' . $templateName .
' -->\';' . "\r\n", $code);
$code .= "\r\n" . '$val .= \'<!-- end template ' . $templateName . ' -->\';';
}
return $code;
}
/**
* Compiles some file that contains template source code, and returns the php code that will execute as per that

View File

@ -417,8 +417,8 @@ class SSTemplateParser extends Parser {
# argument structure to every other block
IfPart: '<%' < 'if' [ :IfArgument > '%>' Template:$TemplateMatcher?
ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' Template:$TemplateMatcher
ElsePart: '<%' < 'else' > '%>' Template:$TemplateMatcher
ElseIfPart: '<%' < 'else_if' [ :IfArgument > '%>' Template:$TemplateMatcher?
ElsePart: '<%' < 'else' > '%>' Template:$TemplateMatcher?
If: IfPart ElseIfPart* ElsePart? '<%' < 'end_if' > '%>'
*/
@ -432,14 +432,14 @@ class SSTemplateParser extends Parser {
function If_ElseIfPart(&$res, $sub) {
$res['php'] .=
'else if (' . $sub['IfArgument']['php'] . ') { ' . PHP_EOL .
$sub['Template']['php'] . PHP_EOL .
(isset($sub['Template']) ? $sub['Template']['php'] : '') . PHP_EOL .
'}';
}
function If_ElsePart(&$res, $sub) {
$res['php'] .=
'else { ' . PHP_EOL .
$sub['Template']['php'] . PHP_EOL .
(isset($sub['Template']) ? $sub['Template']['php'] : '') . PHP_EOL .
'}';
}
@ -1044,23 +1044,47 @@ class SSTemplateParser extends Parser {
// Get the result
$code = $result['php'];
}
// Include top level debugging comments if desired
if($includeDebuggingComments && $templateName && stripos($code, "<?xml") === false) {
// If this template is a full HTML page, then put the comments just inside the HTML tag to prevent any IE
// glitches
if(stripos($code, "<html") !== false) {
$code = preg_replace('/(<html[^>]*>)/i', "\\1<!-- template $templateName -->", $code);
$code = preg_replace('/(<\/html[^>]*>)/i', "<!-- end template $templateName -->\\1", $code);
} else {
$code = str_replace('<?php' . PHP_EOL, '<?php' . PHP_EOL . '$val .= \'<!-- template ' . $templateName .
' -->\';' . "\n", $code);
$code .= "\n" . '$val .= \'<!-- end template ' . $templateName . ' -->\';';
}
$code = $parser->includeDebuggingComments($code, $templateName);
}
return $code;
}
/**
* @param string $code
* @return string $code
*/
protected function includeDebuggingComments($code, $templateName) {
// If this template contains a doctype, put it right after it,
// if not, put it after the <html> tag to avoid IE glitches
if(stripos($code, "<!doctype") !== false) {
$code = preg_replace('/(<!doctype[^>]*("[^"]")*[^>]*>)/im', "$1\r\n<!-- template $templateName -->", $code);
$code .= "\r\n" . '$val .= \'<!-- end template ' . $templateName . ' -->\';';
} elseif(stripos($code, "<html") !== false) {
$code = preg_replace_callback('/(.*)(<html[^>]*>)(.*)/i', function($matches) use ($templateName) {
if (stripos($matches[3], '<!--') === false && stripos($matches[3], '-->') !== false) {
// after this <html> tag there is a comment close but no comment has been opened
// this most likely means that this <html> tag is inside a comment
// we should not add a comment inside a comment (invalid html)
// lets append it at the end of the comment
// an example case for this is the html5boilerplate: <!--[if IE]><html class="ie"><![endif]-->
return $matches[0];
} else {
// all other cases, add the comment and return it
return "{$matches[1]}{$matches[2]}<!-- template $templateName -->{$matches[3]}";
}
}, $code);
$code = preg_replace('/(<\/html[^>]*>)/i', "<!-- end template $templateName -->$1", $code);
} else {
$code = str_replace('<?php' . PHP_EOL, '<?php' . PHP_EOL . '$val .= \'<!-- template ' . $templateName .
' -->\';' . "\r\n", $code);
$code .= "\r\n" . '$val .= \'<!-- end template ' . $templateName . ' -->\';';
}
return $code;
}
/**
* Compiles some file that contains template source code, and returns the php code that will execute as per that