mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merged changes from 2.3 branch
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@71172 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
2eb73817c2
commit
60f75c5ca4
@ -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');
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
@ -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);
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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();
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -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 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
|
@ -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() {}
|
||||
}
|
||||
?>
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -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:
|
||||
* <example>
|
||||
* ClassInfo::subclassesFor('BaseClass');
|
||||
* array(
|
||||
* 0 => 'BaseClass',
|
||||
* 'ChildClass' => 'ChildClass',
|
||||
* 'GrandChildClass' => 'GrandChildClass'
|
||||
* )
|
||||
* </example>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
@ -286,5 +286,4 @@ function _t($entity, $string = "", $priority = 40, $context = "") {
|
||||
return i18n::_t($entity, $string, $priority, $context);
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -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 {
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
@ -549,5 +549,4 @@ class ManifestBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
@ -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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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 <style> tag enclosing selectors).
|
||||
* @param int $uniquenessID Group CSS by a unique ID as to avoid duplicate custom CSS in header
|
||||
*/
|
||||
static function customCSS($script, $uniquenessID = null) {
|
||||
self::backend()->custom($script, $uniquenessID);
|
||||
self::backend()->customCSS($script, $uniquenessID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add the following custom code to the <head> section of the page.
|
||||
* See {@link Requirements_Backend::insertHeadTags()}
|
||||
@ -245,7 +246,7 @@ class Requirements {
|
||||
* Set whether you want to write the JS to the body of the page or
|
||||
* in the head section
|
||||
*
|
||||
* @see {@link Requirements_Backend::set_write_js_to_body()}
|
||||
* @see Requirements_Backend::set_write_js_to_body()
|
||||
* @param boolean
|
||||
*/
|
||||
static function set_write_js_to_body($var) {
|
||||
@ -390,7 +391,12 @@ class Requirements_Backend {
|
||||
$script .= "\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Include custom CSS styling to the header of the page.
|
||||
*
|
||||
* @param string $script CSS selectors as a string (without <style> tag enclosing selectors).
|
||||
* @param int $uniquenessID Group CSS by a unique ID as to avoid duplicate custom CSS in header
|
||||
*/
|
||||
function customCSS($script, $uniquenessID = null) {
|
||||
if($uniquenessID)
|
||||
$this->customCSS[$uniquenessID] = $script;
|
||||
@ -399,7 +405,6 @@ class Requirements_Backend {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the following custom code to the <head> section of the page.
|
||||
*
|
||||
@ -444,7 +449,7 @@ class Requirements_Backend {
|
||||
}
|
||||
|
||||
function get_css() {
|
||||
return array_diff_key($this->css,$this->blocked);
|
||||
return array_diff_key($this->css, $this->blocked);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -561,7 +566,7 @@ class Requirements_Backend {
|
||||
$requirements .= "<link rel=\"stylesheet\" type=\"text/css\"{$media} href=\"$path\" />\n";
|
||||
}
|
||||
}
|
||||
foreach(array_diff_key($this->customCSS,$this->blocked) as $css) {
|
||||
foreach(array_diff_key($this->customCSS, $this->blocked) as $css) {
|
||||
$requirements .= "<style type=\"text/css\">\n$css\n</style>\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 {
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
@ -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, "<html") !== false) {
|
||||
@ -369,9 +383,9 @@ class SSViewer extends Object {
|
||||
$oldContent = $content;
|
||||
|
||||
// Add include filename comments on dev sites
|
||||
if(Director::isDev()) $replacementCode = 'return "<!-- include " . SSViewer::getTemplateFile($matches[1]) . "-->\n"
|
||||
if(Director::isDev() && self::$source_file_comments) $replacementCode = 'return "<!-- include " . SSViewer::getTemplateFile($matches[1]) . " -->\n"
|
||||
. SSViewer::getTemplateContent($matches[1])
|
||||
. "\n<!-- end include " . SSViewer::getTemplateFile($matches[1]) . "-->";';
|
||||
. "\n<!-- end include " . SSViewer::getTemplateFile($matches[1]) . " -->";';
|
||||
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 "";
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -236,4 +236,4 @@ class Session {
|
||||
return self::$timeout;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -224,7 +224,7 @@ JS
|
||||
if($this->dataRecord){
|
||||
$thisPage = $this->dataRecord->Link();
|
||||
$cmsLink = 'admin/show/' . $this->dataRecord->ID;
|
||||
$cmsLink = "<a href=\"$cmsLink\" target=\"cms\">CMS</a>";
|
||||
$cmsLink = "<a href=\"$cmsLink\" target=\"cms\">". _t('ContentController.CMS', 'CMS') ."</a>";
|
||||
} 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 = "<a class=\"current\">Archived Site</a>";
|
||||
$liveLink = "<a href=\"$thisPage?stage=Live\" target=\"site\" style=\"left : -3px;\">Published Site</a>";
|
||||
$stageLink = "<a href=\"$thisPage?stage=Stage\" target=\"site\" style=\"left : -1px;\">Draft Site</a>";
|
||||
$message = "<div id=\"SilverStripeNavigatorMessage\" title=\"Note: this message won't be shown to your visitors\">Archived site from<br>" . $dateObj->Nice() . "</div>";
|
||||
$archiveLink = "<a class=\"current\">". _t('ContentController.ARCHIVEDSITE', 'Archived Site') ."</a>";
|
||||
$liveLink = "<a href=\"$thisPage?stage=Live\" target=\"site\" style=\"left : -3px;\">". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."</a>";
|
||||
$stageLink = "<a href=\"$thisPage?stage=Stage\" target=\"site\" style=\"left : -1px;\">". _t('ContentController.DRAFTSITE', 'Draft Site') ."</a>";
|
||||
$message = "<div id=\"SilverStripeNavigatorMessage\" title='". _t('ContentControl.NOTEWONTBESHOWN', 'Note: this message won\'t be shown to your visitors') ."'>". _t('ContentController.ARCHIVEDSITEFROM', 'Archived site from') ."<br>" . $dateObj->Nice() . "</div>";
|
||||
|
||||
} else if(Versioned::current_stage() == 'Stage') {
|
||||
$stageLink = "<a class=\"current\">Draft Site</a>";
|
||||
$liveLink = "<a href=\"$thisPage?stage=Live\" target=\"site\" style=\"left : -3px;\">Published Site</a>";
|
||||
$message = "<div id=\"SilverStripeNavigatorMessage\" title=\"Note: this message won't be shown to your visitors\">DRAFT SITE</div>";
|
||||
$stageLink = "<a class=\"current\">". _t('ContentController.DRAFTSITE', 'Draft Site') ."</a>";
|
||||
$liveLink = "<a href=\"$thisPage?stage=Live\" target=\"site\" style=\"left : -3px;\">". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."</a>";
|
||||
$message = "<div id=\"SilverStripeNavigatorMessage\" title='". _t('ContentControl.NOTEWONTBESHOWN', 'Note: this message won\'t be shown to your visitors') ."'>". _t('ContentController.DRAFTSITE', 'Draft Site') ."</div>";
|
||||
|
||||
} else {
|
||||
$liveLink = "<a class=\"current\">Published Site</a>";
|
||||
$stageLink = "<a href=\"$thisPage?stage=Stage\" target=\"site\" style=\"left : -1px;\">Draft Site</a>";
|
||||
$message = "<div id=\"SilverStripeNavigatorMessage\" title=\"Note: this message won't be shown to your visitors\">PUBLISHED SITE</div>";
|
||||
$liveLink = "<a class=\"current\">". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."</a>";
|
||||
$stageLink = "<a href=\"$thisPage?stage=Stage\" target=\"site\" style=\"left : -1px;\">". _t('ContentController.DRAFTSITE', 'Draft Site') ."</a>";
|
||||
$message = "<div id=\"SilverStripeNavigatorMessage\" title='". _t('ContentControl.NOTEWONTBESHOWN', 'Note: this message won\'t be shown to your visitors') ."'>". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."</div>";
|
||||
}
|
||||
|
||||
if($member) {
|
||||
$firstname = Convert::raw2xml($member->FirstName);
|
||||
$surname = Convert::raw2xml($member->Surame);
|
||||
$logInMessage = "Logged in as {$firstname} {$surname} - <a href=\"Security/logout\">log out</a>";
|
||||
$logInMessage = _t('ContentController.LOGGEDINAS', 'Logged in as') ." {$firstname} {$surname} - <a href=\"Security/logout\">". _t('ContentController.LOGOUT', 'Log out'). "</a>";
|
||||
} else {
|
||||
$logInMessage = "Not logged in - <a href=\"Security/login\">log in</a>";
|
||||
$logInMessage = _t('ContentController.NOTLOGGEDIN', 'Not logged in') ." - <a href='Security/login'>". _t('ContentController.LOGIN', 'Login') ."</a>";
|
||||
}
|
||||
|
||||
$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
|
||||
</div>
|
||||
|
||||
<div id="switchView" class="bottomTabs">
|
||||
<div class="blank"> View page in: </div>
|
||||
<div class="blank">$viewPageIn </div>
|
||||
$cmsLink
|
||||
$stageLink
|
||||
<div class="blank" style="width:1em;"> </div>
|
||||
@ -295,7 +295,7 @@ HTML;
|
||||
Requirements::css(SAPPHIRE_DIR . '/css/SilverStripeNavigator.css');
|
||||
$dateObj = Object::create('Datetime', $date, null);
|
||||
// $dateObj->setVal($date);
|
||||
return "<div id=\"SilverStripeNavigatorMessage\">Archived site from<br>" . $dateObj->Nice() . "</div>";
|
||||
return "<div id=\"SilverStripeNavigatorMessage\">". _t('ContentController.ARCHIVEDSITEFROM') ."<br>" . $dateObj->Nice() . "</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -423,5 +423,4 @@ HTML
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
@ -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 <?xml> 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');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -544,4 +544,4 @@ class Controller extends RequestHandler {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,4 +102,4 @@ class ModelAsController extends Controller implements NestedController {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------//
|
||||
|
@ -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:
|
||||
* <code>
|
||||
* class MyTestClass implements i18nEntityProvider {
|
||||
* function provideI18nEntities() {
|
||||
* $entities = array();
|
||||
* $entities["MyOtherModuleClass.MYENTITY"] = array(
|
||||
* $value,
|
||||
* PR_MEDIUM,
|
||||
* 'My context description',
|
||||
* 'myothermodule'
|
||||
* );
|
||||
* }
|
||||
* return $entities;
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @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.
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -262,4 +262,4 @@ class DB {
|
||||
return DB::$globalConn->quiet();
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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:
|
||||
* <code>
|
||||
* <% if MyPages.MoreThanOnePage %>
|
||||
* <% if MyPages.NotFirstPage %>
|
||||
* <a class="prev" href="$MyPages.PrevLink">Prev</a>
|
||||
* <% end_if %>
|
||||
* <% control MyPages.PaginationSummary(4) %>
|
||||
* <% if CurrentBool %>
|
||||
* $PageNum
|
||||
* <% else %>
|
||||
* <% if Link %>
|
||||
* <a href="$Link">$PageNum</a>
|
||||
* <% else %>
|
||||
* ...
|
||||
* <% end_if %>
|
||||
* <% end_if %>
|
||||
* <% end_control %>
|
||||
* <% if MyPages.NotLastPage %>
|
||||
* <a class="next" href="$MyPages.NextLink">Next</a>
|
||||
* <% end_if %>
|
||||
* <% end_if %>
|
||||
* </code>
|
||||
*
|
||||
* @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 {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -780,4 +780,4 @@ class Image_Uploader extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -727,5 +727,4 @@ class PDOQuery extends Query {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
@ -452,4 +452,4 @@ class SQLQuery extends Object {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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 <title> tag in separate getter for easier customization and more obvious usage
|
||||
*
|
||||
* @param boolean|string $includeTitle Show default <title>-tag, set to false for custom templating
|
||||
@ -831,7 +866,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
|
||||
? $this->MetaTitle
|
||||
: $this->Title) . "</title>\n";
|
||||
}
|
||||
$tags .= "<meta name=\"generator\" http-equiv=\"generator\" content=\"SilverStripe - http://www.silverstripe.com\" />\n";
|
||||
$version = new SapphireInfo();
|
||||
|
||||
$tags .= "<meta name=\"generator\" http-equiv=\"generator\" content=\"SilverStripe ". $version->Version() ." - http://www.silverstripe.com\" />\n";
|
||||
|
||||
$charset = ContentNegotiator::get_encoding();
|
||||
$tags .= "<meta http-equiv=\"Content-type\" content=\"text/html; charset=$charset\" />\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[] = "<li><a class=\"cmsEditlink\" href=\"admin/show/$link->ID\">" .
|
||||
$link->Breadcrumbs(null,true) . "</a></li>";
|
||||
}
|
||||
$backlinks = "<div style=\"clear:left\">
|
||||
" . _t('SiteTree.PAGESLINKING', 'The following pages link to this page:') .
|
||||
"<ul>" . implode("",$backlinks) . "</ul></div>";
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($backlinks)) {
|
||||
$backlinks = "<p>" . _t('SiteTree.NOBACKLINKS', 'This page hasn\'t been linked to from any pages.') . "</p>";
|
||||
}
|
||||
|
||||
|
||||
// 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("<br />", $statusMessage);
|
||||
}
|
||||
|
||||
$backLinksNote = '';
|
||||
$backLinksTable = new LiteralField('BackLinksNote', '<p>' . _t('NOBACKLINKEDPAGES', 'There are no pages linked to this page.') . '</p>');
|
||||
|
||||
// Create a table for showing pages linked to this one
|
||||
if($this->BackLinkTracking() && $this->BackLinkTracking()->Count() > 0) {
|
||||
$backLinksNote = new LiteralField('BackLinksNote', '<p>' . _t('SiteTree.PAGESLINKING', 'The following pages link to this page:') . '</p>');
|
||||
$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' => '<a href=\"admin/show/$ID\">$Title</a>'
|
||||
));
|
||||
$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
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -170,4 +170,4 @@ class VirtualPage_Controller extends Page_Controller {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -60,4 +60,4 @@ class Int extends DBField {
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -321,4 +321,4 @@ class Text extends DBField {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
22
css/Form.css
22
css/Form.css
@ -137,4 +137,24 @@ form .message {
|
||||
color:#FF4040;
|
||||
width:240px;
|
||||
border-color: #FF4040;
|
||||
}
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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".
|
||||
*
|
||||
* <code>
|
||||
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -130,4 +130,4 @@ class DevelopmentAdmin extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -11,4 +11,4 @@ class InstallerTest extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -171,5 +171,4 @@ class ModelViewer_Relation extends ViewableData {
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
@ -76,4 +76,4 @@ class SSCli extends Object {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -236,4 +236,4 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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 '<span class="codedirection">' . strrev($email) . '</span>';
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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.
|
||||
|
@ -124,4 +124,4 @@ class Filesystem extends Object {
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -441,11 +441,11 @@ class Folder extends File {
|
||||
*/
|
||||
function getUploadIframe() {
|
||||
return <<<HTML
|
||||
<iframe name="AssetAdmin_upload" src="admin/assets/uploadiframe/{$this->ID}" id="AssetAdmin_upload" border="0" style="border-style: none; width: 100%; height: 200px">
|
||||
<iframe name="AssetAdmin_upload" src="admin/assets/uploadiframe/{$this->ID}" id="AssetAdmin_upload" border="0" style="border-style none !important; width: 97%; min-height: 300px; height: 100%; height: expression(document.body.clientHeight) !important;">
|
||||
</iframe>
|
||||
HTML;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -408,4 +408,4 @@ class GD extends Object {
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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 .= "<li class=\"$extraClass\"><input id=\"$itemID\" name=\"$this->name[$key]\" type=\"checkbox\" value=\"$key\"$checked $disabled class=\"checkbox\" /> <label for=\"$itemID\">$value</label></li>\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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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(
|
||||
'<small><a href="' . $_SERVER['HTTP_REFERER'] . '" onclick="javascript:window.top.GB_hide(); return false;">(%s)</a></small>',
|
||||
@ -734,8 +736,8 @@ class ComplexTableField_ItemRequest extends RequestHandler {
|
||||
);
|
||||
$message = sprintf(
|
||||
_t('ComplexTableField.SUCCESSEDIT', 'Saved %s %s %s'),
|
||||
$this->dataObj()->singular_name(),
|
||||
'<a href="' . $this->Link() . '">"' . $this->dataObj()->Title . '"</a>',
|
||||
$dataObject->singular_name(),
|
||||
'<a href="' . $this->Link() . '">"' . $dataObject->Title . '"</a>',
|
||||
$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}");
|
||||
|
@ -175,4 +175,4 @@ class CompositeDateField_Disabled extends DateField {
|
||||
return "date_disabled readonly";
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -28,4 +28,4 @@ class CountryDropdownField extends DropdownField {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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 = '<i>('._t('DateField.NOTSET', 'not set').')</i>';
|
||||
$val = '<i>('._t('DateField.NOTSET', 'not set').')</i>';
|
||||
}
|
||||
|
||||
return "<span class=\"readonly\" id=\"" . $this->id() . "\">$val</span>";
|
||||
return "<span class=\"readonly\" id=\"" . $this->id() . "\">$val</span>
|
||||
<input type=\"hidden\" value=\"{$this->value}\" name=\"$this->name\" />";
|
||||
}
|
||||
|
||||
function Type() {
|
||||
@ -139,4 +140,4 @@ class DateField_Disabled extends DateField {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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)) ? "<label class=\"left\">$Title</label>" : "";
|
||||
$messageBlock = (!empty($Message)) ? "<span class=\"message $MessageType\">$Message</span>" : "";
|
||||
$rightTitleBlock = (!empty($RightTitle)) ? "<label class=\"right\">$RightTitle</label>" : "";
|
||||
|
||||
return <<<HTML
|
||||
<div id="$Name" class="field $Type $extraClass">$titleBlock<div class="middleColumn">$Field</div>$rightTitleBlock$messageBlock</div>
|
||||
HTML;
|
||||
}
|
||||
|
||||
function Message() {
|
||||
|
@ -535,4 +535,4 @@ class FieldSet extends DataObjectSet {
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -52,4 +52,4 @@ JS;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
@ -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 <<<HTML
|
||||
<input id="$inputId" name="{$this->name}[{$this->htmlListField}]" type="hidden" value="$list"/>
|
||||
@ -166,4 +126,4 @@ class HasManyComplexTableField_Item extends ComplexTableField_Item {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -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('(<img[^>]* )width=([0-9]+)( [^>]*>|>)','\\1width="\\2"\\3',$content);
|
||||
$content = eregi_replace('(<img[^>]* )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('(<img[^>]* )width=([0-9]+)( [^>]*>|>)','\\1width="\\2"\\3', $content);
|
||||
$content = eregi_replace('(<img[^>]* )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('/(<img[^>]* )(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 = "<p>$content</p>";
|
||||
|
||||
$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',
|
||||
'<div style="clear:both;"></div><div id="AddFolderGroup" style="display:inline">
|
||||
<a style="" href="#" id="AddFolder" class="link">' . _t('HtmlEditorField.CREATEFOLDER','create folder') . '</a>
|
||||
<a style="" href="#" id="AddFolder" class="link">' . _t('HtmlEditorField.CREATEFOLDER','Create Folder') . '</a>
|
||||
<input style="display: none; margin-left: 2px; width: 94px;" id="NewFolderName" class="addFolder" type="text">
|
||||
<a style="display: none;" href="#" id="FolderOk" class="link addFolder">' . _t('HtmlEditorField.OK','ok') . '</a>
|
||||
<a style="display: none;" href="#" id="FolderCancel" class="link addFolder">' . _t('HtmlEditorField.FOLDERCANCEL','cancel') . '</a>
|
||||
<a style="display: none;" href="#" id="FolderOk" class="link addFolder">' . _t('HtmlEditorField.OK','Ok') . '</a>
|
||||
<a style="display: none;" href="#" id="FolderCancel" class="link addFolder">' . _t('HtmlEditorField.FOLDERCANCEL','Cancel') . '</a>
|
||||
</div>
|
||||
<div id="PipeSeparator" style="display:inline">|</div>
|
||||
<div id="UploadGroup" class="group" style="display: inline; margin-top: 2px;">
|
||||
<a href="#" id="UploadFiles" class="link">' . _t('HtmlEditorField.UPLOAD','upload') . '</a>
|
||||
<a href="#" id="UploadFiles" class="link">' . _t('HtmlEditorField.UPLOAD','Upload') . '</a>
|
||||
</div>'
|
||||
),
|
||||
new TextField('getimagesSearch', _t('HtmlEditorField.SEARCHFILENAME', 'Search by file name')),
|
||||
|
@ -59,5 +59,4 @@ class ImageField extends FileField {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -33,4 +33,4 @@ class ImageFormAction extends FormAction {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -80,4 +80,4 @@ class ListboxField extends DropdownField {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -58,4 +58,4 @@ class LookupField extends DropdownField {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -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 <<<HTML
|
||||
<input id="$inputId" name="{$this->name}[{$this->htmlListField}]" type="hidden" value="$list"/>
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,4 +62,4 @@ JS;
|
||||
return (is_numeric($this->value)) ? $this->value : 0;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -49,4 +49,4 @@ class PasswordField extends FormField {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -189,4 +189,4 @@ JS;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -6,6 +6,21 @@
|
||||
*/
|
||||
class PopupDateTimeField extends CalendarDateField {
|
||||
|
||||
/**
|
||||
* @todo js validation needs to be implemented.
|
||||
* @see sapphire/forms/DateField#jsValidation()
|
||||
*/
|
||||
function jsValidation() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo php validation needs to be implemented.
|
||||
* @see sapphire/forms/DateField#validate($validator)
|
||||
*/
|
||||
function validate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function Field() {
|
||||
|
||||
Requirements::css( SAPPHIRE_DIR . '/css/PopupDateTimeField.css' );
|
||||
|
@ -393,5 +393,4 @@ class ReportField_Controller extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -8,11 +8,36 @@
|
||||
class ResetFormAction extends FormAction {
|
||||
|
||||
function Field() {
|
||||
$titleAttr = $this->description ? "title=\"" . Convert::raw2att($this->description) . "\"" : '';
|
||||
if($this->useButtonTag) {
|
||||
return "<button class=\"action " . $this->extraClass() . "\" id=\"" . $this->id() . "\" type=\"reset\" name=\"$this->action\" $titleAttr />" . $this->attrTitle() . "</button>\n";
|
||||
$attributes = array(
|
||||
'class' => 'action' . ($this->extraClass() ? $this->extraClass() : ''),
|
||||
'id' => $this->id(),
|
||||
'type' => 'reset',
|
||||
'name' => $this->action
|
||||
);
|
||||
|
||||
if($this->isReadonly()) {
|
||||
$attributes['disabled'] = 'disabled';
|
||||
$attributes['class'] = $attributes['class'] . ' disabled';
|
||||
}
|
||||
|
||||
return $this->createTag('button', $attributes, $this->attrTitle());
|
||||
} else {
|
||||
return "<input class=\"action " . $this->extraClass() . "\" id=\"" . $this->id() . "\" type=\"reset\" name=\"$this->action\" value=\"" . $this->attrTitle() . "\" $titleAttr />\n";
|
||||
$attributes = array(
|
||||
'class' => 'action' . ($this->extraClass() ? $this->extraClass() : ''),
|
||||
'id' => $this->id(),
|
||||
'type' => 'reset',
|
||||
'name' => $this->action,
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,4 @@ class Tab extends CompositeField {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
?>
|
||||
?>
|
@ -118,4 +118,4 @@ class TabSet extends CompositeField {
|
||||
parent::removeByName( $tabName, $dataFieldOnly );
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -223,7 +223,7 @@ class TableField extends TableListField {
|
||||
|
||||
function SubmittedFieldSet(&$sourceItems){
|
||||
$fields = array ();
|
||||
if($rows = $_POST[$this->name]){
|
||||
if(isset($_POST[$this->name])&&$rows = $_POST[$this->name]){
|
||||
if(count($rows)){
|
||||
foreach($rows as $idx => $row){
|
||||
if($idx == 'new'){
|
||||
@ -772,4 +772,4 @@ class TableField_Item extends TableListField_Item {
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -801,6 +801,7 @@ JS
|
||||
}
|
||||
|
||||
function FirstItem() {
|
||||
if ($this->TotalCount() < 1) return 0;
|
||||
return isset($_REQUEST['ctf'][$this->Name()]['start']) ? $_REQUEST['ctf'][$this->Name()]['start'] + 1 : 1;
|
||||
}
|
||||
|
||||
@ -894,6 +895,8 @@ JS
|
||||
/**
|
||||
* Exports a given set of comma-separated IDs (from a previous search-query, stored in a HiddenField).
|
||||
* Uses {$csv_columns} if present, and falls back to {$result_columns}.
|
||||
* We move the most filedata generation code to the function {@link generateExportFileData()} so that a child class
|
||||
* could reuse the filedata generation code while overwrite export function.
|
||||
*
|
||||
* @todo Make relation-syntax available (at the moment you'll have to use custom sql)
|
||||
*/
|
||||
@ -901,19 +904,28 @@ JS
|
||||
$now = Date("d-m-Y-H-i");
|
||||
$fileName = "export-$now.csv";
|
||||
|
||||
if($fileData = $this->generateExportFileData($numColumns, $numRows)){
|
||||
return HTTPRequest::send_file($fileData, $fileName);
|
||||
}else{
|
||||
user_error("No records found", E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
function generateExportFileData(&$numColumns, &$numRows) {
|
||||
$separator = $this->csvSeparator;
|
||||
$csvColumns = ($this->fieldListCsv) ? $this->fieldListCsv : $this->fieldList;
|
||||
$fileData = "";
|
||||
$fileData = '';
|
||||
$columnData = array();
|
||||
$fieldItems = new DataObjectSet();
|
||||
|
||||
if($this->csvHasHeader) {
|
||||
$fileData .= "\"" . implode("\"{$separator}\"",array_values($csvColumns)) . "\"";
|
||||
$fileData .= "\"" . implode("\"{$separator}\"", array_values($csvColumns)) . "\"";
|
||||
$fileData .= "\n";
|
||||
}
|
||||
|
||||
// get data
|
||||
if(isset($this->customSourceItems)){
|
||||
if(isset($this->customSourceItems)) {
|
||||
$items = $this->customSourceItems;
|
||||
}else{
|
||||
} else {
|
||||
$dataQuery = $this->getCsvQuery();
|
||||
$records = $dataQuery->execute();
|
||||
$sourceClass = $this->sourceClass;
|
||||
@ -921,7 +933,6 @@ JS
|
||||
$items = $dataobject->buildDataObjectSet($records, 'DataObjectSet');
|
||||
}
|
||||
|
||||
$fieldItems = new DataObjectSet();
|
||||
if($items && $items->count()) foreach($items as $item) {
|
||||
// create a TableListField_Item to support resolving of
|
||||
// relation-fields in dot notation via TableListField_Item->Fields()
|
||||
@ -934,15 +945,14 @@ JS
|
||||
|
||||
if($fieldItems) {
|
||||
foreach($fieldItems as $fieldItem) {
|
||||
$columnData = array();
|
||||
$fields = $fieldItem->Fields();
|
||||
foreach($fields as $field) {
|
||||
|
||||
$columnData = array();
|
||||
if($fields) foreach($fields as $field) {
|
||||
$value = $field->Value;
|
||||
|
||||
// TODO This should be replaced with casting
|
||||
if(array_key_exists($field->Name, $this->csvFieldFormatting)) {
|
||||
$format = str_replace('$value', "__VAL__", $this->csvFieldFormatting[$columnName]);
|
||||
$format = str_replace('$value', "__VAL__", $this->csvFieldFormatting[$field->Name]);
|
||||
$format = preg_replace('/\$([A-Za-z0-9-_]+)/','$item->$1', $format);
|
||||
$format = str_replace('__VAL__', '$value', $format);
|
||||
eval('$value = "' . $format . '";');
|
||||
@ -955,9 +965,12 @@ JS
|
||||
$fileData .= implode($separator, $columnData);
|
||||
$fileData .= "\n";
|
||||
}
|
||||
return HTTPRequest::send_file($fileData, $fileName);
|
||||
|
||||
$numColumns = count($columnData);
|
||||
$numRows = $fieldItems->count();
|
||||
return $fileData;
|
||||
} else {
|
||||
user_error("No records found", E_USER_ERROR);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1416,4 +1429,4 @@ class TableListField_ItemRequest extends RequestHandler {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -94,4 +94,4 @@ class TextareaField extends FormField {
|
||||
return parent::Type() . ( $this->readonly ? ' readonly' : '' );
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
@ -137,4 +137,4 @@ HTML;
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
@ -1,127 +0,0 @@
|
||||
/**
|
||||
* @author Tim Copeland
|
||||
*/
|
||||
// Browser detection
|
||||
|
||||
var BrowserDetect = {
|
||||
init: function () {
|
||||
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
|
||||
this.version = this.searchVersion(navigator.userAgent)
|
||||
|| this.searchVersion(navigator.appVersion)
|
||||
|| "an unknown version";
|
||||
this.OS = this.searchString(this.dataOS) || "an unknown OS";
|
||||
},
|
||||
searchString: function (data) {
|
||||
for (var i=0;i<data.length;i++) {
|
||||
var dataString = data[i].string;
|
||||
var dataProp = data[i].prop;
|
||||
this.versionSearchString = data[i].versionSearch || data[i].identity;
|
||||
if (dataString) {
|
||||
if (dataString.indexOf(data[i].subString) != -1)
|
||||
return data[i].identity;
|
||||
}
|
||||
else if (dataProp)
|
||||
return data[i].identity;
|
||||
}
|
||||
},
|
||||
searchVersion: function (dataString) {
|
||||
var index = dataString.indexOf(this.versionSearchString);
|
||||
if (index == -1) return;
|
||||
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
|
||||
},
|
||||
dataBrowser: [
|
||||
{
|
||||
string: navigator.vendor,
|
||||
subString: "Apple",
|
||||
identity: "Safari"
|
||||
},
|
||||
{
|
||||
prop: window.opera,
|
||||
identity: "Opera"
|
||||
},
|
||||
{
|
||||
string: navigator.vendor,
|
||||
subString: "iCab",
|
||||
identity: "iCab"
|
||||
},
|
||||
{
|
||||
string: navigator.vendor,
|
||||
subString: "KDE",
|
||||
identity: "Konqueror"
|
||||
},
|
||||
{
|
||||
string: navigator.userAgent,
|
||||
subString: "Firefox",
|
||||
identity: "Firefox"
|
||||
},
|
||||
{ // for newer Netscapes (6+)
|
||||
string: navigator.userAgent,
|
||||
subString: "Netscape",
|
||||
identity: "Netscape"
|
||||
},
|
||||
{
|
||||
string: navigator.userAgent,
|
||||
subString: "MSIE",
|
||||
identity: "Explorer",
|
||||
versionSearch: "MSIE"
|
||||
},
|
||||
{
|
||||
string: navigator.userAgent,
|
||||
subString: "Gecko",
|
||||
identity: "Mozilla",
|
||||
versionSearch: "rv"
|
||||
},
|
||||
{ // for older Netscapes (4-)
|
||||
string: navigator.userAgent,
|
||||
subString: "Mozilla",
|
||||
identity: "Netscape",
|
||||
versionSearch: "Mozilla"
|
||||
}
|
||||
],
|
||||
dataOS : [
|
||||
{
|
||||
string: navigator.platform,
|
||||
subString: "Win",
|
||||
identity: "Windows"
|
||||
},
|
||||
{
|
||||
string: navigator.platform,
|
||||
subString: "Mac",
|
||||
identity: "Mac"
|
||||
},
|
||||
{
|
||||
string: navigator.platform,
|
||||
subString: "Linux",
|
||||
identity: "Linux"
|
||||
}
|
||||
]
|
||||
|
||||
};
|
||||
BrowserDetect.init();
|
||||
|
||||
Behaviour.register({
|
||||
'#all' : {
|
||||
initialise: function() {
|
||||
if( BrowserDetect.browser == "Firefox" /*&& BrowserDetect.version >= 1.5*/ ||
|
||||
(BrowserDetect.browser == "Explorer" && BrowserDetect.version >= 6) ||
|
||||
(BrowserDetect.browser == "Mozilla" && BrowserDetect.version >= 1.2)
|
||||
) {
|
||||
|
||||
$("noSupport").style.display = "none"
|
||||
$("supported").style.display = "block"
|
||||
|
||||
}
|
||||
|
||||
//center the all holder
|
||||
$("all").style.left = (document.body.offsetWidth /2) - ( $("all").offsetWidth /2) -2 + "px"
|
||||
}
|
||||
},
|
||||
|
||||
'#LoginForm_LoginForm_action_login' : {
|
||||
onclick: function() {
|
||||
document.body.style.backgroundColor = "white";
|
||||
// Effect.Puff("all");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
})
|
@ -136,8 +136,10 @@ TableListField.prototype = {
|
||||
{
|
||||
postBody: 'update=1',
|
||||
onComplete: function(response) {
|
||||
Element.replace(this.id, response.responseText)
|
||||
Behaviour.apply($(this.id))
|
||||
Element.replace(this.id, response.responseText);
|
||||
// reapply behaviour and reattach methods to TF container node
|
||||
// e.g. <div class="TableListField">
|
||||
Behaviour.apply($(this.id), true);
|
||||
}.bind(this)
|
||||
}
|
||||
);
|
||||
|
@ -134,7 +134,7 @@ TreeDropdownField.prototype = {
|
||||
this.treeShown = false;
|
||||
if(this.itemTree) {
|
||||
this.itemTree.style.display = 'none';
|
||||
Event.stopObserving(document, 'click', this.bound_testForBlur);
|
||||
if(this.bound_testForBlur) Event.stopObserving(document, 'click', this.bound_testForBlur);
|
||||
// this.editLink.style.display = this.humanItems.style.display = 'block';
|
||||
this.unstretchIframeIfNeeded();
|
||||
}
|
||||
|
5
main.php
5
main.php
@ -57,7 +57,7 @@ if($majorVersion < 5) {
|
||||
*/
|
||||
require_once("core/Core.php");
|
||||
|
||||
header("Content-type: text/html; charset=\"utf-8\"");
|
||||
if(!headers_sent()) header("Content-type: text/html; charset=\"utf-8\"");
|
||||
if (function_exists('mb_http_output')) {
|
||||
mb_http_output('UTF-8');
|
||||
mb_internal_encoding('UTF-8');
|
||||
@ -86,8 +86,7 @@ if (isset($_GET['url'])) {
|
||||
}
|
||||
|
||||
// Fix glitches in URL generation
|
||||
if (substr($url, 0, strlen(BASE_URL)) == BASE_URL) $url = substr($url, strlen(BASE_URL));
|
||||
|
||||
if (substr(strtolower($url), 0, strlen(BASE_URL)) == strtolower(BASE_URL)) $url = substr($url, strlen(BASE_URL));
|
||||
|
||||
if (isset($_GET['debug_profile'])) {
|
||||
Profiler::init();
|
||||
|
@ -165,4 +165,4 @@ class BBCodeParser extends TextParser {
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
@ -213,17 +213,20 @@ class SSHTMLBBCodeParser
|
||||
$filter = ucfirst($filter);
|
||||
if (!array_key_exists($filter, $this->_filters)) {
|
||||
$class = 'SSHTMLBBCodeParser_Filter_'.$filter;
|
||||
@include_once 'BBCodeParser/Filter/'.$filter.'.php';
|
||||
if (fopen('BBCodeParser/Filter/'.$filter.'.php','r',true)) {
|
||||
include_once 'BBCodeParser/Filter/'.$filter.'.php';
|
||||
}
|
||||
if (!class_exists($class)) {
|
||||
|
||||
//PEAR::raiseError("Failed to load filter $filter", null, PEAR_ERROR_DIE);
|
||||
}
|
||||
|
||||
$this->_filters[$filter] = new $class;
|
||||
$this->_definedTags = array_merge(
|
||||
$this->_definedTags,
|
||||
$this->_filters[$filter]->_definedTags
|
||||
);
|
||||
else {
|
||||
$this->_filters[$filter] = new $class;
|
||||
$this->_definedTags = array_merge(
|
||||
$this->_definedTags,
|
||||
$this->_filters[$filter]->_definedTags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -242,4 +242,4 @@ function profiler_stop($name) {
|
||||
$GLOBALS["midcom_profiler"]->stopTimer ($name);
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
13
sake
13
sake
@ -48,7 +48,7 @@ if [ "$1" = "-start" ]; then
|
||||
echo "You need to install the 'daemon' tool. In debian, go 'sudo apt-get install daemon'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if [ ! -f $base/$2.pid ]; then
|
||||
echo "Starting service $2 $3"
|
||||
touch $base/$2.pid
|
||||
@ -61,11 +61,18 @@ if [ "$1" = "-start" ]; then
|
||||
|
||||
sake=`realpath $0`
|
||||
base=`realpath $base`
|
||||
|
||||
# if third argument is not explicitly given, copy from second argument
|
||||
if [ "$3" = "" ]; then
|
||||
url=$2
|
||||
else
|
||||
url=$3
|
||||
fi
|
||||
|
||||
# TODO: Give a globally unique processname by including the projectname as well
|
||||
processname=$2
|
||||
|
||||
daemon -n $processname -r -D $base --pidfile=$pidfile --stdout=$outlog --stderr=$errlog $sake $2 $3
|
||||
daemon -n $processname -r -D $base --pidfile=$pidfile --stdout=$outlog --stderr=$errlog $sake $url
|
||||
else
|
||||
echo "Service $2 seems to already be running"
|
||||
fi
|
||||
@ -89,4 +96,4 @@ fi
|
||||
################################################################################################
|
||||
## Basic execution
|
||||
|
||||
$php $sapphire/cli-script.php ${*}
|
||||
$php $sapphire/cli-script.php ${*}
|
||||
|
@ -134,5 +134,4 @@ class AdvancedSearchForm extends SearchForm {
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -31,6 +31,11 @@ class SearchForm extends Form {
|
||||
*/
|
||||
protected $pageLength = 10;
|
||||
|
||||
/**
|
||||
* Classes to search
|
||||
*/
|
||||
protected $classesToSearch = array("SiteTree", "File");
|
||||
|
||||
/**
|
||||
*
|
||||
* @param Controller $controller
|
||||
@ -73,6 +78,19 @@ class SearchForm extends Form {
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the classes to search.
|
||||
* Currently you can only choose from "SiteTree" and "File", but a future version might improve this.
|
||||
*/
|
||||
function classesToSearch($classes) {
|
||||
$illegalClasses = array_diff($classes, array('SiteTree', 'File'));
|
||||
if($illegalClasses) {
|
||||
user_error("SearchForm::classesToSearch() passed illegal classes '" . implode("', '", $illegalClasses) . "'. At this stage, only File and SiteTree are allowed", E_USER_WARNING);
|
||||
}
|
||||
$legalClasses = array_intersect($classes, array('SiteTree', 'File'));
|
||||
$this->classesToSearch = $legalClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return dataObjectSet of the results using $_REQUEST to get info from form.
|
||||
* Wraps around {@link searchEngine()}.
|
||||
@ -150,66 +168,71 @@ class SearchForm extends Form {
|
||||
public function searchEngine($keywords, $pageLength = null, $sortBy = "Relevance DESC", $extraFilter = "", $booleanSearch = false, $alternativeFileFilter = "", $invertedMatch = false) {
|
||||
if(!$pageLength) $pageLength = $this->pageLength;
|
||||
$fileFilter = '';
|
||||
|
||||
$keywords = Convert::raw2sql($keywords);
|
||||
$htmlEntityKeywords = htmlentities($keywords);
|
||||
|
||||
|
||||
$extraFilters = array('SiteTree' => '', 'File' => '');
|
||||
|
||||
if($booleanSearch) $boolean = "IN BOOLEAN MODE";
|
||||
|
||||
if($extraFilter) {
|
||||
$extraFilter = " AND $extraFilter";
|
||||
$fileFilter = ($alternativeFileFilter) ? " AND $alternativeFileFilter" : $extraFilter;
|
||||
$extraFilters['SiteTree'] = " AND $extraFilter";
|
||||
|
||||
if($alternativeFileFilter) $extraFilters['File'] = " AND $alternativeFileFilter";
|
||||
else $extraFilters['File'] = $extraFilters['SiteTree'];
|
||||
}
|
||||
|
||||
if($this->showInSearchTurnOn) $extraFilter .= " AND showInSearch <> 0";
|
||||
if($this->showInSearchTurnOn) $extraFilters['SiteTree'] .= " AND showInSearch <> 0";
|
||||
|
||||
$start = isset($_GET['start']) ? (int)$_GET['start'] : 0;
|
||||
$limit = $start . ", " . (int) $pageLength;
|
||||
|
||||
$notMatch = $invertedMatch ? "NOT " : "";
|
||||
if($keywords) {
|
||||
$matchContent = "
|
||||
MATCH (Title, MenuTitle, MetaTitle, MetaDescription, MetaKeywords) AGAINST ('$keywords' $boolean)
|
||||
+ MATCH (Content) AGAINST ('$htmlEntityKeywords' $boolean)
|
||||
";
|
||||
$matchFile = "MATCH (Filename, Title, Content) AGAINST ('$keywords' $boolean) AND ClassName = 'File'";
|
||||
$match['SiteTree'] = "MATCH (Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords) AGAINST ('$keywords' $boolean)";
|
||||
$match['File'] = "MATCH (Filename, Title, Content) AGAINST ('$keywords' $boolean) AND ClassName = 'File'";
|
||||
|
||||
// We make the relevance search by converting a boolean mode search into a normal one
|
||||
$relevanceKeywords = str_replace(array('*','+','-'),'',$keywords);
|
||||
$htmlEntityRelevanceKeywords = str_replace(array('*','+','-'),'',$htmlEntityKeywords);
|
||||
$relevanceContent = "
|
||||
MATCH (Title) AGAINST ('$relevanceKeywords')
|
||||
+ MATCH(Content) AGAINST ('$htmlEntityRelevanceKeywords')
|
||||
+ MATCH (Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords) AGAINST ('$relevanceKeywords')
|
||||
";
|
||||
$relevanceFile = "MATCH (Filename, Title, Content) AGAINST ('$relevanceKeywords')";
|
||||
$relevance['SiteTree'] = "MATCH (Title) AGAINST ('$relevanceKeywords') + MATCH(Content) AGAINST ('$htmlEntityRelevanceKeywords') + MATCH (Title, MenuTitle, Content, MetaTitle, MetaDescription, MetaKeywords) AGAINST ('$relevanceKeywords')";
|
||||
$relevance['File'] = "MATCH (Filename, Title, Content) AGAINST ('$relevanceKeywords')";
|
||||
} else {
|
||||
$relevanceContent = $relevanceFile = 1;
|
||||
$matchContent = $matchFile = "1 = 1";
|
||||
$relevance['SiteTree'] = $relevance['File'] = 1;
|
||||
$match['SiteTree'] = $match['File'] = "1 = 1";
|
||||
}
|
||||
|
||||
$queryContent = singleton('SiteTree')->extendedSQL($notMatch . $matchContent . $extraFilter, "");
|
||||
|
||||
$baseClass = reset($queryContent->from);
|
||||
// There's no need to do all that joining
|
||||
$queryContent->from = array(str_replace(array('`','"'),'',$baseClass) => $baseClass);
|
||||
$queryContent->select = array("\"ClassName\"","$baseClass.\"ID\"","\"ParentID\"","\"Title\"",
|
||||
"\"URLSegment\"","\"Content\"","\"LastEdited\"","\"Created\"","'' AS \"Filename\"",
|
||||
"'' AS \"Name\"", "$relevanceContent AS \"Relevance\"", "\"CanViewType\"");
|
||||
$queryContent->orderby = null;
|
||||
|
||||
$queryFiles = singleton('File')->extendedSQL($notMatch . $matchFile . $fileFilter, "");
|
||||
$baseClass = reset($queryFiles->from);
|
||||
// There's no need to do all that joining
|
||||
$queryFiles->from = array(str_replace(array('`','"'),'',$baseClass) => $baseClass);
|
||||
$queryFiles->select = array("\"ClassName\"","$baseClass.\"ID\"","'' AS \"ParentID\"","\"Title\"",
|
||||
"'' AS \"URLSegment\"","\"Content\"","\"LastEdited\"","\"Created\"","\"Filename\"","\"Name\"",
|
||||
"$relevanceFile AS \"Relevance\"","NULL AS \"CanViewType\"");
|
||||
$queryFiles->orderby = null;
|
||||
// Generate initial queries and base table names
|
||||
$baseClasses = array('SiteTree' => '', 'File' => '');
|
||||
foreach($this->classesToSearch as $class) {
|
||||
$queries[$class] = singleton($class)->extendedSQL($notMatch . $match[$class] . $extraFilters[$class], "");
|
||||
$baseClasses[$class] = reset($queries[$class]->from);
|
||||
}
|
||||
|
||||
$fullQuery = $queryContent->sql() . " UNION " . $queryFiles->sql() . " ORDER BY $sortBy LIMIT $limit";
|
||||
$totalCount = $queryContent->unlimitedRowCount() + $queryFiles->unlimitedRowCount();
|
||||
|
||||
// Make column selection lists
|
||||
$select = array(
|
||||
'SiteTree' => array("ClassName","$baseClasses[SiteTree].ID","ParentID","Title","URLSegment","Content","LastEdited","Created","_utf8'' AS Filename", "_utf8'' AS Name", "$relevance[SiteTree] AS Relevance", "CanViewType"),
|
||||
'File' => array("ClassName","$baseClasses[File].ID","_utf8'' AS ParentID","Title","_utf8'' AS URLSegment","Content","LastEdited","Created","Filename","Name","$relevance[File] AS Relevance","NULL AS CanViewType"),
|
||||
);
|
||||
|
||||
// Process queries
|
||||
foreach($this->classesToSearch as $class) {
|
||||
// There's no need to do all that joining
|
||||
$queries[$class]->from = array(str_replace('`','',$baseClasses[$class]) => $baseClasses[$class]);
|
||||
$queries[$class]->select = $select[$class];
|
||||
$queries[$class]->orderby = null;
|
||||
}
|
||||
|
||||
// Combine queries
|
||||
$querySQLs = array();
|
||||
$totalCount = 0;
|
||||
foreach($queries as $query) {
|
||||
$querySQLs[] = $query->sql();
|
||||
$totalCount += $query->unlimitedRowCount();
|
||||
}
|
||||
$fullQuery = implode(" UNION ", $querySQLs) . " ORDER BY $sortBy LIMIT $limit";
|
||||
|
||||
// Get records
|
||||
$records = DB::query($fullQuery);
|
||||
|
||||
foreach($records as $record)
|
||||
@ -254,4 +277,4 @@ class SearchForm extends Form {
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -186,5 +186,4 @@ abstract class Authenticator extends Object {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -100,5 +100,4 @@ class ChangePasswordForm extends Form {
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -278,6 +278,14 @@ class Group extends DataObject {
|
||||
|| (Member::currentUserID() && !DataObject::get("Permission", "GroupID = $this->ID AND Code = 'ADMIN'"));
|
||||
}
|
||||
}
|
||||
|
||||
public function canView() {
|
||||
if($this->hasMethod('alternateCanView')) return $this->alternateCanView();
|
||||
else {
|
||||
return Permission::check("ADMIN")
|
||||
|| (Member::currentUserID() && !DataObject::get("Permission", "GroupID = $this->ID AND Code = 'ADMIN'"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the children for the CMS Tree.
|
||||
@ -317,4 +325,4 @@ class Group extends DataObject {
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -27,6 +27,12 @@ class LoginAttempt extends DataObject {
|
||||
'Member' => 'Member', // only linked if the member actually exists
|
||||
);
|
||||
|
||||
static $has_many = array();
|
||||
|
||||
static $many_many = array();
|
||||
|
||||
static $belongs_many_many = array();
|
||||
|
||||
function fieldLabels() {
|
||||
$labels = parent::fieldLabels();
|
||||
$labels['Email'] = _t('LoginAttempt.Email', 'Email Address');
|
||||
|
@ -7,17 +7,16 @@
|
||||
class Member extends DataObject {
|
||||
|
||||
static $db = array(
|
||||
'FirstName' => "Varchar",
|
||||
'Surname' => "Varchar",
|
||||
'Email' => "Varchar",
|
||||
'Password' => "Varchar(64)", // support for up to SHA256!
|
||||
'RememberLoginToken' => "Varchar(50)",
|
||||
'NumVisit' => "Int",
|
||||
'FirstName' => 'Varchar',
|
||||
'Surname' => 'Varchar',
|
||||
'Email' => 'Varchar',
|
||||
'Password' => 'Varchar(64)', // support for up to SHA256!
|
||||
'RememberLoginToken' => 'Varchar(50)',
|
||||
'NumVisit' => 'Int',
|
||||
'LastVisited' => 'SSDatetime',
|
||||
'Bounced' => 'Boolean', // Note: This does not seem to be used anywhere.
|
||||
'AutoLoginHash' => 'Varchar(30)',
|
||||
'AutoLoginExpired' => 'SSDatetime',
|
||||
'BlacklistedEmail' => 'Boolean',
|
||||
'PasswordEncryption' => "Enum('none', 'none')",
|
||||
'Salt' => 'Varchar(50)',
|
||||
'PasswordExpiry' => 'Date',
|
||||
@ -26,11 +25,13 @@ class Member extends DataObject {
|
||||
);
|
||||
|
||||
static $belongs_many_many = array(
|
||||
"Groups" => "Group",
|
||||
'Groups' => 'Group',
|
||||
);
|
||||
|
||||
static $has_one = array();
|
||||
|
||||
static $has_many = array();
|
||||
|
||||
static $many_many = array();
|
||||
|
||||
static $many_many_extraFields = array();
|
||||
@ -68,6 +69,15 @@ class Member extends DataObject {
|
||||
'Email',
|
||||
);
|
||||
|
||||
/**
|
||||
* The unique field used to identify this member.
|
||||
* By default, it's "Email", but another common
|
||||
* field could be Username.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $unique_identifier_field = 'Email';
|
||||
|
||||
/**
|
||||
* {@link PasswordValidator} object for validating user's password
|
||||
*/
|
||||
@ -130,8 +140,30 @@ class Member extends DataObject {
|
||||
// This can be called via CLI during testing.
|
||||
if(Director::is_cli()) return;
|
||||
|
||||
$file = ""; $line = "";
|
||||
if (!headers_sent($file, $line)) session_regenerate_id(true);
|
||||
$file = '';
|
||||
$line = '';
|
||||
|
||||
if(!headers_sent($file, $line)) session_regenerate_id(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field used for uniquely identifying a member
|
||||
* in the database. {@see Member::$unique_identifier_field}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function get_unique_identifier_field() {
|
||||
return self::$unique_identifier_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field used for uniquely identifying a member
|
||||
* in the database. {@see Member::$unique_identifier_field}
|
||||
*
|
||||
* @param $field The field name to set as the unique field
|
||||
*/
|
||||
static function set_unique_identifier_field($field) {
|
||||
self::$unique_identifier_field = $field;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,7 +230,10 @@ class Member extends DataObject {
|
||||
Session::set('Member.FailedLogins', $failedLogins);
|
||||
}
|
||||
|
||||
$this->LockedOutUntil = null;
|
||||
// Don't set column if its not built yet (the login might be precursor to a /dev/build...)
|
||||
if(array_key_exists('LockedOutUntil', DB::fieldList('Member'))) {
|
||||
$this->LockedOutUntil = null;
|
||||
}
|
||||
|
||||
$this->write();
|
||||
|
||||
@ -388,30 +423,6 @@ class Member extends DataObject {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the members email address to the blacklist
|
||||
*
|
||||
* With this method the blacklisted email table is updated to ensure that
|
||||
* no promotional material is sent to the member (newsletters).
|
||||
* Standard system messages are still sent such as receipts.
|
||||
*
|
||||
* @param bool $val Set to TRUE if the address should be added to the
|
||||
* blacklist, otherwise to FALSE.
|
||||
*/
|
||||
function setBlacklistedEmail($val) {
|
||||
if($val && $this->Email) {
|
||||
$blacklisting = new Email_BlackList();
|
||||
$blacklisting->BlockedEmail = $this->Email;
|
||||
$blacklisting->MemberID = $this->ID;
|
||||
$blacklisting->write();
|
||||
}
|
||||
|
||||
$this->setField("BlacklistedEmail", $val);
|
||||
// Save the BlacklistedEmail field to the Member table
|
||||
$this->write();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate a random password, with randomiser to kick in if there's no words file on the
|
||||
* filesystem.
|
||||
@ -437,29 +448,18 @@ class Member extends DataObject {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Event handler called before writing to the database
|
||||
*
|
||||
* If an email's filled out look for a record with the same email and if
|
||||
* found update this record to merge with that member.
|
||||
* Event handler called before writing to the database.
|
||||
*/
|
||||
|
||||
function onBeforeWrite() {
|
||||
if($this->SetPassword) $this->Password = $this->SetPassword;
|
||||
|
||||
if($this->Email) {
|
||||
if($this->ID) {
|
||||
$idClause = "AND \"Member\".\"ID\" <> $this->ID";
|
||||
} else {
|
||||
$idClause = "";
|
||||
}
|
||||
|
||||
$existingRecord = DataObject::get_one(
|
||||
"Member", "\"Email\" = '" . addslashes($this->Email) . "' $idClause");
|
||||
|
||||
// Debug::message("Found an existing member for email $this->Email");
|
||||
|
||||
$identifierField = self::$unique_identifier_field;
|
||||
if($this->$identifierField) {
|
||||
$idClause = ($this->ID) ? " AND \"Member\".\"ID\" <> $this->ID" : '';
|
||||
$SQL_identifierField = Convert::raw2sql($this->$identifierField);
|
||||
|
||||
$existingRecord = DataObject::get_one('Member', "\"$identifierField\" = '{$SQL_identifierField}'{$idClause}");
|
||||
if($existingRecord) {
|
||||
$newID = $existingRecord->ID;
|
||||
if($this->ID) {
|
||||
@ -761,15 +761,13 @@ class Member extends DataObject {
|
||||
$groupIDList = array();
|
||||
|
||||
if(is_a($groups, 'DataObjectSet')) {
|
||||
foreach($groups as $group)
|
||||
foreach($groups as $group) {
|
||||
$groupIDList[] = $group->ID;
|
||||
}
|
||||
} elseif(is_array($groups)) {
|
||||
$groupIDList = $groups;
|
||||
}
|
||||
|
||||
/*if( empty( $groupIDList ) )
|
||||
return Member::map(); */
|
||||
|
||||
$filterClause = ($groupIDList)
|
||||
? "\"GroupID\" IN (" . implode( ',', $groupIDList ) . ")"
|
||||
: "";
|
||||
@ -792,8 +790,7 @@ class Member extends DataObject {
|
||||
* @return array Groups in which the member is NOT in.
|
||||
*/
|
||||
public function memberNotInGroups($groupList, $memberGroups = null){
|
||||
if(!$memberGroups)
|
||||
$memberGroups = $this->Groups();
|
||||
if(!$memberGroups) $memberGroups = $this->Groups();
|
||||
|
||||
foreach($memberGroups as $group) {
|
||||
if(in_array($group->Code, $groupList)) {
|
||||
@ -801,6 +798,7 @@ class Member extends DataObject {
|
||||
unset($groupList[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
return $groupList;
|
||||
}
|
||||
|
||||
@ -846,11 +844,6 @@ class Member extends DataObject {
|
||||
$locale
|
||||
));
|
||||
|
||||
$mainFields->insertAfter(
|
||||
new TreeMultiselectField("Groups", _t("Member.SECURITYGROUPS", "Security groups")),
|
||||
'Locale'
|
||||
);
|
||||
|
||||
$mainFields->removeByName('Bounced');
|
||||
$mainFields->removeByName('RememberLoginToken');
|
||||
$mainFields->removeByName('AutoLoginHash');
|
||||
@ -861,14 +854,14 @@ class Member extends DataObject {
|
||||
$mainFields->removeByName('Salt');
|
||||
$mainFields->removeByName('NumVisit');
|
||||
$mainFields->removeByName('LastVisited');
|
||||
$mainFields->removeByName('BlacklistedEmail');
|
||||
|
||||
$fields->removeByName('Subscriptions');
|
||||
$fields->removeByName('UnsubscribedRecords');
|
||||
// Groups relation will get us into logical conflicts because
|
||||
// Members are displayed within group edit form in SecurityAdmin
|
||||
$fields->removeByName('Groups');
|
||||
|
||||
$this->extend('updateCMSFields', $fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
@ -935,10 +928,6 @@ class Member extends DataObject {
|
||||
if($valid->valid()) {
|
||||
$this->AutoLoginHash = null;
|
||||
$this->write();
|
||||
|
||||
// Emails will be sent by Member::onBeforeWrite().
|
||||
|
||||
//$this->sendinfo('changePassword', array('CleartextPassword' => $password));
|
||||
}
|
||||
|
||||
return $valid;
|
||||
@ -1371,27 +1360,36 @@ class Member_Validator extends RequiredFields {
|
||||
*/
|
||||
function php($data) {
|
||||
$valid = parent::php($data);
|
||||
|
||||
$identifierField = Member::get_unique_identifier_field();
|
||||
|
||||
$SQL_identifierField = Convert::raw2sql($data[$identifierField]);
|
||||
$member = DataObject::get_one('Member', "\"$identifierField\" = '{$SQL_identifierField}'");
|
||||
|
||||
$member = DataObject::get_one('Member',
|
||||
"\"Email\" = '". Convert::raw2sql($data['Email']) ."'");
|
||||
|
||||
// if we are in a complex table field popup, use ctf[childID], else use
|
||||
// ID
|
||||
if(isset($_REQUEST['ctf']['childID']))
|
||||
// if we are in a complex table field popup, use ctf[childID], else use ID
|
||||
if(isset($_REQUEST['ctf']['childID'])) {
|
||||
$id = $_REQUEST['ctf']['childID'];
|
||||
elseif(isset($_REQUEST['ID']))
|
||||
} elseif(isset($_REQUEST['ID'])) {
|
||||
$id = $_REQUEST['ID'];
|
||||
else
|
||||
} else {
|
||||
$id = null;
|
||||
|
||||
if($id && is_object($member) && $member->ID != $id) {
|
||||
$emailField = $this->form->dataFieldByName('Email');
|
||||
$this->validationError($emailField->id(),
|
||||
_t('Member.VALIDATIONMEMBEREXISTS', "There already exists a member with this email"),
|
||||
"required");
|
||||
$valid = false;
|
||||
}
|
||||
|
||||
if($id && is_object($member) && $member->ID != $id) {
|
||||
$uniqueField = $this->form->dataFieldByName($identifierField);
|
||||
$this->validationError(
|
||||
$uniqueField->id(),
|
||||
sprintf(
|
||||
_t(
|
||||
'Member.VALIDATIONMEMBEREXISTS',
|
||||
'A member already exists with the same %s'
|
||||
),
|
||||
strtolower($identifierField)
|
||||
),
|
||||
'required'
|
||||
);
|
||||
$valid = false;
|
||||
}
|
||||
|
||||
// Execute the validators on the extensions
|
||||
if($this->extension_instances) {
|
||||
@ -1402,7 +1400,6 @@ class Member_Validator extends RequiredFields {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
@ -1429,9 +1426,7 @@ class Member_Validator extends RequiredFields {
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the static DB variables to add the supported encryption
|
||||
// algorithms to the PasswordEncryption Enum field
|
||||
Member::init_db_fields();
|
||||
|
||||
?>
|
||||
|
@ -114,5 +114,4 @@ class MemberAuthenticator extends Authenticator {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -36,6 +36,15 @@ class MemberLoginForm extends LoginForm {
|
||||
if(Director::fileExists($customCSS)) {
|
||||
Requirements::css($customCSS);
|
||||
}
|
||||
|
||||
// Focus on the email input when the page is loaded
|
||||
Requirements::customScript("
|
||||
(function($){
|
||||
$(document).ready(function() {
|
||||
$('#Email input').focus();
|
||||
});
|
||||
})(jQuery);
|
||||
");
|
||||
|
||||
if(isset($_REQUEST['BackURL'])) {
|
||||
$backURL = $_REQUEST['BackURL'];
|
||||
@ -50,8 +59,8 @@ class MemberLoginForm extends LoginForm {
|
||||
if(!$fields) {
|
||||
$fields = new FieldSet(
|
||||
new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this),
|
||||
new TextField("Email", _t('Member.EMAIL'), Session::get('SessionForms.MemberLoginForm.Email'), null, $this),
|
||||
new PasswordField("Password", _t('Member.PASSWORD'), null, $this)
|
||||
new TextField("Email", _t('Member.EMAIL', 'Email'), Session::get('SessionForms.MemberLoginForm.Email'), null, $this),
|
||||
new PasswordField("Password", _t('Member.PASSWORD', 'Password'))
|
||||
);
|
||||
if(Security::$autologin_enabled) {
|
||||
$fields->push(new CheckboxField(
|
||||
@ -231,6 +240,4 @@ class MemberLoginForm extends LoginForm {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
@ -12,9 +12,15 @@ class MemberPassword extends DataObject {
|
||||
);
|
||||
|
||||
static $has_one = array(
|
||||
'Member' => 'Member',
|
||||
'Member' => 'Member'
|
||||
);
|
||||
|
||||
static $has_many = array();
|
||||
|
||||
static $many_many = array();
|
||||
|
||||
static $belongs_many_many = array();
|
||||
|
||||
/**
|
||||
* Log a password change from the given member.
|
||||
* Call MemberPassword::log($this) from within Member whenever the password is changed.
|
||||
|
@ -22,6 +22,11 @@ class Permission extends DataObject {
|
||||
static $defaults = array(
|
||||
"Type" => 1
|
||||
);
|
||||
static $has_many = array();
|
||||
|
||||
static $many_many = array();
|
||||
|
||||
static $belongs_many_many = array();
|
||||
|
||||
/**
|
||||
* This is the value to use for the "Type" field if a permission should be
|
||||
@ -106,6 +111,16 @@ class Permission extends DataObject {
|
||||
}
|
||||
|
||||
|
||||
private static $cache_permissions = array();
|
||||
|
||||
/**
|
||||
* Flush the permission cache, for example if you have edited group membership or a permission record.
|
||||
* @todo Call this whenever Group_Members is added to or removed from
|
||||
*/
|
||||
public static function flush_permission_cache() {
|
||||
self::$cache_permissions = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the given member has the given permission
|
||||
* @param int|Member memberID The ID of the member to check. Leave blank for the current member.
|
||||
@ -124,6 +139,12 @@ class Permission extends DataObject {
|
||||
$perms_list = self::get_declared_permissions_list();
|
||||
$memberID = (is_object($member)) ? $member->ID : $member;
|
||||
|
||||
// Simple cache. This could be improved a lot by actually downloading all of the given user's permissions in one hit
|
||||
$codeStr = is_array($code) ? implode(',',$code) : $code;
|
||||
if($arg == 'any' && isset(self::$cache_permissions[$memberID][$codeStr])) {
|
||||
return self::$cache_permissions[$memberID][$codeStr];
|
||||
}
|
||||
|
||||
/*
|
||||
if(self::$declared_permissions && is_array($perms_list) && !in_array($code, $perms_list)) {
|
||||
user_error(
|
||||
@ -134,6 +155,8 @@ class Permission extends DataObject {
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
$groupList = self::groupList($memberID);
|
||||
if(!$groupList) return false;
|
||||
|
||||
@ -176,9 +199,11 @@ class Permission extends DataObject {
|
||||
$argClause
|
||||
)
|
||||
")->value();
|
||||
|
||||
if($permission)
|
||||
|
||||
if($permission) {
|
||||
self::$cache_permissions[$memberID][$codeStr] = $permission;
|
||||
return $permission;
|
||||
}
|
||||
|
||||
// Strict checking disabled?
|
||||
if(!self::$strict_checking || !$strict) {
|
||||
@ -190,11 +215,14 @@ class Permission extends DataObject {
|
||||
AND (\"Type\" = " . self::GRANT_PERMISSION . ")
|
||||
)
|
||||
")->value();
|
||||
|
||||
if(!$hasPermission) {
|
||||
self::$cache_permissions[$memberID][$codeStr] = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self::$cache_permissions[$memberID][$codeStr] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -544,6 +572,13 @@ class Permission extends DataObject {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onBeforeWrite() {
|
||||
parent::onBeforeWrite();
|
||||
|
||||
// Just in case we've altered someone's permissions
|
||||
Permission::flush_permission_cache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -612,5 +647,4 @@ class Permission_Group {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
@ -174,20 +174,12 @@ class Security extends Controller {
|
||||
|
||||
// Work out the right message to show
|
||||
if(Member::currentUserID()) {
|
||||
// user_error( 'PermFailure with member', E_USER_ERROR );
|
||||
|
||||
$message = isset($messageSet['alreadyLoggedIn'])
|
||||
? $messageSet['alreadyLoggedIn']
|
||||
: $messageSet['default'];
|
||||
|
||||
if($member = Member::currentUser())
|
||||
$member->logout();
|
||||
|
||||
$message = isset($messageSet['alreadyLoggedIn']) ? $messageSet['alreadyLoggedIn'] : $messageSet['default'];
|
||||
if($member = Member::currentUser()) {
|
||||
$member->logOut();
|
||||
}
|
||||
} else if(substr(Director::history(),0,15) == 'Security/logout') {
|
||||
$message = $messageSet['logInAgain']
|
||||
? $messageSet['logInAgain']
|
||||
: $messageSet['default'];
|
||||
|
||||
$message = $messageSet['logInAgain'] ? $messageSet['logInAgain'] : $messageSet['default'];
|
||||
} else {
|
||||
$message = $messageSet['default'];
|
||||
}
|
||||
@ -356,11 +348,7 @@ class Security extends Controller {
|
||||
Session::clear('Security.Message');
|
||||
|
||||
// custom processing
|
||||
if(SSViewer::hasTemplate("Security_login")) {
|
||||
return $customisedController->renderWith(array("Security_login", $this->stat('template_main')));
|
||||
} else {
|
||||
return $customisedController->renderWith($this->stat('template_main'));
|
||||
}
|
||||
return $customisedController->renderWith(array('Security_login', 'Security', $this->stat('template_main')));
|
||||
}
|
||||
|
||||
function basicauthlogin() {
|
||||
@ -398,7 +386,7 @@ class Security extends Controller {
|
||||
));
|
||||
|
||||
//Controller::$currentController = $controller;
|
||||
return $customisedController->renderWith($this->stat('template_main'));
|
||||
return $customisedController->renderWith(array('Security_lostpassword', 'Security', $this->stat('template_main')));
|
||||
}
|
||||
|
||||
|
||||
@ -412,7 +400,7 @@ class Security extends Controller {
|
||||
$this,
|
||||
'LostPasswordForm',
|
||||
new FieldSet(
|
||||
new EmailField('Email', _t('Member.EMAIL'))
|
||||
new EmailField('Email', _t('Member.EMAIL', 'Email'))
|
||||
),
|
||||
new FieldSet(
|
||||
new FormAction(
|
||||
@ -456,7 +444,7 @@ class Security extends Controller {
|
||||
));
|
||||
|
||||
//Controller::$currentController = $controller;
|
||||
return $customisedController->renderWith($this->stat('template_main'));
|
||||
return $customisedController->renderWith(array('Security_passwordsent', 'Security', $this->stat('template_main')));
|
||||
}
|
||||
|
||||
|
||||
@ -525,7 +513,7 @@ class Security extends Controller {
|
||||
}
|
||||
|
||||
//Controller::$currentController = $controller;
|
||||
return $customisedController->renderWith($this->stat('template_main'));
|
||||
return $customisedController->renderWith(array('Security_changepassword', 'Security', $this->stat('template_main')));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -982,5 +970,4 @@ class Security extends Controller {
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -12,4 +12,4 @@
|
||||
class HourlyTask extends ScheduledTask {
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
@ -12,4 +12,4 @@
|
||||
class MonthlyTask extends ScheduledTask {
|
||||
|
||||
}
|
||||
?>
|
||||
?>
|
@ -24,4 +24,4 @@
|
||||
abstract class ScheduledTask extends CliController {
|
||||
// this class exists as a logical extension
|
||||
}
|
||||
?>
|
||||
?>
|
@ -64,7 +64,7 @@
|
||||
<% end_control %>
|
||||
<% control Actions %>
|
||||
<td width="16" class="action<% if Default %> default<% end_if %>"><a class="$Class" href="$Link"><% if Icon %><img src="$Icon" alt="$Label" /><% else %>$Label<% end_if %></a></td>
|
||||
<% end_if %>
|
||||
<% end_control %>
|
||||
</tr>
|
||||
<% end_control %>
|
||||
<% else %>
|
||||
|
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<% control Items %>
|
||||
<url>
|
||||
<loc>$AbsoluteLink</loc>
|
||||
<lastmod>$LastEdited.Format(c)</lastmod>
|
||||
<% if ChangeFreq %><changefreq>$ChangeFreq</changefreq><% end_if %>
|
||||
<% if Priority %><priority>$Priority</priority><% end_if %>
|
||||
</url>
|
||||
<% end_control %>
|
||||
</urlset>
|
@ -1,4 +1,4 @@
|
||||
<div id="$id" class="$CSSClasses">
|
||||
<div id="$id" class="$CSSClasses" href="$CurrentLink">
|
||||
<% include TableListField_PageControls %>
|
||||
<table class="data">
|
||||
<thead>
|
||||
|
33
tests/ClassInfoTest.php
Normal file
33
tests/ClassInfoTest.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class ClassInfoTest extends SapphireTest {
|
||||
|
||||
function testSubclassesFor() {
|
||||
$this->assertEquals(
|
||||
ClassInfo::subclassesFor('ClassInfoTest_BaseClass'),
|
||||
array(
|
||||
0 => 'ClassInfoTest_BaseClass',
|
||||
'ClassInfoTest_ChildClass' => 'ClassInfoTest_ChildClass',
|
||||
'ClassInfoTest_GrandChildClass' => 'ClassInfoTest_GrandChildClass'
|
||||
),
|
||||
'ClassInfo::subclassesFor() returns only direct subclasses and doesnt include base class'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ClassInfoTest_BaseClass {
|
||||
|
||||
}
|
||||
|
||||
class ClassInfoTest_ChildClass extends ClassInfoTest_BaseClass {
|
||||
|
||||
}
|
||||
|
||||
class ClassInfoTest_GrandChildClass extends ClassInfoTest_ChildClass {
|
||||
|
||||
}
|
||||
?>
|
@ -7,6 +7,21 @@
|
||||
*/
|
||||
class HTTPTest extends SapphireTest {
|
||||
|
||||
/**
|
||||
* Tests {@link HTTP::getLinksIn()}
|
||||
*/
|
||||
public function testGetLinksIn() {
|
||||
$content = '
|
||||
<h2>My page</h2>
|
||||
<p>A boy went <a href="home/">home</a> to see his <span><a href="mother/">mother</a></span>.</p>
|
||||
';
|
||||
|
||||
$links = HTTP::getLinksIn($content);
|
||||
|
||||
$this->assertTrue(is_array($links));
|
||||
$this->assertTrue(count($links) == 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link HTTP::setGetVar()}
|
||||
*/
|
||||
|
@ -57,6 +57,7 @@ class RestfulServiceTest extends SapphireTest {
|
||||
class RestfulServiceTest_Controller extends Controller {
|
||||
public function index() {
|
||||
ContentNegotiator::disable();
|
||||
BasicAuth::disable();
|
||||
$request_count = count($_REQUEST);
|
||||
$get_count = count($_GET);
|
||||
$post_count = count($_POST);
|
||||
|
@ -23,10 +23,11 @@ class CsvBulkLoaderTest extends SapphireTest {
|
||||
$this->assertEquals(4, $results->Count(), 'Test correct count of imported data');
|
||||
|
||||
// Test that columns were correctly imported
|
||||
$obj = Dataobject::get_one("CsvBulkLoaderTest_Player", "\"FirstName\" = 'John'");
|
||||
$obj = DataObject::get_one("CsvBulkLoaderTest_Player", "\"FirstName\" = 'John'");
|
||||
$this->assertNotNull($obj);
|
||||
$this->assertEquals("He's a good guy", $obj->Biography);
|
||||
$this->assertEquals("1988-01-31", $obj->Birthday);
|
||||
$this->assertEquals("1", $obj->IsRegistered);
|
||||
|
||||
fclose($file);
|
||||
}
|
||||
@ -44,7 +45,8 @@ class CsvBulkLoaderTest extends SapphireTest {
|
||||
'FirstName',
|
||||
'Biography',
|
||||
null, // ignored column
|
||||
'Birthday'
|
||||
'Birthday',
|
||||
'IsRegistered'
|
||||
);
|
||||
$loader->hasHeaderRow = false;
|
||||
$results = $loader->load($filepath);
|
||||
@ -53,10 +55,15 @@ class CsvBulkLoaderTest extends SapphireTest {
|
||||
$this->assertEquals(4, $results->Count(), 'Test correct count of imported data');
|
||||
|
||||
// Test that columns were correctly imported
|
||||
$obj = Dataobject::get_one("CsvBulkLoaderTest_Player", "\"FirstName\" = 'John'");
|
||||
$obj = DataObject::get_one("CsvBulkLoaderTest_Player", "\"FirstName\" = 'John'");
|
||||
$this->assertNotNull($obj);
|
||||
$this->assertEquals("He's a good guy", $obj->Biography);
|
||||
$this->assertEquals("1988-01-31", $obj->Birthday);
|
||||
$this->assertEquals("1", $obj->IsRegistered);
|
||||
|
||||
$obj2 = DataObject::get_one('CsvBulkLoaderTest_Player', "FirstName = 'Jane'");
|
||||
$this->assertNotNull($obj2);
|
||||
$this->assertEquals('0', $obj2->IsRegistered);
|
||||
|
||||
fclose($file);
|
||||
}
|
||||
@ -133,7 +140,6 @@ class CsvBulkLoaderTest extends SapphireTest {
|
||||
$player = DataObject::get_by_id('CsvBulkLoaderTest_Player', 1);
|
||||
$this->assertEquals($player->FirstName, 'JohnUpdated', 'Test updating of existing records works');
|
||||
$this->assertEquals($player->Biography, 'He\'s a good guy', 'Test retaining of previous information on duplicate when overwriting with blank field');
|
||||
|
||||
}
|
||||
|
||||
function testLoadWithCustomImportMethods() {
|
||||
@ -142,12 +148,14 @@ class CsvBulkLoaderTest extends SapphireTest {
|
||||
$loader->columnMap = array(
|
||||
'FirstName' => '->importFirstName',
|
||||
'Biography' => 'Biography',
|
||||
'Birthday' => 'Birthday'
|
||||
'Birthday' => 'Birthday',
|
||||
'IsRegistered' => 'IsRegistered'
|
||||
);
|
||||
$results = $loader->load($filepath);
|
||||
$player = DataObject::get_by_id('CsvBulkLoaderTest_Player', 1);
|
||||
$this->assertEquals($player->FirstName, 'Customized John');
|
||||
$this->assertEquals($player->Biography, "He's a good guy");
|
||||
$this->assertEquals($player->IsRegistered, "1");
|
||||
}
|
||||
|
||||
protected function getLineCount(&$file) {
|
||||
@ -185,6 +193,7 @@ class CsvBulkLoaderTest_Player extends DataObject implements TestOnly {
|
||||
'Biography' => 'HTMLText',
|
||||
'Birthday' => 'Date',
|
||||
'ExternalIdentifier' => 'Varchar(255)', // used for uniqueness checks on passed property
|
||||
'IsRegistered' => 'Boolean'
|
||||
);
|
||||
|
||||
static $has_one = array(
|
||||
@ -215,4 +224,4 @@ class CsvBulkLoaderTest_PlayerContract extends DataObject implements TestOnly {
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -1,4 +1 @@
|
||||
"John","He's a good guy","ignored","31/01/1988"
|
||||
"Jane","She is awesome.\nSo awesome that she gets multiple rows and \"escaped\" strings in her biography","ignored","31/01/1982"
|
||||
"Jamie","Pretty old\, with an escaped comma","ignored","31/01/1882"
|
||||
"Järg","Unicode FTW","ignored","31/06/1982"
|
||||
John,He's a good guy,ignored,31/01/88,1
Jane,"She is awesome.\nSo awesome that she gets multiple rows and \escaped\"" strings in her biography""",ignored,31/01/82,0
Jamie,"Pretty old\, with an escaped comma",ignored,31/01/1882,1
Järg,Unicode FTW,ignored,31/06/1982,1
|
Can't render this file because it contains an unexpected character in line 2 and column 70.
|
@ -1,6 +1,2 @@
|
||||
"FirstName","Biography","Birthday"
|
||||
"John","He's a good guy","31/01/1988"
|
||||
"Jane","She is awesome.
|
||||
So awesome that she gets multiple rows and \"escaped\" strings in her biography","31/01/1982"
|
||||
"Jamie","Pretty old\, with an escaped comma","31/01/1882"
|
||||
"Järg","Unicode FTW","31/06/1982"
|
||||
FirstName,Biography,Birthday,IsRegistered
John,He's a good guy,31/01/88,1
Jane,"She is awesome.
|
||||
So awesome that she gets multiple rows and \escaped\"" strings in her biography""",31/01/82,0
Jamie,"Pretty old\, with an escaped comma",31/01/1882,1
Järg,Unicode FTW,31/06/1982,1
|
Can't render this file because it contains an unexpected character in line 4 and column 45.
|
44
tests/fieldtypes/DateTest.php
Normal file
44
tests/fieldtypes/DateTest.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class DateTest extends SapphireTest {
|
||||
|
||||
function testNiceDate() {
|
||||
/* Test the DD/MM/YYYY formatting of Date::Nice() */
|
||||
$cases = array(
|
||||
'4/3/03' => '04/03/2003',
|
||||
'04/03/03' => '04/03/2003',
|
||||
'4/3/03' => '04/03/2003',
|
||||
'4/03/03' => '04/03/2003',
|
||||
'4/3/2003' => '04/03/2003',
|
||||
'4-3-2003' => '04/03/2003',
|
||||
'2003-03-04' => '04/03/2003',
|
||||
'04/03/2003' => '04/03/2003',
|
||||
'04-03-2003' => '04/03/2003'
|
||||
);
|
||||
|
||||
foreach($cases as $original => $expected) {
|
||||
$date = new Date();
|
||||
$date->setValue($original);
|
||||
$this->assertEquals($expected, $date->Nice());
|
||||
}
|
||||
}
|
||||
|
||||
function testLongDate() {
|
||||
/* "24 May 2006" style formatting of Date::Long() */
|
||||
$cases = array(
|
||||
'2003-4-3' => '3 April 2003',
|
||||
'3/4/2003' => '3 April 2003',
|
||||
);
|
||||
|
||||
foreach($cases as $original => $expected) {
|
||||
$date = new Date();
|
||||
$date->setValue($original);
|
||||
$this->assertEquals($expected, $date->Long());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
39
tests/forms/DateFieldTest.php
Normal file
39
tests/forms/DateFieldTest.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class DateFieldTest extends SapphireTest {
|
||||
|
||||
function testDMYFormat() {
|
||||
/* We get YYYY-MM-DD format as the data value for DD/MM/YYYY input value */
|
||||
$dateField = new DateField('Date', 'Date', '04/03/2003');
|
||||
$this->assertEquals($dateField->dataValue(), '2003-03-04');
|
||||
|
||||
/* Even if value hasn't got leading 0's in it we still get the correct data value */
|
||||
$dateField2 = new DateField('Date', 'Date', '4/3/03');
|
||||
$this->assertEquals($dateField2->dataValue(), '03-3-4');
|
||||
}
|
||||
|
||||
function testYMDFormat() {
|
||||
/* We get YYYY-MM-DD format as the data value for YYYY-MM-DD input value */
|
||||
$dateField = new DateField('Date', 'Date', '2003/03/04');
|
||||
$this->assertEquals($dateField->dataValue(), '2003-03-04');
|
||||
|
||||
/* Even if input value hasn't got leading 0's in it we still get the correct data value */
|
||||
$dateField2 = new DateField('Date', 'Date', '2003/3/4');
|
||||
$this->assertEquals($dateField2->dataValue(), '2003-03-04');
|
||||
}
|
||||
|
||||
function testMDYFormat() {
|
||||
/* We get MM-DD-YYYY format as the data value for YYYY-MM-DD input value */
|
||||
$dateField = new DateField('Date', 'Date', '03/04/2003');
|
||||
$this->assertEquals($dateField->dataValue(), '2003-04-03');
|
||||
|
||||
/* Even if input value hasn't got leading 0's in it we still get the correct data value */
|
||||
$dateField2 = new DateField('Date', 'Date', '3/4/03');
|
||||
$this->assertEquals($dateField2->dataValue(), '03-4-3');
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
@ -13,7 +13,12 @@ class Widget extends DataObject {
|
||||
static $has_one = array(
|
||||
"Parent" => "WidgetArea",
|
||||
);
|
||||
|
||||
|
||||
static $has_many = array();
|
||||
static $many_many = array();
|
||||
static $belongs_many_many = array();
|
||||
static $defaults = array();
|
||||
|
||||
static $default_sort = "Sort";
|
||||
|
||||
static $title = "Widget Title";
|
||||
|
@ -5,12 +5,19 @@
|
||||
* @subpackage widgets
|
||||
*/
|
||||
class WidgetArea extends DataObject {
|
||||
|
||||
static $db = array();
|
||||
|
||||
static $has_one = array();
|
||||
|
||||
static $has_many = array(
|
||||
"Widgets" => "Widget"
|
||||
);
|
||||
|
||||
static $many_many = array();
|
||||
|
||||
static $belongs_many_many = array();
|
||||
|
||||
function forTemplate() {
|
||||
return $this->renderWith($this->class);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user