From 60f75c5ca45e4f420bd838af412ed176f279e9a3 Mon Sep 17 00:00:00 2001
From: Andrew O'Neil
Date: Sun, 1 Feb 2009 23:49:53 +0000
Subject: [PATCH] Merged changes from 2.3 branch
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@71172 467b73ca-7a2a-4603-9d3b-597d59a354a9
---
_config.php | 6 +-
api/RSSFeed.php | 3 +-
api/RestfulServer.php | 5 +
api/RestfulService.php | 13 +-
api/XMLDataFormatter.php | 4 +-
cli/CliController.php | 11 +-
core/ClassInfo.php | 26 ++-
core/Core.php | 1 -
core/HTTP.php | 10 +-
core/ManifestBuilder.php | 3 +-
core/Object.php | 8 +-
core/Requirements.php | 42 ++---
core/SSViewer.php | 22 ++-
core/Session.php | 2 +-
core/ViewableData.php | 4 +-
core/control/ContentController.php | 35 ++--
core/control/ContentNegotiator.php | 11 +-
core/control/Controller.php | 2 +-
core/control/HTTPRequest.php | 2 +-
core/control/ModelAsController.php | 2 +-
core/control/RootURLController.php | 2 +-
core/i18n.php | 26 ++-
core/i18nEntityProvider.php | 17 ++
core/i18nTextCollector.php | 12 +-
core/model/DB.php | 2 +-
core/model/DataObject.php | 15 +-
core/model/DataObjectDecorator.php | 26 ++-
core/model/DataObjectSet.php | 83 ++++++++-
core/model/Database.php | 9 +-
core/model/ErrorPage.php | 12 ++
core/model/Hierarchy.php | 15 +-
core/model/Image.php | 2 +-
core/model/MySQLDatabase.php | 5 +-
core/model/PDODatabase.php | 3 +-
core/model/SQLQuery.php | 2 +-
core/model/SiteTree.php | 120 +++++++-----
core/model/Versioned.php | 23 ++-
core/model/VirtualPage.php | 2 +-
core/model/fieldtypes/DBField.php | 3 +-
core/model/fieldtypes/Decimal.php | 4 +
core/model/fieldtypes/Int.php | 2 +-
core/model/fieldtypes/SSDatetime.php | 6 +-
core/model/fieldtypes/Text.php | 2 +-
core/model/fieldtypes/Varchar.php | 6 +-
css/CalendarDateField.css | 11 +-
css/ComplexTableField_popup.css | 14 +-
css/Form.css | 22 ++-
css/MemberProfileForm.css | 5 -
css/SilverStripeNavigator.css | 77 +++-----
css/TableListField.css | 3 +-
dev/BulkLoader.php | 11 +-
dev/DevelopmentAdmin.php | 2 +-
dev/InstallerTest.php | 2 +-
dev/ModelViewer.php | 3 +-
dev/SSCli.php | 2 +-
dev/SapphireTest.php | 2 +-
email/Email.php | 74 ++++----
email/Mailer.php | 3 +-
email/QueuedEmail.php | 8 +-
filesystem/File.php | 13 +-
filesystem/Filesystem.php | 2 +-
filesystem/Folder.php | 4 +-
filesystem/GD.php | 2 +-
forms/CheckboxSetField.php | 106 ++++++-----
forms/ComplexTableField.php | 28 +--
forms/CompositeDateField.php | 2 +-
forms/CountryDropdownField.php | 2 +-
forms/DateField.php | 9 +-
forms/FieldGroup.php | 17 +-
forms/FieldSet.php | 2 +-
forms/FileField.php | 4 +-
forms/Form.php | 2 +
forms/FormAction.php | 9 +-
forms/FormField.php | 7 +-
forms/GSTNumberField.php | 2 +-
forms/HasManyComplexTableField.php | 68 ++-----
forms/HtmlEditorField.php | 27 ++-
forms/ImageField.php | 1 -
forms/ImageFormAction.php | 2 +-
forms/ListboxField.php | 2 +-
forms/LookupField.php | 2 +-
forms/ManyManyComplexTableField.php | 38 +---
forms/NumericField.php | 2 +-
forms/PasswordField.php | 2 +-
forms/PhoneNumberField.php | 2 +-
forms/PopupDateTimeField.php | 15 ++
forms/ReportField.php | 1 -
forms/ResetFormAction.php | 31 +++-
forms/Tab.php | 5 +-
forms/TabSet.php | 2 +-
forms/TableField.php | 4 +-
forms/TableListField.php | 39 ++--
forms/TextareaField.php | 2 +-
forms/TreeDropdownField.php | 2 +-
javascript/Security_login.js | 127 -------------
javascript/TableListField.js | 6 +-
javascript/TreeSelectorField.js | 2 +-
main.php | 5 +-
parsers/BBCodeParser.php | 2 +-
parsers/HTML/HTMLBBCodeParser.php | 17 +-
profiler/Profiler.php | 2 +-
sake | 13 +-
search/AdvancedSearchForm.php | 1 -
search/SearchForm.php | 103 +++++++----
security/Authenticator.php | 1 -
security/ChangePasswordForm.php | 1 -
security/Group.php | 10 +-
security/LoginAttempt.php | 6 +
security/Member.php | 171 +++++++++---------
security/MemberAuthenticator.php | 1 -
security/MemberLoginForm.php | 17 +-
security/MemberPassword.php | 8 +-
security/Permission.php | 42 ++++-
security/Security.php | 35 ++--
tasks/HourlyTask.php | 2 +-
tasks/MonthlyTask.php | 2 +-
tasks/ScheduledTask.php | 2 +-
templates/ComplexTableField.ss | 2 +-
templates/GoogleSitemap.ss | 11 --
templates/RelationComplexTableField.ss | 2 +-
tests/ClassInfoTest.php | 33 ++++
tests/HTTPTest.php | 15 ++
tests/api/RestfulServiceTest.php | 1 +
tests/dev/CsvBulkLoaderTest.php | 21 ++-
tests/dev/CsvBulkLoaderTest_Players.csv | 5 +-
.../CsvBulkLoaderTest_PlayersWithHeader.csv | 8 +-
tests/fieldtypes/DateTest.php | 44 +++++
tests/forms/DateFieldTest.php | 39 ++++
widgets/Widget.php | 7 +-
widgets/WidgetArea.php | 7 +
130 files changed, 1246 insertions(+), 833 deletions(-)
delete mode 100755 templates/GoogleSitemap.ss
create mode 100644 tests/ClassInfoTest.php
create mode 100644 tests/fieldtypes/DateTest.php
create mode 100644 tests/forms/DateFieldTest.php
diff --git a/_config.php b/_config.php
index 5542c8b70..41198ca91 100644
--- a/_config.php
+++ b/_config.php
@@ -25,7 +25,6 @@ Director::addRules(10, array(
'$Controller//$Action/$ID/$OtherID' => '*',
'images' => 'Image_Uploader',
'' => 'RootURLController',
- 'sitemap.xml' => 'GoogleSitemap',
'api/v1' => 'RestfulServer',
'soap/v1' => 'SOAPModelAccess',
'dev' => 'DevelopmentAdmin',
@@ -47,7 +46,7 @@ Object::useCustomClass('Datetime','SSDatetime',true);
* Add pear parser to include path
*/
$path = Director::baseFolder().'/sapphire/parsers/';
-set_include_path(get_include_path() . PATH_SEPARATOR . $path);
+set_include_path(str_replace('.' . PATH_SEPARATOR, '.' . PATH_SEPARATOR . $path . PATH_SEPARATOR, get_include_path()));
/**
* Define a default language different than english
@@ -70,7 +69,4 @@ define('MCE_ROOT', 'jsparty/tiny_mce2/');
*/
define('EMAIL_BOUNCEHANDLER_KEY', '1aaaf8fb60ea253dbf6efa71baaacbb3');
-
-
-
?>
\ No newline at end of file
diff --git a/api/RSSFeed.php b/api/RSSFeed.php
index 273c10169..73a88396e 100755
--- a/api/RSSFeed.php
+++ b/api/RSSFeed.php
@@ -193,6 +193,7 @@ class RSSFeed extends ViewableData {
* Return the content of the RSS feed
*/
function feedContent() {
+ SSViewer::set_source_file_comments(false);
return str_replace(' ', ' ', $this->renderWith('RSSFeed'));
}
}
@@ -301,4 +302,4 @@ class RSSFeed_Entry extends ViewableData {
else user_error($this->failover->class . " object has either an AbsoluteLink nor a Link method. Can't put a link in the RSS feed", E_USER_WARNING);
}
}
-?>
+?>
\ No newline at end of file
diff --git a/api/RestfulServer.php b/api/RestfulServer.php
index a861ff6ba..e764bf3f8 100644
--- a/api/RestfulServer.php
+++ b/api/RestfulServer.php
@@ -137,6 +137,11 @@ class RestfulServer extends Controller {
$id = (isset($this->urlParams['ID'])) ? $this->urlParams['ID'] : null;
$relation = (isset($this->urlParams['Relation'])) ? $this->urlParams['Relation'] : null;
+ // Check input formats
+ if(!class_exists($className)) return $this->notFound();
+ if($id && !is_numeric($id)) return $this->notFound();
+ if($relation && !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $relation)) return $this->notFound();
+
// if api access is disabled, don't proceed
$apiAccess = singleton($className)->stat('api_access');
if(!$apiAccess) return $this->permissionFailure();
diff --git a/api/RestfulService.php b/api/RestfulService.php
index 7f007e9cc..b64d8584e 100644
--- a/api/RestfulService.php
+++ b/api/RestfulService.php
@@ -124,8 +124,15 @@ class RestfulService extends ViewableData {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$responseBody = curl_exec($ch);
$curlError = curl_error($ch);
-
- if($curlError) {
+
+ // Problem verifying the server SSL certificate; just ignore it as it's not mandatory
+ if(strpos($curlError,'14090086') !== false) {
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ $responseBody = curl_exec($ch);
+ $curlError = curl_error($ch);
+ }
+
+ if($responseBody === false) {
user_error("Curl Error:" . $curlError, E_USER_WARNING);
return;
}
@@ -338,4 +345,4 @@ class RestfulService_Response extends HTTPResponse {
}
}
-?>
\ No newline at end of file
+?>
diff --git a/api/XMLDataFormatter.php b/api/XMLDataFormatter.php
index 150ba31c8..d9f5f64c2 100644
--- a/api/XMLDataFormatter.php
+++ b/api/XMLDataFormatter.php
@@ -29,7 +29,7 @@ class XMLDataFormatter extends DataFormatter {
* @return String XML
*/
public function convertDataObject(DataObjectInterface $obj, $fields = null) {
- Controller::curr()->getResponse()->addHeader("Content-type", "text/xml");
+ Controller::curr()->getResponse()->addHeader("Content-Type", "text/xml");
return "\n" . $this->convertDataObjectWithoutHeader($obj, $fields);
}
@@ -111,7 +111,7 @@ class XMLDataFormatter extends DataFormatter {
* @return String XML
*/
public function convertDataObjectSet(DataObjectSet $set, $fields = null) {
- Controller::curr()->getResponse()->addHeader("Content-type", "text/xml");
+ Controller::curr()->getResponse()->addHeader("Content-Type", "text/xml");
$className = $set->class;
$xml = "\n";
diff --git a/cli/CliController.php b/cli/CliController.php
index 12bc2f1cf..260b5b317 100755
--- a/cli/CliController.php
+++ b/cli/CliController.php
@@ -11,8 +11,10 @@
*/
abstract class CliController extends Controller {
function init() {
- $this->disableBasicAuth();
- parent::init();
+ $this->disableBasicAuth();
+ parent::init();
+ // Unless called from the command line, all CliControllers need ADMIN privileges
+ if(!Director::is_cli() && !Permission::check("ADMIN")) return Security::permissionFailure();
}
function index() {
@@ -29,5 +31,6 @@ abstract class CliController extends Controller {
* Overload this method to contain the task logic.
*/
function process() {}
-}
-?>
\ No newline at end of file
+}
+
+?>
diff --git a/core/ClassInfo.php b/core/ClassInfo.php
index 9e497cc99..747be4339 100755
--- a/core/ClassInfo.php
+++ b/core/ClassInfo.php
@@ -93,16 +93,36 @@ class ClassInfo {
/**
* Returns a list of classes that inherit from the given class.
+ * The resulting array includes the base class passed
+ * through the $class parameter as the first array value.
+ *
+ * Example usage:
+ *
+ * ClassInfo::subclassesFor('BaseClass');
+ * array(
+ * 0 => 'BaseClass',
+ * 'ChildClass' => 'ChildClass',
+ * 'GrandChildClass' => 'GrandChildClass'
+ * )
+ *
*
* @param mixed $class string of the classname or instance of the class
- * @return array
+ * @return array Names of all subclasses as an associative array.
*/
static function subclassesFor($class){
global $_ALL_CLASSES;
if (is_object($class)) $class = get_class($class);
+
+ // get all classes from the manifest
$subclasses = isset($_ALL_CLASSES['children'][$class]) ? $_ALL_CLASSES['children'][$class] : null;
- if(isset($subclasses)) array_unshift($subclasses, $class);
- else $subclasses[$class] = $class;
+
+ // add the base class to the array
+ if(isset($subclasses)) {
+ array_unshift($subclasses, $class);
+ } else {
+ $subclasses[$class] = $class;
+ }
+
return $subclasses;
}
diff --git a/core/Core.php b/core/Core.php
index 1308f8166..fbd913269 100755
--- a/core/Core.php
+++ b/core/Core.php
@@ -286,5 +286,4 @@ function _t($entity, $string = "", $priority = 40, $context = "") {
return i18n::_t($entity, $string, $priority, $context);
}
-
?>
\ No newline at end of file
diff --git a/core/HTTP.php b/core/HTTP.php
index d2672b168..6220d2790 100644
--- a/core/HTTP.php
+++ b/core/HTTP.php
@@ -102,12 +102,10 @@ class HTTP {
static function findByTagAndAttribute($content, $attribs) {
$regExps = array();
- $content = '';
foreach($attribs as $tag => $attrib) {
- if(!is_numeric($tag)) $tagPrefix = "$tag ";
- else $tagPrefix = "";
-
+ $tagPrefix = (is_numeric($tag)) ? '' : "$tag ";
+
$regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *\")([^\"]*)(\")/ie";
$regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *')([^']*)(')/ie";
$regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *)([^\"' ]*)( )/ie";
@@ -125,6 +123,7 @@ class HTTP {
static function getLinksIn($content) {
return self::findByTagAndAttribute($content, array("a" => "href"));
}
+
static function getImagesIn($content) {
return self::findByTagAndAttribute($content, array("img" => "src"));
}
@@ -362,5 +361,4 @@ class HTTP {
}
-
-?>
+?>
\ No newline at end of file
diff --git a/core/ManifestBuilder.php b/core/ManifestBuilder.php
index 16a92069f..f40da439c 100644
--- a/core/ManifestBuilder.php
+++ b/core/ManifestBuilder.php
@@ -549,5 +549,4 @@ class ManifestBuilder {
}
}
-
-?>
+?>
\ No newline at end of file
diff --git a/core/Object.php b/core/Object.php
index a08a6c294..80c5a2d00 100755
--- a/core/Object.php
+++ b/core/Object.php
@@ -515,10 +515,6 @@ class Object {
public static function remove_extension($className, $extensionName) {
Object::$extraStatics[$className]['extensions'] = array_diff(Object::$extraStatics[$className]['extensions'], array($extensionName));
}
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // CACHE METHODS (added by simon_w (simon -at- simon -dot- geek -dot- nz))
- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Loads a current cache from the filesystem, if it can.
@@ -606,8 +602,6 @@ class Object {
* @param string|int $id An id for the cache
* @return mixed The cached return of the method
*/
- // I know this is almost exactly the same as cacheToFile, but call_user_func_array() is slow.
- // Which is why there's two separate functions
public function cacheToFileWithArgs($callback, $args = array(), $expire = 3600, $id = false) {
if(!$this->class) {
$this->class = get_class($this);
@@ -632,4 +626,4 @@ class Object {
return $data;
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/Requirements.php b/core/Requirements.php
index 1f0361952..5aea2f2bc 100644
--- a/core/Requirements.php
+++ b/core/Requirements.php
@@ -54,16 +54,17 @@ class Requirements {
}
/**
- * Add the CSS styling to the header of the page
+ * Include custom CSS styling to the header of the page.
*
* See {@link Requirements_Backend::customCSS()}
+ *
+ * @param string $script CSS selectors as a string (without \n";
}
@@ -775,6 +780,7 @@ class Requirements_Backend {
*
*/
function process_combined_files() {
+
if(Director::isDev() && !SapphireTest::is_running_test()) {
return;
}
@@ -803,7 +809,7 @@ class Requirements_Backend {
$newJSRequirements[$file] = true;
}
}
-
+
foreach($this->css as $file => $params) {
if(isset($combinerCheck[$file])) {
$newCSSRequirements[$combinerCheck[$file]] = true;
@@ -812,7 +818,7 @@ class Requirements_Backend {
$newCSSRequirements[$file] = $params;
}
}
-
+
// Process the combined files
$base = Director::baseFolder() . '/';
foreach(array_diff_key($combinedFiles,$this->blocked) as $combinedFile => $dummy) {
@@ -857,20 +863,11 @@ class Requirements_Backend {
fclose($fh);
unset($fh);
}
-
+
// Unsuccessful write - just include the regular JS files, rather than the combined one
if(!$successfulWrite) {
user_error("Requirements_Backend::process_combined_files(): Couldn't create '$base$combinedFile'", E_USER_WARNING);
- $keyedFileList = array();
- foreach($fileList as $file) $keyedFileList[$file] = true;
- $combinedPos = array_search($combinedFile, array_keys($newJSRequirements));
- if($combinedPos) {
- $newJSRequirements = array_merge(
- array_slice($newJSRequirements, 0, $combinedPos),
- $keyedFileList,
- array_slice($newJSRequirements, $combinedPos+1)
- );
- }
+ return;
}
}
@@ -925,5 +922,4 @@ class Requirements_Backend {
}
-
?>
diff --git a/core/SSViewer.php b/core/SSViewer.php
index a1770704d..41ac4470f 100644
--- a/core/SSViewer.php
+++ b/core/SSViewer.php
@@ -48,16 +48,29 @@
* @subpackage view
*/
class SSViewer extends Object {
+
+ /**
+ * @var boolean $source_file_comments
+ */
protected static $source_file_comments = true;
/**
* Set whether HTML comments indicating the source .SS file used to render this page should be
* included in the output. This is enabled by default
+ *
+ * @param boolean $val
*/
- function set_source_file_comments($val) {
+ static function set_source_file_comments($val) {
self::$source_file_comments = $val;
}
+ /**
+ * @return boolean
+ */
+ static function get_source_file_comments() {
+ return self::$source_file_comments;
+ }
+
/**
* @var array $chosenTemplates Associative array for the different
* template containers: "main" and "Layout".
@@ -355,6 +368,7 @@ class SSViewer extends Object {
static function parseTemplateContent($content, $template="") {
// Add template filename comments on dev sites
+
if(Director::isDev() && self::$source_file_comments && $template) {
// If this template is a full HTML page, then put the comments just inside the HTML tag to prevent any IE glitches
if(stripos($content, "\n"
+ if(Director::isDev() && self::$source_file_comments) $replacementCode = 'return "\n"
. SSViewer::getTemplateContent($matches[1])
- . "\n";';
+ . "\n";';
else $replacementCode = 'return SSViewer::getTemplateContent($matches[1]);';
$content = preg_replace_callback('/<' . '% include +([A-Za-z0-9_]+) +%' . '>/', create_function(
@@ -578,4 +592,4 @@ function supressOutput() {
return "";
}
-?>
+?>
\ No newline at end of file
diff --git a/core/Session.php b/core/Session.php
index 557543f6b..f52975197 100644
--- a/core/Session.php
+++ b/core/Session.php
@@ -236,4 +236,4 @@ class Session {
return self::$timeout;
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/ViewableData.php b/core/ViewableData.php
index ef60e3444..7a07c6037 100644
--- a/core/ViewableData.php
+++ b/core/ViewableData.php
@@ -18,7 +18,7 @@ class ViewableData extends Object implements IteratorAggregate {
* @var int
*/
protected $iteratorPos;
-
+
/**
* Total number of items in the iterator.
* @var int
@@ -1221,4 +1221,4 @@ class ViewableData_Iterator implements Iterator {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/control/ContentController.php b/core/control/ContentController.php
index 6f9498863..50f2b6d84 100644
--- a/core/control/ContentController.php
+++ b/core/control/ContentController.php
@@ -224,7 +224,7 @@ JS
if($this->dataRecord){
$thisPage = $this->dataRecord->Link();
$cmsLink = 'admin/show/' . $this->dataRecord->ID;
- $cmsLink = "CMS ";
+ $cmsLink = "". _t('ContentController.CMS', 'CMS') ." ";
} else {
/**
* HGS: If this variable is missing a notice is raised. Subclasses of ContentController
@@ -241,30 +241,30 @@ JS
$dateObj = Object::create('Datetime', $date, null);
// $dateObj->setVal($date);
- $archiveLink = "Archived Site ";
- $liveLink = "Published Site ";
- $stageLink = "Draft Site ";
- $message = "Archived site from " . $dateObj->Nice() . "
";
+ $archiveLink = "". _t('ContentController.ARCHIVEDSITE', 'Archived Site') ." ";
+ $liveLink = "". _t('ContentController.PUBLISHEDSITE', 'Published Site') ." ";
+ $stageLink = "". _t('ContentController.DRAFTSITE', 'Draft Site') ." ";
+ $message = "". _t('ContentController.ARCHIVEDSITEFROM', 'Archived site from') ." " . $dateObj->Nice() . "
";
} else if(Versioned::current_stage() == 'Stage') {
- $stageLink = "Draft Site ";
- $liveLink = "Published Site ";
- $message = "DRAFT SITE
";
+ $stageLink = "". _t('ContentController.DRAFTSITE', 'Draft Site') ." ";
+ $liveLink = "". _t('ContentController.PUBLISHEDSITE', 'Published Site') ." ";
+ $message = "". _t('ContentController.DRAFTSITE', 'Draft Site') ."
";
} else {
- $liveLink = "Published Site ";
- $stageLink = "Draft Site ";
- $message = "PUBLISHED SITE
";
+ $liveLink = "". _t('ContentController.PUBLISHEDSITE', 'Published Site') ." ";
+ $stageLink = "". _t('ContentController.DRAFTSITE', 'Draft Site') ." ";
+ $message = "". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."
";
}
if($member) {
$firstname = Convert::raw2xml($member->FirstName);
$surname = Convert::raw2xml($member->Surame);
- $logInMessage = "Logged in as {$firstname} {$surname} - log out ";
+ $logInMessage = _t('ContentController.LOGGEDINAS', 'Logged in as') ." {$firstname} {$surname} - ". _t('ContentController.LOGOUT', 'Log out'). " ";
} else {
- $logInMessage = "Not logged in - log in ";
+ $logInMessage = _t('ContentController.NOTLOGGEDIN', 'Not logged in') ." - ". _t('ContentController.LOGIN', 'Login') ." ";
}
-
+ $viewPageIn = _t('ContentController.VIEWPAGEIN', 'View Page in:');
/**
* HGS: cmsLink is now only set if there is a dataRecord. You can't view the page in the
* CMS if there is no dataRecord
@@ -277,7 +277,7 @@ JS
-
View page in:
+
$viewPageIn
$cmsLink
$stageLink
@@ -295,7 +295,7 @@ HTML;
Requirements::css(SAPPHIRE_DIR . '/css/SilverStripeNavigator.css');
$dateObj = Object::create('Datetime', $date, null);
// $dateObj->setVal($date);
- return "
Archived site from " . $dateObj->Nice() . "
";
+ return "
". _t('ContentController.ARCHIVEDSITEFROM') ." " . $dateObj->Nice() . "
";
}
}
}
@@ -423,5 +423,4 @@ HTML
}
}
-
-?>
+?>
\ No newline at end of file
diff --git a/core/control/ContentNegotiator.php b/core/control/ContentNegotiator.php
index e3555f5c1..116bf59e8 100755
--- a/core/control/ContentNegotiator.php
+++ b/core/control/ContentNegotiator.php
@@ -112,7 +112,7 @@ class ContentNegotiator {
// Only serve "pure" XHTML if the XML header is present
if(substr($content,0,5) == '<' . '?xml' ) {
- $response->addHeader("Content-type", "application/xhtml+xml; charset=" . self::$encoding);
+ $response->addHeader("Content-Type", "application/xhtml+xml; charset=" . self::$encoding);
$response->addHeader("Vary" , "Accept");
$content = str_replace(' ',' ', $content);
@@ -134,7 +134,7 @@ class ContentNegotiator {
* Removes "xmlns" attributes and any Pragmas.
*/
function html(HTTPResponse $response) {
- $response->addHeader("Content-type", "text/html; charset=" . self::$encoding);
+ $response->addHeader("Content-Type", "text/html; charset=" . self::$encoding);
$response->addHeader("Vary", "Accept");
$content = $response->getBody();
@@ -174,10 +174,15 @@ class ContentNegotiator {
* By default, negotiation is only enabled for pages that have the xml header.
*/
static function enabled_for($response) {
+ $contentType = $response->getHeader("Content-Type");
+
+ // Disable content negotation for other content types
+ if($contentType && substr($contentType, 0,9) != 'text/html' && substr($contentType, 0,21) != 'application/xhtml+xml') return false;
+
if(self::$enabled) return true;
else return (substr($response->getBody(),0,5) == '<' . '?xml');
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/control/Controller.php b/core/control/Controller.php
index 96c3ae08b..b363e4a17 100644
--- a/core/control/Controller.php
+++ b/core/control/Controller.php
@@ -544,4 +544,4 @@ class Controller extends RequestHandler {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/control/HTTPRequest.php b/core/control/HTTPRequest.php
index 796704308..d120bf57f 100644
--- a/core/control/HTTPRequest.php
+++ b/core/control/HTTPRequest.php
@@ -217,7 +217,7 @@ class HTTPRequest extends Object implements ArrayAccess {
* @return string
*/
function getURL() {
- return $this->url;
+ return ($this->getExtension()) ? $this->url . '.' . $this->getExtension() : $this->url;
}
/**
diff --git a/core/control/ModelAsController.php b/core/control/ModelAsController.php
index 178626f7e..925b48dcb 100644
--- a/core/control/ModelAsController.php
+++ b/core/control/ModelAsController.php
@@ -102,4 +102,4 @@ class ModelAsController extends Controller implements NestedController {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/control/RootURLController.php b/core/control/RootURLController.php
index 82fc583fe..60d4bad15 100755
--- a/core/control/RootURLController.php
+++ b/core/control/RootURLController.php
@@ -22,7 +22,7 @@ class RootURLController extends Controller {
$controller = new ModelAsController();
$request = new HTTPRequest("GET", self::get_homepage_urlsegment().'/', $request->getVars(), $request->postVars());
- $request->match('$URLSegment//$Action');
+ $request->match('$URLSegment//$Action', true);
$result = $controller->handleRequest($request);
diff --git a/core/i18n.php b/core/i18n.php
index 5a48ddf39..07d2632a3 100755
--- a/core/i18n.php
+++ b/core/i18n.php
@@ -965,15 +965,26 @@ class i18n extends Object {
* Given a file name (a php class name, without the .php ext, or a template name, including the .ss extension)
* this helper function determines the module where this file is located
*
- * @param string $name php class name or template file name
+ * @param string $name php class name or template file name (including *.ss extension)
* @return string Module where the file is located
*/
public static function get_owner_module($name) {
- if (substr($name,-3) == '.ss') {
+ // if $name is a template file
+ if(substr($name,-3) == '.ss') {
global $_TEMPLATE_MANIFEST;
- $path = str_replace('\\','/',Director::makeRelative(current($_TEMPLATE_MANIFEST[substr($name,0,-3)])));
+ $templateManifest = $_TEMPLATE_MANIFEST[substr($name,0,-3)];
+ if(is_array($templateManifest) && isset($templateManifest['themes'])) {
+ $absolutePath = $templateManifest['themes'][SSViewer::current_theme()];
+ } else {
+ $absolutePath = $templateManifest;
+ }
+
+ $path = str_replace('\\','/',Director::makeRelative(current($absolutePath)));
+
ereg('/([^/]+)/',$path,$module);
- } else {
+ }
+ // $name is assumed to be a PHP class
+ else {
global $_CLASS_MANIFEST;
if(strpos($name,'_') !== false) $name = strtok($name,'_');
if(isset($_CLASS_MANIFEST[$name])) {
@@ -1076,6 +1087,7 @@ class i18n extends Object {
$module = self::get_owner_module($class);
if(!$module) user_error("i18n::include_by_class: Class {$class} not found", E_USER_WARNING);
+ $locale = self::get_locale();
if (file_exists($file = Director::getAbsFile("$module/lang/". self::get_locale() . '.php'))) {
include($file);
@@ -1088,6 +1100,12 @@ class i18n extends Object {
} else if(file_exists(Director::getAbsFile("$module/lang"))) {
user_error("i18n::include_by_class: Locale file $file should exist", E_USER_WARNING);
}
+
+ // If the language file wasn't included for this class, include an empty array to prevent
+ // this method from being called again
+ global $lang;
+ if(!isset($lang[$locale][$class])) $lang[$locale][$class] = array();
+
}
//-----------------------------------------------------------------------------------------------//
diff --git a/core/i18nEntityProvider.php b/core/i18nEntityProvider.php
index 645cdc380..7c7e4fec3 100644
--- a/core/i18nEntityProvider.php
+++ b/core/i18nEntityProvider.php
@@ -44,6 +44,23 @@ interface i18nEntityProvider {
*
* Example usage in {@link DataObject->provideI18nEntities()}.
*
+ * You can ask textcollector to add the provided entity to a different module
+ * than the class is contained in by adding a 4th argument to the array:
+ *
+ * class MyTestClass implements i18nEntityProvider {
+ * function provideI18nEntities() {
+ * $entities = array();
+ * $entities["MyOtherModuleClass.MYENTITY"] = array(
+ * $value,
+ * PR_MEDIUM,
+ * 'My context description',
+ * 'myothermodule'
+ * );
+ * }
+ * return $entities;
+ * }
+ *
+ *
* @return array All entites in an associative array, with
* entity name as the key, and a numerical array of pseudo-arguments
* for _t() as a value.
diff --git a/core/i18nTextCollector.php b/core/i18nTextCollector.php
index 126a3bab7..e0cddd508 100644
--- a/core/i18nTextCollector.php
+++ b/core/i18nTextCollector.php
@@ -110,6 +110,16 @@ class i18nTextCollector extends Object {
unset($entitiesByModule[$module][$fullName]);
}
}
+
+ // extract all entities for "foreign" modules (fourth argument)
+ foreach($entitiesByModule[$module] as $fullName => $spec) {
+ if(isset($spec[3]) && $spec[3] != $module) {
+ $othermodule = $spec[3];
+ if(!isset($entitiesByModule[$othermodule])) $entitiesByModule[$othermodule] = array();
+ unset($spec[3]);
+ $entitiesByModule[$othermodule][$fullName] = $spec;
+ }
+ }
}
// Write the generated master string tables
@@ -228,7 +238,7 @@ class i18nTextCollector extends Object {
if(class_exists($class) && in_array('i18nEntityProvider', class_implements($class))) {
$reflectionClass = new ReflectionClass($class);
if($reflectionClass->isAbstract()) continue;
-
+
$obj = singleton($class);
$entitiesArr = array_merge($entitiesArr,(array)$obj->provideI18nEntities());
}
diff --git a/core/model/DB.php b/core/model/DB.php
index f006fc038..19be4b36d 100755
--- a/core/model/DB.php
+++ b/core/model/DB.php
@@ -262,4 +262,4 @@ class DB {
return DB::$globalConn->quiet();
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/DataObject.php b/core/model/DataObject.php
index 97bdbe332..3ebf6c012 100644
--- a/core/model/DataObject.php
+++ b/core/model/DataObject.php
@@ -1581,7 +1581,7 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP
* Used for simple frontend forms without relation editing
* or {@link TabSet} behaviour. Uses {@link scaffoldFormFields()}
* by default. To customize, either overload this method in your
- * subclass, or decorate it by {@link DataObjectDecorator->updateFormFields()}.
+ * subclass, or decorate it by {@link DataObjectDecorator->updateFrontEndFields()}.
*
* @todo Decide on naming for "website|frontend|site|page" and stick with it in the API
*
@@ -1590,7 +1590,7 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP
*/
public function getFrontEndFields($params = null) {
$untabbedFields = $this->scaffoldFormFields($params);
- $this->extend('updateFormFields', $untabbedFields);
+ $this->extend('updateFrontEndFields', $untabbedFields);
return $untabbedFields;
}
@@ -1836,7 +1836,10 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP
* Uses the rules for whether the table should exist rather than actually looking in the database.
*/
public function has_own_table($dataClass) {
- if(!is_subclass_of($dataClass,'DataObject')) return false;
+ // The condition below has the same effect as !is_subclass_of($dataClass,'DataObject'),
+ // which causes PHP < 5.3 to segfault in rare circumstances, see PHP bug #46753
+ if($dataClass == 'DataObject' || !in_array('DataObject', ClassInfo::ancestry($dataClass))) return false;
+
if(!isset(self::$cache_has_own_table[$dataClass])) {
if(get_parent_class($dataClass) == 'DataObject') {
self::$cache_has_own_table[$dataClass] = true;
@@ -2736,7 +2739,7 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP
$fields = array();
// try to scaffold a couple of usual suspects
if ($this->hasField('Name')) $fields['Name'] = 'Name';
- if ($this->hasField('Title')) $fields['Title'] = 'Title';
+ if ($this->hasDataBaseField('Title')) $fields['Title'] = 'Title';
if ($this->hasField('Description')) $fields['Description'] = 'Description';
if ($this->hasField('FirstName')) $fields['FirstName'] = 'First Name';
}
@@ -2848,7 +2851,7 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP
/**
* Inserts standard column-values when a DataObject
* is instanciated. Does not insert default records {@see $default_records}.
- * This is a map from classname to default value.
+ * This is a map from fieldname to default value.
*
* - If you would like to change a default value in a sub-class, just specify it.
* - If you would like to disable the default value given by a parent class, set the default value to 0,'',or false in your
@@ -3001,4 +3004,4 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/DataObjectDecorator.php b/core/model/DataObjectDecorator.php
index de8519371..d69560001 100755
--- a/core/model/DataObjectDecorator.php
+++ b/core/model/DataObjectDecorator.php
@@ -57,7 +57,6 @@ abstract class DataObjectDecorator extends Extension {
return $this->loadExtraStatics();
}
-
/**
* Edit the given query object to support queries for this extension
*
@@ -66,7 +65,6 @@ abstract class DataObjectDecorator extends Extension {
function augmentSQL(SQLQuery &$query) {
}
-
/**
* Update the database schema as required by this extension.
*/
@@ -139,7 +137,8 @@ abstract class DataObjectDecorator extends Extension {
/**
* This function is used to provide modifications to the form in the CMS
- * by the decorator. By default, no changes are made.
+ * by the decorator. By default, no changes are made. {@link DataObject->getCMSFields()}.
+ *
* Please consider using {@link updateFormFields()} to globally add
* formfields to the record. The method {@link updateCMSFields()}
* should just be used to add or modify tabs, or fields which
@@ -153,16 +152,22 @@ abstract class DataObjectDecorator extends Extension {
}
/**
- * This function is used to provide modifications to the form in the CMS
- * by the decorator.
+ * This function is used to provide modifications to the form used
+ * for front end forms. {@link DataObject->getFrontEndFields()}
*
* Caution: Use {@link FieldSet->push()} to add fields.
*
* @param FieldSet $fields FieldSet without TabSet nesting
*/
- function updateFormFields(FieldSet &$fields) {
+ function updateFrontEndFields(FieldSet &$fields) {
}
+ /**
+ * This is used to provide modifications to the form actions
+ * used in the CMS. {@link DataObject->getCMSActions()}.
+ *
+ * @param FieldSet $actions FieldSet
+ */
function updateCMSActions(FieldSet &$actions) {
}
@@ -176,6 +181,12 @@ abstract class DataObjectDecorator extends Extension {
$extra_fields = $this->extraStatics();
if(isset($extra_fields['summary_fields'])){
$summary_fields = $extra_fields['summary_fields'];
+
+ // if summary_fields were passed in numeric array,
+ // convert to an associative array
+ if($summary_fields && array_key_exists(0, $summary_fields)) {
+ $summary_fields = array_combine(array_values($summary_fields), array_values($summary_fields));
+ }
if($summary_fields) $fields = array_merge($fields, $summary_fields);
}
}
@@ -201,5 +212,4 @@ abstract class DataObjectDecorator extends Extension {
}
}
-
-?>
+?>
\ No newline at end of file
diff --git a/core/model/DataObjectSet.php b/core/model/DataObjectSet.php
index 3385fc91d..bb62d50e1 100644
--- a/core/model/DataObjectSet.php
+++ b/core/model/DataObjectSet.php
@@ -264,6 +264,85 @@ class DataObjectSet extends ViewableData implements IteratorAggregate {
return $ret;
}
+ /*
+ * Display a summarized pagination which limits the number of pages shown
+ * "around" the currently active page for visual balance.
+ * In case more paginated pages have to be displayed, only
+ *
+ * Example: 25 pages total, currently on page 6, context of 4 pages
+ * [prev] [1] ... [4] [5] [[6]] [7] [8] ... [25] [next]
+ *
+ * Example template usage:
+ *
+ * <% if MyPages.MoreThanOnePage %>
+ * <% if MyPages.NotFirstPage %>
+ * Prev
+ * <% end_if %>
+ * <% control MyPages.PaginationSummary(4) %>
+ * <% if CurrentBool %>
+ * $PageNum
+ * <% else %>
+ * <% if Link %>
+ * $PageNum
+ * <% else %>
+ * ...
+ * <% end_if %>
+ * <% end_if %>
+ * <% end_control %>
+ * <% if MyPages.NotLastPage %>
+ * Next
+ * <% end_if %>
+ * <% end_if %>
+ *
+ *
+ * @param integer $context Number of pages to display "around" the current page. Number should be even,
+ * because its halved to either side of the current page.
+ * @return DataObjectSet
+ */
+ public function PaginationSummary($context = 4) {
+ $ret = new DataObjectSet();
+
+ // convert number of pages to even number for offset calculation
+ if($context % 2) $context--;
+
+ // find out the offset
+ $current = $this->CurrentPage();
+ $totalPages = $this->TotalPages();
+
+ // if the first or last page is shown, use all content on one side (either left or right of current page)
+ // otherwise half the number for usage "around" the current page
+ $offset = ($current == 1 || $current == $totalPages) ? $context : floor($context/2);
+
+ $leftOffset = $current - ($offset);
+ if($leftOffset < 1) $leftOffset = 1;
+ if($leftOffset + $context > $totalPages) $leftOffset = $totalPages - $context;
+
+ for($i=0; $i < $totalPages; $i++) {
+ $link = HTTP::setGetVar($this->paginationGetVar, $i*$this->pageLength);
+ $num = $i+1;
+ $currentBool = ($current == $i+1) ? true:false;
+ if(
+ ($num == $leftOffset-1 && $num != 1 && $num != $totalPages)
+ || ($num == $leftOffset+$context+1 && $num != 1 && $num != $totalPages)
+ ) {
+ $ret->push(new ArrayData(array(
+ "PageNum" => null,
+ "Link" => null,
+ "CurrentBool" => $currentBool,
+ )
+ ));
+ } else if($num == 1 || $num == $totalPages || in_array($num, range($current-$offset,$current+$offset))) {
+ $ret->push(new ArrayData(array(
+ "PageNum" => $num,
+ "Link" => $link,
+ "CurrentBool" => $currentBool,
+ )
+ ));
+ }
+ }
+ return $ret;
+ }
+
/**
* Returns true if the current page is not the first page.
* @return boolean
@@ -694,7 +773,7 @@ class DataObjectSet extends ViewableData implements IteratorAggregate {
$myViewer = SSViewer::fromString($currentTemplate);
if(isset($nestingLevels[$level+1]['dataclass'])){
- $childrenMethod = $nestingLevels[$level+1]['dataclass'];if($level==1){print_r($childrenMethod);die;}
+ $childrenMethod = $nestingLevels[$level+1]['dataclass'];
}
// sql-parts
@@ -1044,4 +1123,4 @@ class DataObjectSet_Iterator implements Iterator {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/Database.php b/core/model/Database.php
index bfcce0eba..a4ee06694 100755
--- a/core/model/Database.php
+++ b/core/model/Database.php
@@ -235,7 +235,9 @@ abstract class Database extends Object {
} else {
$this->checkAndRepairTable($table);
}
-
+
+ $this->requireField($table, "ID", "int(11) not null auto_increment");
+
// Create custom fields
if($fieldSchema) {
foreach($fieldSchema as $fieldName => $fieldSpec) {
@@ -591,10 +593,11 @@ abstract class Query extends Object implements Iterator {
* @return array
*/
public function column() {
+ $column = array();
foreach($this as $record) {
$column[] = reset($record);
}
- return isset($column) ? $column : null;
+ return $column;
}
/**
@@ -603,6 +606,7 @@ abstract class Query extends Object implements Iterator {
* @return array
*/
public function keyedColumn() {
+ $column = array();
foreach($this as $record) {
$val = reset($record);
$column[$val] = $val;
@@ -615,6 +619,7 @@ abstract class Query extends Object implements Iterator {
* @return array
*/
public function map() {
+ $column = array();
foreach($this as $record) {
$key = reset($record);
$val = next($record);
diff --git a/core/model/ErrorPage.php b/core/model/ErrorPage.php
index 11c30e65e..9db4f9128 100755
--- a/core/model/ErrorPage.php
+++ b/core/model/ErrorPage.php
@@ -103,6 +103,7 @@ class ErrorPage extends Page {
$errorContent = $response->getBody();
+ // Check we have an assets base directory, creating if it we don't
if(!file_exists(ASSETS_PATH)) {
mkdir(ASSETS_PATH, 02775);
}
@@ -113,6 +114,17 @@ class ErrorPage extends Page {
if($fh = fopen($filePath, "w")) {
fwrite($fh, $errorContent);
fclose($fh);
+ } else {
+ $fileErrorText = sprintf(
+ _t(
+ "ErrorPage.ERRORFILEPROBLEM",
+ "Error opening file \"%s\" for writing. Please check file permissions."
+ ),
+ $errorFile
+ );
+ FormResponse::status_message($fileErrorText, 'bad');
+ FormResponse::respond();
+ return;
}
// Restore the version we're currently connected to.
diff --git a/core/model/Hierarchy.php b/core/model/Hierarchy.php
index 74b063cc1..16456073c 100644
--- a/core/model/Hierarchy.php
+++ b/core/model/Hierarchy.php
@@ -159,7 +159,7 @@ class Hierarchy extends DataObjectDecorator {
protected function markingFinished() {
// Mark childless nodes as expanded.
foreach($this->markedNodes as $id => $node) {
- if(!$node->numChildren()) {
+ if(!$node->isExpanded() && !$node->numChildren()) {
$node->markExpanded();
}
}
@@ -351,7 +351,18 @@ class Hierarchy extends DataObjectDecorator {
* @return DataObjectSet
*/
public function Children() {
- return $this->owner->stageChildren(false);
+ if(!(isset($this->children) && $this->children)) {
+ $result = $this->owner->stageChildren(false);
+ if(isset($result)) {
+ $this->children = new DataObjectSet();
+ foreach($result as $child) {
+ if($child->canView()) {
+ $this->children->push($child);
+ }
+ }
+ }
+ }
+ return $this->children;
}
/**
diff --git a/core/model/Image.php b/core/model/Image.php
index c92e0e6ab..91310ecb7 100755
--- a/core/model/Image.php
+++ b/core/model/Image.php
@@ -780,4 +780,4 @@ class Image_Uploader extends Controller {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/MySQLDatabase.php b/core/model/MySQLDatabase.php
index dec6f3f8a..756000eb4 100644
--- a/core/model/MySQLDatabase.php
+++ b/core/model/MySQLDatabase.php
@@ -174,11 +174,12 @@ class MySQLDatabase extends Database {
public function createTable($tableName, $fields = null, $indexes = null) {
$fieldSchemas = $indexSchemas = "";
+
+ if(!isset($fields['ID'])) $fields['ID'] = "int(11) not null auto_increment";
if($fields) foreach($fields as $k => $v) $fieldSchemas .= "\"$k\" $v,\n";
if($indexes) foreach($indexes as $k => $v) $fieldSchemas .= $this->getIndexSqlDefinition($k, $v) . ",\n";
$this->query("CREATE TABLE \"$tableName\" (
- ID int(11) not null auto_increment,
$fieldSchemas
$indexSchemas
primary key (ID)
@@ -468,7 +469,7 @@ class MySQLDatabase extends Database {
//$parts=Array('datatype'=>'decimal', 'precision'=>"$this->wholeSize,$this->decimalSize");
//DB::requireField($this->tableName, $this->name, "decimal($this->wholeSize,$this->decimalSize)");
- return 'decimal(' . (int)$values['precision'] . ')';
+ return 'decimal(' . (int)$values['precision'] . ') not null';
}
/**
diff --git a/core/model/PDODatabase.php b/core/model/PDODatabase.php
index 1a9155586..e70769932 100644
--- a/core/model/PDODatabase.php
+++ b/core/model/PDODatabase.php
@@ -727,5 +727,4 @@ class PDOQuery extends Query {
}
}
-
-?>
+?>
\ No newline at end of file
diff --git a/core/model/SQLQuery.php b/core/model/SQLQuery.php
index e50eeceda..ff3f55754 100755
--- a/core/model/SQLQuery.php
+++ b/core/model/SQLQuery.php
@@ -452,4 +452,4 @@ class SQLQuery extends Object {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/SiteTree.php b/core/model/SiteTree.php
index efdb81ea3..feb09758f 100644
--- a/core/model/SiteTree.php
+++ b/core/model/SiteTree.php
@@ -191,6 +191,42 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
*/
private static $runCMSFieldsExtensions = true;
+ /**
+ * Return a subclass map of SiteTree
+ * that shouldn't be hidden through
+ * {@link SiteTree::$hide_ancestor}
+ *
+ * @return array
+ */
+ public static function page_type_classes() {
+ $classes = ClassInfo::getValidSubClasses();
+ array_shift($classes);
+ $kill_ancestors = array();
+
+ // figure out if there are any classes we don't want to appear
+ foreach($classes as $class) {
+ $instance = singleton($class);
+
+ // do any of the progeny want to hide an ancestor?
+ if($ancestor_to_hide = $instance->stat('hide_ancestor')) {
+ // note for killing later
+ $kill_ancestors[] = $ancestor_to_hide;
+ }
+ }
+
+ // If any of the descendents don't want any of the elders to show up, cruelly render the elders surplus to requirements.
+ if($kill_ancestors) {
+ $kill_ancestors = array_unique($kill_ancestors);
+ foreach($kill_ancestors as $mark) {
+ // unset from $classes
+ $idx = array_search($mark, $classes);
+ unset($classes[$idx]);
+ }
+ }
+
+ return $classes;
+ }
+
/**
* Get the URL for this page.
*
@@ -525,7 +561,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @todo Check we get a endless recursion if we use parent::can()
*/
function can($perm, $member = null) {
- if(!$member && $member !== FALSE) $member = Member::currentUser();
+ if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
if($member && Permission::checkMember($member, "ADMIN")) return true;
@@ -562,7 +598,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return boolean True if the current user can add children.
*/
public function canAddChildren($member = null) {
- if(!$member && $member !== FALSE) $member = Member::currentUser();
+ if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
if($member && Permission::checkMember($member, "ADMIN")) return true;
// DEPRECATED 2.3: use canAddChildren() instead
@@ -593,7 +629,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return boolean True if the current user can view this page.
*/
public function canView($member = null) {
- if(!$member && $member !== FALSE) $member = Member::currentUser();
+ if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
// admin override
if($member && Permission::checkMember($member, "ADMIN")) return true;
@@ -648,7 +684,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return boolean True if the current user can delete this page.
*/
public function canDelete($member = null) {
- if(!$member && $member !== FALSE) $member = Member::currentUser();
+ if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
if($member && Permission::checkMember($member, "ADMIN")) return true;
@@ -690,7 +726,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return boolean True if the current user can create pages on this class.
*/
public function canCreate($member = null) {
- if(!$member && $member !== FALSE) $member = Member::currentUser();
+ if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
if($member && Permission::checkMember($member, "ADMIN")) return true;
@@ -726,7 +762,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return boolean True if the current user can edit this page.
*/
public function canEdit($member = null) {
- if(!$member && $member !== FALSE) $member = Member::currentUser();
+ if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
if($member && Permission::checkMember($member, "ADMIN")) return true;
@@ -774,7 +810,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return boolean True if the current user can publish this page.
*/
public function canPublish($member = null) {
- if(!$member && $member !== FALSE) $member = Member::currentUser();
+ if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser();
if($member && Permission::checkMember($member, "ADMIN")) return true;
@@ -816,7 +852,6 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/**
* Return the title, description, keywords and language metatags.
*
- * @todo Make generator tag dynamically determine version number (currently defaults to "2.0")
* @todo Move
tag in separate getter for easier customization and more obvious usage
*
* @param boolean|string $includeTitle Show default -tag, set to false for custom templating
@@ -831,7 +866,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
? $this->MetaTitle
: $this->Title) . " \n";
}
- $tags .= " \n";
+ $version = new SapphireInfo();
+
+ $tags .= " Version() ." - http://www.silverstripe.com\" />\n";
$charset = ContentNegotiator::get_encoding();
$tags .= " \n";
@@ -1076,26 +1113,6 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
Requirements::javascript(CMS_DIR . "/javascript/SitetreeAccess.js");
Requirements::javascript(SAPPHIRE_DIR . '/javascript/UpdateURL.js');
- // Backlink report
- if($this->hasMethod('BackLinkTracking')) {
- $links = $this->BackLinkTracking();
-
- if($links->exists()) {
- foreach($links as $link) {
- $backlinks[] = "ID\">" .
- $link->Breadcrumbs(null,true) . " ";
- }
- $backlinks = "
- " . _t('SiteTree.PAGESLINKING', 'The following pages link to this page:') .
- "
" . implode("",$backlinks) . " ";
- }
- }
-
- if(!isset($backlinks)) {
- $backlinks = "" . _t('SiteTree.NOBACKLINKS', 'This page hasn\'t been linked to from any pages.') . "
";
- }
-
-
// Status / message
// Create a status message for multiple parents
if($this->ID && is_numeric($this->ID)) {
@@ -1139,18 +1156,37 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
$message .= "NOTE: " . implode(" ", $statusMessage);
}
+ $backLinksNote = '';
+ $backLinksTable = new LiteralField('BackLinksNote', '' . _t('NOBACKLINKEDPAGES', 'There are no pages linked to this page.') . '
');
+
+ // Create a table for showing pages linked to this one
+ if($this->BackLinkTracking() && $this->BackLinkTracking()->Count() > 0) {
+ $backLinksNote = new LiteralField('BackLinksNote', '' . _t('SiteTree.PAGESLINKING', 'The following pages link to this page:') . '
');
+ $backLinksTable = new TableListField(
+ 'BackLinkTracking',
+ 'SiteTree',
+ array(
+ 'Title' => 'Title'
+ ),
+ 'ChildID = ' . $this->ID,
+ '',
+ 'LEFT JOIN SiteTree_LinkTracking ON SiteTree.ID = SiteTree_LinkTracking.SiteTreeID'
+ );
+ $backLinksTable->setFieldFormatting(array(
+ 'Title' => '$Title '
+ ));
+ $backLinksTable->setPermissions(array(
+ 'show',
+ 'export'
+ ));
+ }
+
// Lay out the fields
$fields = new FieldSet(
new TabSet("Root",
$tabContent = new TabSet('Content',
$tabMain = new Tab('Main',
new TextField("Title", $this->fieldLabel('Title')),
- /*new UniqueTextField("Title",
- "Title",
- "SiteTree",
- "Another page is using that name. Page names should be unique.",
- "Page Name"
- ),*/
new TextField("MenuTitle", $this->fieldLabel('MenuTitle')),
new HtmlEditorField("Content", _t('SiteTree.HTMLEDITORTITLE', "Content", PR_MEDIUM, 'HTML editor title'))
),
@@ -1206,8 +1242,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
new TextareaField("ToDo", "")
),
$tabReports = new TabSet('Reports',
- $tabBacklinks =new Tab('Backlinks',
- new LiteralField("Backlinks", $backlinks)
+ $tabBacklinks = new Tab('Backlinks',
+ $backLinksNote,
+ $backLinksTable
)
),
$tabAccess = new Tab('Access',
@@ -1496,11 +1533,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return array
*/
protected function getClassDropdown() {
- $classes = ClassInfo::getValidSubClasses('SiteTree');
- array_shift($classes);
-
+ $classes = self::page_type_classes();
$currentClass = null;
-
+ $result = array();
+
$result = array();
foreach($classes as $class) {
$instance = singleton($class);
@@ -1812,4 +1848,4 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/Versioned.php b/core/model/Versioned.php
index fb5f467ee..8e05d98d9 100755
--- a/core/model/Versioned.php
+++ b/core/model/Versioned.php
@@ -617,6 +617,27 @@ class Versioned extends DataObjectDecorator {
return $version;
}
+ /**
+ * Pre-populate the cache for Versioned::get_versionnumber_by_stage() for a list of record IDs,
+ * for more efficient database querying. If $idList is null, then every page will be pre-cached.
+ */
+ static function prepopulate_versionnumber_cache($class, $stage, $idList = null) {
+ $filter = "";
+ if($idList) {
+ // Validate the ID list
+ foreach($idList as $id) if(!is_numeric($id)) user_error("Bad ID passed to Versioned::prepopulate_versionnumber_cache() in \$idList: " . $id, E_USER_ERROR);
+ $filter = "WHERE ID IN(" .implode(", ", $idList) . ")";
+ }
+
+ $baseClass = ClassInfo::baseDataClass($class);
+ $stageTable = ($stage == 'Stage') ? $baseClass : "{$baseClass}_{$stage}";
+
+ $versions = DB::query("SELECT ID, Version FROM `$stageTable` $filter")->map();
+ foreach($versions as $id => $version) {
+ self::$cache_versionnumber[$baseClass][$stage][$id] = $version;
+ }
+ }
+
/**
* Get a set of class instances by the given stage.
*
@@ -802,4 +823,4 @@ class Versioned_Version extends ViewableData {
}
}
-?>
\ No newline at end of file
+?>
diff --git a/core/model/VirtualPage.php b/core/model/VirtualPage.php
index 35eb033da..84960901e 100755
--- a/core/model/VirtualPage.php
+++ b/core/model/VirtualPage.php
@@ -170,4 +170,4 @@ class VirtualPage_Controller extends Page_Controller {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/fieldtypes/DBField.php b/core/model/fieldtypes/DBField.php
index 183ccaf7d..cb27fe49d 100644
--- a/core/model/fieldtypes/DBField.php
+++ b/core/model/fieldtypes/DBField.php
@@ -64,7 +64,8 @@ abstract class DBField extends ViewableData {
}
/**
- * Returns the name of this field
+ * Returns the name of this field.
+ * @return string
*/
function getName() {
return $this->name;
diff --git a/core/model/fieldtypes/Decimal.php b/core/model/fieldtypes/Decimal.php
index 6d0184461..42f08ceb9 100644
--- a/core/model/fieldtypes/Decimal.php
+++ b/core/model/fieldtypes/Decimal.php
@@ -42,6 +42,10 @@ class Decimal extends DBField {
public function scaffoldFormField($title = null, $params = null) {
return new NumericField($this->name, $title);
}
+
+ public function nullValue() {
+ return "0.00";
+ }
/**
* Return an encoding of the given value suitable for inclusion in a SQL statement.
diff --git a/core/model/fieldtypes/Int.php b/core/model/fieldtypes/Int.php
index 964de2896..25217af64 100644
--- a/core/model/fieldtypes/Int.php
+++ b/core/model/fieldtypes/Int.php
@@ -60,4 +60,4 @@ class Int extends DBField {
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/fieldtypes/SSDatetime.php b/core/model/fieldtypes/SSDatetime.php
index cd6a8c123..85e4711dc 100644
--- a/core/model/fieldtypes/SSDatetime.php
+++ b/core/model/fieldtypes/SSDatetime.php
@@ -6,6 +6,10 @@
*/
class SSDatetime extends Date {
function setValue($value) {
+ // Default to NZ date format - strtotime expects a US date
+ if(ereg('^([0-9]+)/([0-9]+)/([0-9]+)$', $value, $parts))
+ $value = "$parts[2]/$parts[1]/$parts[3]";
+
if($value) $this->value = date('Y-m-d H:i:s', strtotime($value));
else $value = null;
}
@@ -41,4 +45,4 @@ class SSDatetime extends Date {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/fieldtypes/Text.php b/core/model/fieldtypes/Text.php
index 5f06ca58c..e5ba404f5 100644
--- a/core/model/fieldtypes/Text.php
+++ b/core/model/fieldtypes/Text.php
@@ -321,4 +321,4 @@ class Text extends DBField {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/core/model/fieldtypes/Varchar.php b/core/model/fieldtypes/Varchar.php
index 81e32c93e..b9c46ab9d 100644
--- a/core/model/fieldtypes/Varchar.php
+++ b/core/model/fieldtypes/Varchar.php
@@ -50,14 +50,10 @@ class Varchar extends DBField {
return str_replace("\n", '\par ', $this->value);
}
- /*function forTemplate() {
- return $this->raw2HTML();
- }*/
-
function LimitCharacters($limit = 20, $add = "...") {
$value = trim($this->value);
return (strlen($value) > $limit) ? substr($value, 0, $limit) . $add : $value;
}
}
-?>
+?>
\ No newline at end of file
diff --git a/css/CalendarDateField.css b/css/CalendarDateField.css
index e59be77ee..7e0a075f6 100755
--- a/css/CalendarDateField.css
+++ b/css/CalendarDateField.css
@@ -9,6 +9,10 @@
width: 200px;
}
+#SiteTreeFilterDate {
+ width: 68px;
+}
+
.calendardate img {
position: relative;
top: 2px;
@@ -17,11 +21,16 @@
.calendarpopup {
position: absolute;
- left: 13.6em;
+ left: 9em;
+ _left: 1.3em;
top: -0.15em;
+ _top: 4em;
display: none;
z-index: 2;
}
+
+
+
.calendarpopup.focused {
display: block;
}
diff --git a/css/ComplexTableField_popup.css b/css/ComplexTableField_popup.css
index acf26b69d..e2e071f5b 100755
--- a/css/ComplexTableField_popup.css
+++ b/css/ComplexTableField_popup.css
@@ -1,15 +1,17 @@
-html,body {
- overflow:auto !important;
- background: #fff !important;
-}
-
.ComplexTableField_popup {
background: #fff;
}
+html {
+ overflow-y: auto !important;
+}
+body {
+ height: auto;
+}
+
#ComplexTableField_Popup_DetailForm input.loading {
background: #fff url(../../cms/images/network-save.gif) left center no-repeat;
- padding-left:16px;
+ padding-left: 16px;
}
.PageControls {
diff --git a/css/Form.css b/css/Form.css
index ec5f8e307..38053fd29 100644
--- a/css/Form.css
+++ b/css/Form.css
@@ -137,4 +137,24 @@ form .message {
color:#FF4040;
width:240px;
border-color: #FF4040;
- }
\ No newline at end of file
+ }
+
+ /** LOGIN FORM **/
+
+#Remember {
+ margin: 0.5em 0 0.5em 11em !important;
+}
+ p#Remember label {
+ display: inline-block;
+ margin: 0;
+ }
+ #Remember input {
+ float: left;
+ margin: 0 5px 0 0;
+ }
+#MemberLoginForm_LoginForm .Actions {
+ padding-left: 12em;
+}
+#ForgotPassword {
+ margin-top: 1em;
+}
\ No newline at end of file
diff --git a/css/MemberProfileForm.css b/css/MemberProfileForm.css
index 71054fcbb..d81f6dbb0 100644
--- a/css/MemberProfileForm.css
+++ b/css/MemberProfileForm.css
@@ -1,8 +1,3 @@
-/* HACK Doesn't work in an iframe-popup at the moment, so we disable it */
-#Avatar {
- display: none;
-}
-
#i18nStatus {
margin-left: 0;
}
\ No newline at end of file
diff --git a/css/SilverStripeNavigator.css b/css/SilverStripeNavigator.css
index d39246a34..d39cfc7e0 100755
--- a/css/SilverStripeNavigator.css
+++ b/css/SilverStripeNavigator.css
@@ -4,24 +4,25 @@
bottom: 0;
left: 0;
width: 100%;
- border-top: 3px solid #d4d0c8;
+ border-top: 2px solid #d4d0c8;
background-color:#81858d;
- height: 18px;
+ height: 22px;
overflow:hidden;
- background-image:url(../../cms/images/textures/bottom.png);
+ background: #4d4e5a url(../../cms/images/textures/footerBg.gif) repeat-x left top;
+}
+#SilverStripeNavigator * {
+ font-family: Arial,Helvetica,sans-serif;
+ font-size: 10px !important;
}
#SilverStripeNavigator .holder {
-
text-align: center;
- padding-top : 3px;
+ padding-top : 4px;
padding-left : 3px;
padding-right : 6px;
- font-size: 10px;
color: white;
border-top: 1px solid #555555;
-
}
#SilverStripeNavigator #logInStatus {
float: right;
@@ -32,72 +33,52 @@
}
#SilverStripeNavigator a {
- color: #333;
- background-color: transparent;
- text-decoration: none;
-}
-#SilverStripeNavigator a:hover {
- color: #333;
+ color: #fff;
background-color: transparent;
text-decoration: underline;
}
+#SilverStripeNavigator a:hover {
+ background-color: transparent;
+}
#SilverStripeNavigator .bottomTabs a {
- width: auto;
- display: block;
- float : left;
- height : 13px;
- padding-left : 12px;
- padding-right : 12px;
- position:relative;
- top : -3px;
- border : 1px solid #65686e;
- border-top : none;
- cursor:pointer;
- background-color: #cdc9c1;
- color : #333333;
- background-image: none;
+ margin-right: 8px;
+ text-decoration: underline;
}
#SilverStripeNavigator .bottomTabs div.blank {
display: block;
float : left;
height : 13px;
- padding-left : 12px;
- padding-right : 12px;
position:relative;
- top : -3px;
- border : 1px solid #65686e;
- border-top : none;
- cursor:pointer;
- background-color: #cdc9c1;
- color : #333333;
-
+ top : -2px;
+ cursor: pointer;
border : none;
background-color: transparent;
- padding-right: 2px;
- padding-left: 2px;
- padding-top : 2px;
- color:#FFFFFF;
+ padding: 2px 4px 2px 2px;
+ font-weight: bold;
}
#SilverStripeNavigator .bottomTabs a.current {
- background-color : #d4d0c8;
- padding-top : 1px;
- top : -5px;
- height : 15px;
font-weight:bold;
- font-size : 11px;
- border : 1px solid #555555;
+ text-decoration: none;
}
#SilverStripeNavigatorMessage {
+ font-family: 'Lucida Grande', Verdana, Arial, 'sans-serif';
position: absolute;
- right: 45%;
- top: 10px;
+ right: 20px;
+ top: 40px;
padding: 10px;
border-color: #c99;
color: #fff;
background-color: #c00;
+ border: 1px solid #000;
+}
+
+#SilverStripeNavigator #logInStatus {
+ background:transparent url(../../cms/images/logout.gif) no-repeat scroll right top !important;
+ padding-bottom:4px;
+ padding-right:20px;
}
\ No newline at end of file
diff --git a/css/TableListField.css b/css/TableListField.css
index 42a99c741..c6f42d80c 100644
--- a/css/TableListField.css
+++ b/css/TableListField.css
@@ -8,7 +8,7 @@ table.CMSList {
width : 100%;
}
-/* HACK Preventing IE6 from showing double borders */
+/* Preventing IE6 from showing double borders */
body>div table.TableField,
body>div table.TableListField,
body>div .TableListField table.data,
@@ -113,6 +113,7 @@ table.CMSList tbody td.checkbox {
table.TableField tbody tr.over td,
.TableListField table.data tbody tr.over td,
+.TableListField table.data tbody tr.over td input,
table.CMSList tbody td.over td{
background-color: #FFCC66;
}
diff --git a/dev/BulkLoader.php b/dev/BulkLoader.php
index 1cf380a10..261f433a6 100644
--- a/dev/BulkLoader.php
+++ b/dev/BulkLoader.php
@@ -93,7 +93,14 @@ abstract class BulkLoader extends ViewableData {
* Specifies how to determine duplicates based on one or more provided fields
* in the imported data, matching to properties on the used {@link DataObject} class.
* Alternatively the array values can contain a callback method (see example for
- * implementation details).
+ * implementation details). The callback method should be defined on the source class.
+ *
+ * NOTE: If you're trying to get a unique Member record by a particular field that
+ * isn't Email, you need to ensure that Member is correctly set to the unique field
+ * you want, as it will merge any duplicates during {@link Member::onBeforeWrite()}.
+ *
+ * {@see Member::set_unique_identifier_field()}.
+ *
* If multiple checks are specified, the first one "wins".
*
*
@@ -222,7 +229,7 @@ abstract class BulkLoader extends ViewableData {
* @return boolean
*/
protected function isNullValue($val, $fieldName = null) {
- return (empty($val));
+ return (empty($val) && $val !== '0');
}
}
diff --git a/dev/DevelopmentAdmin.php b/dev/DevelopmentAdmin.php
index 4dce4b7a3..a40eb3b98 100644
--- a/dev/DevelopmentAdmin.php
+++ b/dev/DevelopmentAdmin.php
@@ -130,4 +130,4 @@ class DevelopmentAdmin extends Controller {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/dev/InstallerTest.php b/dev/InstallerTest.php
index f35f972e1..b061235b3 100644
--- a/dev/InstallerTest.php
+++ b/dev/InstallerTest.php
@@ -11,4 +11,4 @@ class InstallerTest extends Controller {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/dev/ModelViewer.php b/dev/ModelViewer.php
index d85dcabd2..4f5b7f358 100644
--- a/dev/ModelViewer.php
+++ b/dev/ModelViewer.php
@@ -171,5 +171,4 @@ class ModelViewer_Relation extends ViewableData {
}
-
-?>
+?>
\ No newline at end of file
diff --git a/dev/SSCli.php b/dev/SSCli.php
index 6987e1cd8..008294619 100644
--- a/dev/SSCli.php
+++ b/dev/SSCli.php
@@ -76,4 +76,4 @@ class SSCli extends Object {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/dev/SapphireTest.php b/dev/SapphireTest.php
index dc63cc0a7..4a290a69d 100644
--- a/dev/SapphireTest.php
+++ b/dev/SapphireTest.php
@@ -236,4 +236,4 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/email/Email.php b/email/Email.php
index b287cc11f..257e63e09 100755
--- a/email/Email.php
+++ b/email/Email.php
@@ -262,6 +262,22 @@ class Email extends ViewableData {
$this->body;
}
+ /**
+ * Set template name (without *.ss extension).
+ *
+ * @param string $template
+ */
+ public function setTemplate($template) {
+ $this->ss_template = $template;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTemplate() {
+ return $this->ss_template;
+ }
+
protected function templateData() {
if($this->template_data) {
return $this->template_data->customise(array(
@@ -384,6 +400,8 @@ class Email extends ViewableData {
if(trim($headers['Bcc'])) $headers['Bcc'] .= ', ';
$headers['Bcc'] .= self::$bcc_all_emails_to;
}
+
+ Requirements::restore();
return self::mailer()->sendPlain($to, $this->from, $subject, $this->body, $this->attachments, $headers);
}
@@ -543,12 +561,19 @@ class Email extends ViewableData {
*
* @param string $email Email-address
* @param string $method Method for obfuscating/encoding the address
+ * - 'direction': Reverse the text and then use CSS to put the text direction back to normal
* - 'visible': Simple string substitution ('@' to '[at]', '.' to '[dot], '-' to [dash])
* - 'hex': Hexadecimal URL-Encoding - useful for mailto: links
* @return string
*/
public static function obfuscate($email, $method = 'visible') {
switch($method) {
+ case 'direction' :
+ Requirements::customCSS(
+ 'span.codedirection { unicode-bidi: bidi-override; direction: rtl; }',
+ 'codedirectionCSS'
+ );
+ return '' . strrev($email) . ' ';
case 'visible' :
$obfuscated = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] ');
return strtr($email, $obfuscated);
@@ -714,38 +739,21 @@ class Email_BounceRecord extends DataObject {
static $has_one = array(
'Member' => 'Member'
);
+
+ static $has_many = array();
+
+ static $many_many = array();
+
+ static $defaults = array();
+
+
+ /**
+ * a record of Email_BounceRecord can't be created manually. Instead, it should be
+ * created though system.
+ */
+ public function canCreate($member = null) {
+ return false;
+ }
}
-/**
- * This class is responsible for ensuring that members who are on it receive NO email
- * communication at all. any correspondance is caught before the email is sent.
- * @package sapphire
- * @subpackage email
- */
-class Email_BlackList extends DataObject{
- static $db = array(
- 'BlockedEmail' => 'Varchar',
- );
- static $has_one = array(
- 'Member' => 'Member'
- );
-
- /**
- * Helper function to see if the email being
- * sent has specifically been blocked.
- */
- static function isBlocked($email){
- $blockedEmails = DataObject::get("Email_BlackList")->toDropDownMap("ID","BlockedEmail");
- if($blockedEmails){
- if(in_array($email,$blockedEmails)){
- return true;
- }else{
- return false;
- }
- }else{
- return false;
- }
- }
-}
-
-?>
+?>
\ No newline at end of file
diff --git a/email/Mailer.php b/email/Mailer.php
index 2b635f3ce..2c553d5f8 100644
--- a/email/Mailer.php
+++ b/email/Mailer.php
@@ -17,7 +17,7 @@ class Mailer extends Object {
* Send a plain-text email
*/
function sendPlain($to, $from, $subject, $plainContent, $attachedFiles = false, $customheaders = false) {
- return plaintextEmail($to, $from, $subject, $htmlContent, $attachedFiles, $customheaders);
+ return plaintextEmail($to, $from, $subject, $plainContent, $attachedFiles, $customheaders);
}
/**
@@ -428,4 +428,3 @@ function loadMimeTypes() {
$global_mimetypes = $mimeData;
return $mimeData;
}
-
diff --git a/email/QueuedEmail.php b/email/QueuedEmail.php
index e8cdd6693..72702ebf3 100644
--- a/email/QueuedEmail.php
+++ b/email/QueuedEmail.php
@@ -17,6 +17,12 @@ class QueuedEmail extends DataObject {
'To' => 'Member'
);
+ static $has_many = array();
+
+ static $many_many = array();
+
+ static $defaults = array();
+
// overwrite this method to provide a check whether or not to send the email
function canSendEmail() {
return true;
@@ -27,4 +33,4 @@ class QueuedEmail extends DataObject {
$email->send();
}
}
-?>
+?>
\ No newline at end of file
diff --git a/filesystem/File.php b/filesystem/File.php
index 19583e0fb..bf7c0e858 100755
--- a/filesystem/File.php
+++ b/filesystem/File.php
@@ -33,14 +33,21 @@ class File extends DataObject {
"Owner" => "Member"
);
- static $extensions = array(
- "Hierarchy",
- );
+ static $has_many = array();
+
+ static $many_many = array();
static $belongs_many_many = array(
"BackLinkTracking" => "SiteTree",
);
+ static $defaults = array();
+
+ static $extensions = array(
+ "Hierarchy",
+ );
+
+
/**
* Cached result of a "SHOW FIELDS" call
* in instance_get() for performance reasons.
diff --git a/filesystem/Filesystem.php b/filesystem/Filesystem.php
index 786ac1015..6e5ed4506 100755
--- a/filesystem/Filesystem.php
+++ b/filesystem/Filesystem.php
@@ -124,4 +124,4 @@ class Filesystem extends Object {
}
-?>
+?>
\ No newline at end of file
diff --git a/filesystem/Folder.php b/filesystem/Folder.php
index 3e82f1423..4aa6cad58 100755
--- a/filesystem/Folder.php
+++ b/filesystem/Folder.php
@@ -441,11 +441,11 @@ class Folder extends File {
*/
function getUploadIframe() {
return <<
+
HTML;
}
}
-?>
+?>
\ No newline at end of file
diff --git a/filesystem/GD.php b/filesystem/GD.php
index b6b602311..43c0afa97 100755
--- a/filesystem/GD.php
+++ b/filesystem/GD.php
@@ -408,4 +408,4 @@ class GD extends Object {
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/CheckboxSetField.php b/forms/CheckboxSetField.php
index cd5f9c944..a1531e362 100755
--- a/forms/CheckboxSetField.php
+++ b/forms/CheckboxSetField.php
@@ -4,6 +4,15 @@
*
* ASSUMPTION -> IF you pass your source as an array, you pass values as an array too.
* Likewise objects are handled the same.
+ *
+ * @todo Document the different source data that can be used
+ * with this form field - e.g ComponentSet, DataObjectSet,
+ * array. Is it also appropriate to accept so many different
+ * types of data when just using an array would be appropriate?
+ *
+ * @todo Make use of FormField->createTag() to generate the
+ * HTML tag(s) for this field.
+ *
* @package forms
* @subpackage fields-basic
*/
@@ -11,11 +20,12 @@ class CheckboxSetField extends OptionsetField {
protected $disabled = false;
- /**
- * Object handles arrays and dosets being passed by reference.
- *
- * @todo Should use CheckboxField FieldHolder rather than constructing own markup.
- */
+ /**
+ * @todo Explain different source data that can be used with this field,
+ * e.g. SQLMap, DataObjectSet or an array.
+ *
+ * @todo Should use CheckboxField FieldHolder rather than constructing own markup.
+ */
function Field() {
Requirements::css(SAPPHIRE_DIR . '/css/CheckboxSetField.css');
@@ -86,10 +96,10 @@ class CheckboxSetField extends OptionsetField {
$checked = '';
if(isset($items)) {
- in_array($key,$items) ? $checked = " checked=\"checked\"" : $checked = "";
+ $checked = (in_array($key, $items)) ? ' checked="checked"' : '';
}
- $this->disabled ? $disabled = " disabled=\"disabled\"" : $disabled = "";
+ $disabled = ($this->disabled) ? $disabled = ' disabled="disabled"' : '';
$options .= "\n";
}
@@ -108,7 +118,7 @@ class CheckboxSetField extends OptionsetField {
if(!$value && $obj && $obj instanceof DataObject && $obj->hasMethod($this->name)) {
$funcName = $this->name;
$selected = $obj->$funcName();
- $value = $selected->toDropdownMap('ID','ID');
+ $value = $selected->toDropdownMap('ID', 'ID');
}
parent::setValue($value, $obj);
@@ -133,7 +143,7 @@ class CheckboxSetField extends OptionsetField {
$record->$fieldname()->setByIDList($idList);
} elseif($fieldname && $record) {
if($this->value) {
- $this->value = str_replace(",", "{comma}", $this->value);
+ $this->value = str_replace(',', '{comma}', $this->value);
$record->$fieldname = implode(",", $this->value);
} else {
$record->$fieldname = '';
@@ -142,79 +152,93 @@ class CheckboxSetField extends OptionsetField {
}
/**
- * Return the CheckboxSetField value, as an array of the selected item keys
+ * Return the CheckboxSetField value as an array
+ * selected item keys.
+ *
+ * @return string
*/
function dataValue() {
- if($this->value&&is_array($this->value)){
- // Filter items to those who aren't 0
+ if($this->value && is_array($this->value)) {
$filtered = array();
- foreach($this->value as $item) if($item) $filtered[] = str_replace(",", "{comma}", $item);
- return implode(",", $filtered);
- } else {
- return '';
+ foreach($this->value as $item) {
+ if($item) {
+ $filtered[] = str_replace(",", "{comma}", $item);
+ }
+ }
+
+ return implode(',', $filtered);
}
+
+ return '';
}
function performDisabledTransformation() {
$clone = clone $this;
$clone->setDisabled(true);
+
return $clone;
}
/**
- * Makes a pretty readonly field
- */
-
+ * Transforms the source data for this CheckboxSetField
+ * into a comma separated list of values.
+ *
+ * @return ReadonlyField
+ */
function performReadonlyTransformation() {
$values = '';
+ $data = array();
$items = $this->value;
- foreach($this->source as $source) {
- if(is_object($source)) {
- $sourceTitles[$source->ID] = $source->Title;
+ if($this->source) {
+ foreach($this->source as $source) {
+ if(is_object($source)) {
+ $sourceTitles[$source->ID] = $source->Title;
+ }
}
}
- if($items){
+ if($items) {
// Items is a DO Set
- if(is_a($items,'DataObjectSet')){
-
- foreach($items as $item){
+ if(is_a($items, 'DataObjectSet')) {
+ foreach($items as $item) {
$data[] = $item->Title;
}
- if($data) {
- $values = implode(", ",$data);
- }
-
+ if($data) $values = implode(', ', $data);
+
// Items is an array or single piece of string (including comma seperated string)
- }else{
+ } else {
if(!is_array($items)) {
- $items = split(" *, *", trim($items));
+ $items = split(' *, *', trim($items));
}
- foreach($items as $item){
+
+ foreach($items as $item) {
if(is_array($item)) {
$data[] = $item['Title'];
- } else if(is_array($this->source) && !empty($this->source[$item])) {
+ } elseif(is_array($this->source) && !empty($this->source[$item])) {
$data[] = $this->source[$item];
- } else if(is_a($this->source, "ComponentSet")){
- //added for editable checkboxset.
+ } elseif(is_a($this->source, 'ComponentSet')) {
$data[] = $sourceTitles[$item];
-
} else {
$data[] = $item;
}
}
- $values = implode(", ",$data);
+
+ $values = implode(', ', $data);
}
}
- $field = new ReadonlyField($this->name,$this->title ? $this->title : "",$values);
+ $title = ($this->title) ? $this->title : '';
+
+ $field = new ReadonlyField($this->name, $title, $values);
$field->setForm($this->form);
+
return $field;
}
function ExtraOptions() {
return FormField::ExtraOptions();
- }
+ }
+
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/ComplexTableField.php b/forms/ComplexTableField.php
index 104f30621..13c1dc951 100755
--- a/forms/ComplexTableField.php
+++ b/forms/ComplexTableField.php
@@ -472,7 +472,7 @@ JS;
if(!$childData->ID && $this->getParentClass()) {
// make sure the relation-link is existing, even if we just add the sourceClass and didn't save it
$parentIDName = $this->getParentIdName( $this->getParentClass(), $this->sourceClass() );
- $childData->$parentIDName = $childData->ID;
+ $childData->$parentIDName = $this->sourceID();
}
$detailFields = $this->getCustomFieldsFor($childData);
@@ -725,8 +725,10 @@ class ComplexTableField_ItemRequest extends RequestHandler {
* @see Form::ReferencedField
*/
function saveComplexTableField($data, $form, $request) {
- $form->saveInto($this->dataObj());
- $this->dataObj()->write();
+ $dataObject = $this->dataObj();
+
+ $form->saveInto($dataObject);
+ $dataObject->write();
$closeLink = sprintf(
'(%s) ',
@@ -734,8 +736,8 @@ class ComplexTableField_ItemRequest extends RequestHandler {
);
$message = sprintf(
_t('ComplexTableField.SUCCESSEDIT', 'Saved %s %s %s'),
- $this->dataObj()->singular_name(),
- '"' . $this->dataObj()->Title . '" ',
+ $dataObject->singular_name(),
+ '"' . $dataObject->Title . '" ',
$closeLink
);
$form->sessionMessage($message, 'good');
@@ -753,8 +755,9 @@ class ComplexTableField_ItemRequest extends RequestHandler {
if(!isset($_REQUEST['ctf']['start']) || !is_numeric($_REQUEST['ctf']['start']) || $_REQUEST['ctf']['start'] == 0) {
return null;
}
-
- $item = $this->unpagedSourceItems->First();
+
+ // We never use $item afterwards in the function, where we have it here? disable it!
+ //$item = $this->unpagedSourceItems->First();
$start = 0;
return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}");
}
@@ -763,8 +766,9 @@ class ComplexTableField_ItemRequest extends RequestHandler {
if(!isset($_REQUEST['ctf']['start']) || !is_numeric($_REQUEST['ctf']['start']) || $_REQUEST['ctf']['start'] == $this->totalCount-1) {
return null;
}
-
- $item = $this->unpagedSourceItems->Last();
+
+ // We never use $item afterwards in the function, where we have it here? disable it!
+ // $item = $this->unpagedSourceItems->Last();
$start = $this->totalCount - 1;
return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}");
}
@@ -774,7 +778,8 @@ class ComplexTableField_ItemRequest extends RequestHandler {
return null;
}
- $item = $this->unpagedSourceItems->getIterator()->getOffset($_REQUEST['ctf']['start'] + 1);
+ // We never use $item afterwards in the function, where we have it here? disable it!
+ //$item = $this->unpagedSourceItems->getIterator()->getOffset($_REQUEST['ctf']['start'] + 1);
$start = $_REQUEST['ctf']['start'] + 1;
return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}");
@@ -785,7 +790,8 @@ class ComplexTableField_ItemRequest extends RequestHandler {
return null;
}
- $item = $this->unpagedSourceItems->getIterator()->getOffset($_REQUEST['ctf']['start'] - 1);
+ // We never use $item afterwards in the function, where we have it here? disable it!
+ //$item = $this->unpagedSourceItems->getIterator()->getOffset($_REQUEST['ctf']['start'] - 1);
$start = $_REQUEST['ctf']['start'] - 1;
return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}");
diff --git a/forms/CompositeDateField.php b/forms/CompositeDateField.php
index 3b52407a9..294c8de7a 100755
--- a/forms/CompositeDateField.php
+++ b/forms/CompositeDateField.php
@@ -175,4 +175,4 @@ class CompositeDateField_Disabled extends DateField {
return "date_disabled readonly";
}
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/CountryDropdownField.php b/forms/CountryDropdownField.php
index 2b13786b8..74e0606b6 100644
--- a/forms/CountryDropdownField.php
+++ b/forms/CountryDropdownField.php
@@ -28,4 +28,4 @@ class CountryDropdownField extends DropdownField {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/DateField.php b/forms/DateField.php
index 524c79c48..92f26bf5b 100755
--- a/forms/DateField.php
+++ b/forms/DateField.php
@@ -112,15 +112,16 @@ class DateField_Disabled extends DateField {
$df->setValue($this->dataValue());
if(date('Y-m-d', time()) == $this->dataValue()) {
- $val = Convert::raw2xml($this->value . ' ('._t('DateField.TODAY','today').')');
+ $val = Convert::raw2xml($this->value . ' ('._t('DateField.TODAY','today').')');
} else {
$val = Convert::raw2xml($this->value . ', ' . $df->Ago());
}
} else {
- $val = '('._t('DateField.NOTSET', 'not set').') ';
+ $val = '('._t('DateField.NOTSET', 'not set').') ';
}
- return "id() . "\">$val ";
+ return "id() . "\">$val
+ value}\" name=\"$this->name\" />";
}
function Type() {
@@ -139,4 +140,4 @@ class DateField_Disabled extends DateField {
return true;
}
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/FieldGroup.php b/forms/FieldGroup.php
index 96dd4ef68..e40165346 100755
--- a/forms/FieldGroup.php
+++ b/forms/FieldGroup.php
@@ -83,7 +83,22 @@ class FieldGroup extends CompositeField {
}
function FieldHolder() {
- return FormField::FieldHolder();
+ $Title = $this->XML_val('Title');
+ $Message = $this->XML_val('Message');
+ $MessageType = $this->XML_val('MessageType');
+ $RightTitle = $this->XML_val('RightTitle');
+ $Type = $this->XML_val('Type');
+ $extraClass = $this->XML_val('extraClass');
+ $Name = $this->XML_val('Name');
+ $Field = $this->XML_val('Field');
+
+ $titleBlock = (!empty($Title)) ? "$Title " : "";
+ $messageBlock = (!empty($Message)) ? "$Message " : "";
+ $rightTitleBlock = (!empty($RightTitle)) ? "$RightTitle " : "";
+
+ return <<$titleBlock$Field
$rightTitleBlock$messageBlock
+HTML;
}
function Message() {
diff --git a/forms/FieldSet.php b/forms/FieldSet.php
index 218148b2e..6d5e13778 100755
--- a/forms/FieldSet.php
+++ b/forms/FieldSet.php
@@ -535,4 +535,4 @@ class FieldSet extends DataObjectSet {
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/FileField.php b/forms/FileField.php
index 3a824ec1a..b8027d0ad 100755
--- a/forms/FileField.php
+++ b/forms/FileField.php
@@ -201,7 +201,7 @@ class FileField extends FormField {
* @return string
*/
public function getFolderName() {
- return $folderName;
+ return $this->folderName;
}
public function validate($validator) {
@@ -223,4 +223,4 @@ class FileField extends FormField {
return true;
}
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/Form.php b/forms/Form.php
index 6448ffb0a..f8aafab77 100644
--- a/forms/Form.php
+++ b/forms/Form.php
@@ -886,6 +886,8 @@ class Form extends RequestHandler {
*/
function getData() {
$dataFields = $this->fields->dataFields();
+ $data = array();
+
if($dataFields){
foreach($dataFields as $field) {
if($field->Name()) {
diff --git a/forms/FormAction.php b/forms/FormAction.php
index c6c946888..d649c31db 100755
--- a/forms/FormAction.php
+++ b/forms/FormAction.php
@@ -69,6 +69,10 @@ class FormAction extends FormField {
'type' => 'submit',
'name' => $this->action
);
+ if($this->isReadonly()) {
+ $attributes['disabled'] = 'disabled';
+ $attributes['class'] = $attributes['class'] . ' disabled';
+ }
return $this->createTag('button', $attributes, $this->attrTitle());
} else {
@@ -79,7 +83,10 @@ class FormAction extends FormField {
'name' => $this->action,
'value' => ($this->dontEscape) ? $this->Title() : $this->attrTitle()
);
-
+ if($this->isReadonly()) {
+ $attributes['disabled'] = 'disabled';
+ $attributes['class'] = $attributes['class'] . ' disabled';
+ }
$attributes['title'] = ($this->description) ? $this->description : ($this->dontEscape) ? $this->Title() : $this->attrTitle();
return $this->createTag('input', $attributes);
diff --git a/forms/FormField.php b/forms/FormField.php
index 791bdb5ab..a103d22c6 100644
--- a/forms/FormField.php
+++ b/forms/FormField.php
@@ -481,7 +481,8 @@ HTML;
*
* @todo shouldn't this be an abstract method?
*/
- function jsValidation() {}
+ function jsValidation() {
+ }
/**
* Validation Functions for each field type by default
@@ -489,7 +490,9 @@ HTML;
*
* @todo shouldn't this be an abstract method?
*/
- function validate(){return true;}
+ function validate() {
+ return true;
+ }
/**
* Describe this field, provide help text for it.
diff --git a/forms/GSTNumberField.php b/forms/GSTNumberField.php
index 20447872d..46ec56087 100755
--- a/forms/GSTNumberField.php
+++ b/forms/GSTNumberField.php
@@ -52,4 +52,4 @@ JS;
}
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/HasManyComplexTableField.php b/forms/HasManyComplexTableField.php
index ab6ede7e0..008fe2bcb 100644
--- a/forms/HasManyComplexTableField.php
+++ b/forms/HasManyComplexTableField.php
@@ -46,52 +46,6 @@ class HasManyComplexTableField extends ComplexTableField {
if($this->controller instanceof DataObject) return $this->controller->class;
elseif($this->controller instanceof ContentController) return $this->controller->data()->class;
}
-
- function getQuery($limitClause = null) {
- if($this->customQuery) {
- $query = $this->customQuery;
- $query->select[] = "{$this->sourceClass}.ID AS ID";
- $query->select[] = "{$this->sourceClass}.ClassName AS ClassName";
- $query->select[] = "{$this->sourceClass}.ClassName AS \"RecordClassName\"";
- }
- else {
- $query = singleton($this->sourceClass)->extendedSQL($this->sourceFilter, $this->sourceSort, $limitClause, $this->sourceJoin);
-
- // Add more selected fields if they are from joined table.
-
- $SNG = singleton($this->sourceClass);
- foreach($this->FieldList() as $k => $title) {
- if(! $SNG->hasField($k) && ! $SNG->hasMethod('get' . $k))
- $query->select[] = $k;
- }
- }
- return clone $query;
- }
-
- function sourceItems() {
- if($this->sourceItems) return $this->sourceItems;
-
- $limitClause = '';
- if(isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) {
- $limitClause = $_REQUEST[ 'ctf' ][ $this->Name() ][ 'start' ] . ", $this->pageSize";
- } else {
- $limitClause = "0, $this->pageSize";
- }
-
- $dataQuery = $this->getQuery($limitClause);
- $records = $dataQuery->execute();
- $items = new DataObjectSet();
-
- $sourceClass = $this->sourceClass;
- $dataobject = new $sourceClass();
- $items = $dataobject->buildDataObjectSet($records, 'DataObjectSet');
-
- $this->unpagedSourceItems = $dataobject->buildDataObjectSet($records, 'DataObjectSet');
-
- $this->totalCount = ($this->unpagedSourceItems) ? $this->unpagedSourceItems->TotalItems() : null;
-
- return $items;
- }
function getControllerID() {
return $this->controller->ID;
@@ -123,15 +77,21 @@ class HasManyComplexTableField extends ComplexTableField {
return $this->addTitle ? $this->addTitle : parent::Title();
}
+ /**
+ * Get the IDs of the selected items, in a has_many or many_many relation
+ */
+ function selectedItemIDs() {
+ $fieldName = $this->name;
+ $selectedItems = $this->form->getRecord()->$fieldName();
+ $itemIDs = array();
+ foreach($selectedItems as $item) $itemIDs[] = $item->ID;
+ return $itemIDs;
+ }
+
function ExtraData() {
$items = array();
- if($this->unpagedSourceItems) {
- foreach($this->unpagedSourceItems as $item) {
- if($item->{$this->joinField} == $this->controller->ID)
- $items[] = $item->ID;
- }
- }
- $list = implode(',', $items);
+
+ $list = implode(',', $this->selectedItemIDs());
$inputId = $this->id() . '_' . $this->htmlListEndName;
return <<
@@ -166,4 +126,4 @@ class HasManyComplexTableField_Item extends ComplexTableField_Item {
}
}
-?>
\ No newline at end of file
+?>
diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php
index 5e950b710..daef011d2 100755
--- a/forms/HtmlEditorField.php
+++ b/forms/HtmlEditorField.php
@@ -15,7 +15,7 @@ class HtmlEditorField extends TextareaField {
/**
* Construct a new HtmlEditor field
*/
- function __construct($name, $title = "", $rows = 20, $cols = 20, $value = "", $form = null) {
+ function __construct($name, $title = null, $rows = 20, $cols = 20, $value = "", $form = null) {
parent::__construct($name, $title, $rows, $cols, $value, $form);
$this->extraClass = 'typography';
}
@@ -100,10 +100,10 @@ class HtmlEditorField extends TextareaField {
$content = preg_replace('/mce_real_src="[^"]+"/i', "", $content);
- $content = eregi_replace('( ]* )width=([0-9]+)( [^>]*>|>)','\\1width="\\2"\\3',$content);
- $content = eregi_replace('( ]* )height=([0-9]+)( [^>]*>|>)','\\1height="\\2"\\3',$content);
- $content = eregi_replace('src="([^\?]*)\?r=[0-9]+"','src="\\1"',$content);
- $content = eregi_replace('mce_src="([^\?]*)\?r=[0-9]+"','mce_src="\\1"',$content);
+ $content = eregi_replace('( ]* )width=([0-9]+)( [^>]*>|>)','\\1width="\\2"\\3', $content);
+ $content = eregi_replace('( ]* )height=([0-9]+)( [^>]*>|>)','\\1height="\\2"\\3', $content);
+ $content = eregi_replace('src="([^\?]*)\?r=[0-9]+"','src="\\1"', $content);
+ $content = eregi_replace('mce_src="([^\?]*)\?r=[0-9]+"','mce_src="\\1"', $content);
$content = preg_replace_callback('/( ]* )(width="|height="|src=")([^"]+)("[^>]* )(width="|height="|src=")([^"]+)("[^>]* )(width="|height="|src=")([^"]+)("[^>]*>)/i', "HtmlEditorField_dataValue_processImage", $content);
@@ -111,11 +111,12 @@ class HtmlEditorField extends TextareaField {
if(!ereg("^[ \t\r\n]*<", $content)) $content = "
$content
";
$links = HTTP::getLinksIn($content);
+ $linkedPages = array();
if($links) foreach($links as $link) {
$link = Director::makeRelative($link);
- if(preg_match( '/^([A-Za-z0-9_-]+)\/?(#.*)?$/', $link, $parts ) ) {
+ if(preg_match('/^([A-Za-z0-9_-]+)\/?(#.*)?$/', $link, $parts)) {
$candidatePage = DataObject::get_one("SiteTree", "\"URLSegment\" = '" . urldecode( $parts[1] ). "'", false);
if($candidatePage) {
$linkedPages[] = $candidatePage->ID;
@@ -135,10 +136,8 @@ class HtmlEditorField extends TextareaField {
}
$images = HTTP::getImagesIn($content);
-
- if($images){
+ if($images) {
foreach($images as $image) {
-
$image = Director::makeRelative($image);
if(substr($image,0,7) == 'assets/') {
$candidateImage = DataObject::get_one("File", "\"Filename\" = '$image'");
@@ -150,7 +149,7 @@ class HtmlEditorField extends TextareaField {
$fieldName = $this->name;
if($record->ID && $record->hasMethod('LinkTracking') && $linkTracking = $record->LinkTracking()) {
- $linkTracking->removeByFilter("\"FieldName\" = '$fieldName'");
+ $linkTracking->removeByFilter("\"FieldName\" = '$fieldName' AND \"SiteTreeID\" = $record->ID");
if(isset($linkedPages)) foreach($linkedPages as $item) {
$linkTracking->add($item, array("FieldName" => $fieldName));
@@ -410,14 +409,14 @@ class HtmlEditorField_Toolbar extends RequestHandler {
new TreeDropdownField('FolderID', _t('HtmlEditorField.FOLDER', 'Folder'), 'Folder'),
new LiteralField('AddFolderOrUpload',
'
|
'
),
new TextField('getimagesSearch', _t('HtmlEditorField.SEARCHFILENAME', 'Search by file name')),
diff --git a/forms/ImageField.php b/forms/ImageField.php
index 4cd38968c..5c2c9e1ec 100755
--- a/forms/ImageField.php
+++ b/forms/ImageField.php
@@ -59,5 +59,4 @@ class ImageField extends FileField {
}
}
-
?>
\ No newline at end of file
diff --git a/forms/ImageFormAction.php b/forms/ImageFormAction.php
index afc3f4a5c..613c708e0 100755
--- a/forms/ImageFormAction.php
+++ b/forms/ImageFormAction.php
@@ -33,4 +33,4 @@ class ImageFormAction extends FormAction {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/ListboxField.php b/forms/ListboxField.php
index ef4db948b..a4e332f7d 100755
--- a/forms/ListboxField.php
+++ b/forms/ListboxField.php
@@ -80,4 +80,4 @@ class ListboxField extends DropdownField {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/LookupField.php b/forms/LookupField.php
index 55fd7ef98..dd5bd15cc 100755
--- a/forms/LookupField.php
+++ b/forms/LookupField.php
@@ -58,4 +58,4 @@ class LookupField extends DropdownField {
}
}
-?>
+?>
\ No newline at end of file
diff --git a/forms/ManyManyComplexTableField.php b/forms/ManyManyComplexTableField.php
index 012d54adb..9b8b47d9c 100644
--- a/forms/ManyManyComplexTableField.php
+++ b/forms/ManyManyComplexTableField.php
@@ -42,45 +42,15 @@ class ManyManyComplexTableField extends HasManyComplexTableField {
$this->joinField = 'Checked';
}
- function getQuery($limitClause = null) {
- if($this->customQuery) {
- $query = $this->customQuery;
- $query->select[] = "{$this->sourceClass}.ID AS ID";
- $query->select[] = "{$this->sourceClass}.ClassName AS ClassName";
- $query->select[] = "{$this->sourceClass}.ClassName AS \"RecordClassName\"";
- }
- else {
- $query = singleton($this->sourceClass)->extendedSQL($this->sourceFilter, $this->sourceSort, $limitClause, $this->sourceJoin);
-
- // Add more selected fields if they are from joined table.
-
- $SNG = singleton($this->sourceClass);
- foreach($this->FieldList() as $k => $title) {
- if(! $SNG->hasField($k) && ! $SNG->hasMethod('get' . $k))
- $query->select[] = $k;
- }
- $parent = $this->controllerClass();
- $query->select[] = "IF(\"{$this->manyManyParentClass}ID\" IS NULL, '0', '1') AS Checked";
- }
- return clone $query;
+ function getQuery() {
+ $query = parent::getQuery();
+ $query->select[] = "IF(`{$this->manyManyParentClass}ID` IS NULL, '0', '1') AS Checked";
+ return $query;
}
function getParentIdName($parentClass, $childClass) {
return $this->getParentIdNameRelation($parentClass, $childClass, 'many_many');
}
-
- function ExtraData() {
- $items = array();
- foreach($this->unpagedSourceItems as $item) {
- if($item->{$this->joinField})
- $items[] = $item->ID;
- }
- $list = implode(',', $items);
- $inputId = $this->id() . '_' . $this->htmlListEndName;
- return <<