FIX DateField Calendar - make dates with day- and monthnames validate

In locales other than en_US, as a result of missing jQuery locale
files, the DatePicker defaulted to English whenever day and monthnames
were used, breaking validation. Needed to change official locale files
before adding, because Zend_Date and jQuery day/monthnames not matching
again breaks validation.

Removed hard setting the names to uppercase, breaking validation for
other locales

Changed order in convert_iso_to_jquery_format(), to prevent EEE(E)
settings from being overwritten

Added a check for existing locale files, and made DatePicker fallback
to ISO yyy-MM-dd if a missing locale file would otherwise break
validation.

Added documentation for the DateField
This commit is contained in:
martimiz 2012-09-25 18:05:13 +02:00 committed by Ingo Schommer
parent a4afea127e
commit 5186bada17
12 changed files with 428 additions and 22 deletions

View File

@ -0,0 +1,131 @@
# DateField
## Introduction
This `FormField` subclass lets you display an editable date, either in
a single text input field, or in three separate fields for day, month and year.
It also provides a calendar datepicker.
## Adding a DateField
The following example will add a simple DateField to your Page, allowing you to
enter a date manually.
:::php
class Page extends SiteTree {
static $db = array(
'MyDate' => 'Date',
);
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab(
'Root.Main',
$myDate = new DateField('MyDate', 'Enter a date')
);
return $fields;
}
}
## Custom Dateformat
You can define a custom dateformat for your Datefield based on [Zend_Date constants](http://framework.zend.com/manual/1.12/en/zend.date.constants.html).
:::php
// will display a date in the following format: 31-06-2012
DateField::create('MyDate')->setConfig('dateformat', 'dd-MM-yyyy');
## Min and Max Dates
Set the minimum and maximum allowed datevalues using the `min` and `max`
configuration settings (in ISO format or strtotime() compatible). Example:
:::php
DateField::create('MyDate')
->setConfig('min', '-7 days')
->setConfig('max', '2012-12-31')
## Separate Day/Month/Year Fields
The following setting will display your DateField as `three input fields` for
day, month and year separately. Any custom dateformat settings will be ignored.
HTML5 placeholders 'day', 'month' and 'year' are enabled by default.
:::php
DateField::create('MyDate')
->setConfig('dmyfields', true);
->setConfig('dmyseparator', '/') // set the separator
->setConfig('dmyplaceholders', 'true'); // enable HTML 5 Placeholders
## Calendar Field
The following setting will add a Calendar to a single DateField, using the
`jQuery UI DatePicker widget`
:::php
DateField::create('MyDate')->setConfig('showcalendar', true);
### 'Safe' Dateformats to Use with the Calendar
The jQuery DatePicker doesn't support every constant available for Zend_Date.
If you choose to use the calendar, the following constants should at least be safe:
Constant | xxxxx
-------- | -----
d | numeric day of the month (without leading zero)
dd | numeric day of the month (with leading zero)
EEE | dayname, abbreviated
EEEE | dayname
M | numeric month of the year (without leading zero)
MM | numeric month of the year (with leading zero)
MMM | monthname, abbreviated
MMMM | monthname
y | year (4 digits)
yy | year (2 digits)
yyyy | year (4 digits)
### Calendar localization issues
Unfortunately the day- and monthname values in Zend Date do not always match
those in the existing jQuery UI locale files, so constants like `EEE` or `MMM`,
for day and monthnames could break validation. To fix this we had to slightly
alter the jQuery locale files, situated in
*/framework/thirdparty/jquery-ui/datepicker/i18n/*, to match Zend_Date.
At this moment not all locale files may be present. If a locale file is
missing, the DatePicker calendar will fallback to 'yyyy-MM-dd' whenever day-
and/or monthnames are used. After saving, the correct format will be displayed.
## Contributing jQuery Locale Files
If you find the jQuery locale file for your chosen locale is missing, the
following section will explain how to create one. If you wish to contribute
your file to the SilverStripe core, please check out the guide on
['contributing code'](http://doc.silverstripe.org/framework/en/trunk/misc/contributing/code).
### 1. Get the Sourcefile
You can find a list of locale files for the jQuery UI DatePicker
[in the jQuery source code](https://github.com/jquery/jquery-ui/tree/master/ui/i18n).
### 2. Find your Zend Locale File
The Zend locale files are located in */framework/thirdparty/Zend/Locale/Data/*.
Find the one that has the information for your locale.
### 3. Find the Date Values
You're looking for the `Gregorian` date values for monthnames and daynames in
the Zend locale file. Edit the DatePicker locale File so your *full day- and
monthnames* and *short monthnames* match. For your *short daynames*, use the
first three characters of the full name. Note that Zend dates are `case
sensitive`!
### 4. Filename
Use the original jQuery UI filename 'jquery.ui.datepicker-xx.js', where xx
stands for the locale.

View File

@ -113,12 +113,26 @@ class DateField extends TextField {
}
public function FieldHolder($properties = array()) {
// TODO Replace with properly extensible view helper system
$d = DateField_View_JQuery::create($this);
$d->onBeforeRender();
if ($this->getConfig('showcalendar')) {
// TODO Replace with properly extensible view helper system
$d = DateField_View_JQuery::create($this);
if(!$d->regionalSettingsExist()) {
$dateformat = $this->getConfig('dateformat');
// if no localefile is present, the jQuery DatePicker
// month- and daynames will default to English, so the date
// will not pass Zend validatiobn. We provide a fallback
if (preg_match('/(MMM+)|(EEE+)/', $dateformat)) {
$this->setConfig('dateformat', $this->getConfig('datavalueformat'));
}
}
$d->onBeforeRender();
}
$html = parent::FieldHolder();
$html = $d->onAfterRender($html);
if(!empty($d)) {
$html = $d->onAfterRender($html);
}
return $html;
}
@ -199,9 +213,6 @@ class DateField extends TextField {
$this->value = null;
$this->valueObj = null;
} else {
// Quick fix for overzealous Zend validation, its case sensitive on month names (see #5990)
if(is_string($val)) $val = ucwords(strtolower($val));
if($this->getConfig('dmyfields')) {
// Setting in correct locale
if(is_array($val) && $this->validateArrayValue($val)) {
@ -480,6 +491,11 @@ class DateField_View_JQuery extends Object {
protected $field;
/*
* the current jQuery UI DatePicker locale file
*/
protected $jqueryLocaleFile = '';
/**
* @var array Maps values from {@link i18n::$all_locales()} to
* localizations existing in jQuery UI.
@ -488,7 +504,7 @@ class DateField_View_JQuery extends Object {
'en_GB' => 'en-GB',
'en_US' => 'en',
'en_NZ' => 'en-GB',
'fr_CH' => 'fr-CH',
'fr_CH' => 'fr',
'pt_BR' => 'pt-BR',
'sr_SR' => 'sr-SR',
'zh_CN' => 'zh-CN',
@ -509,7 +525,24 @@ class DateField_View_JQuery extends Object {
public function getField() {
return $this->field;
}
/**
* Check if jQuery UI locale settings exists for the current locale
* @return boolean
*/
function regionalSettingsExist() {
$lang = $this->getLang();
$localeFile = THIRDPARTY_DIR . "/jquery-ui/datepicker/i18n/jquery.ui.datepicker-{$lang}.js";
if (file_exists(Director::baseFolder() . '/' .$localeFile)){
$this->jqueryLocaleFile = $localeFile;
return true;
} else {
// file goes before internal en_US settings,
// but both will validate
return ($lang == 'en');
}
}
public function onBeforeRender() {
}
@ -524,16 +557,9 @@ class DateField_View_JQuery extends Object {
Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery-ui/jquery-ui.js');
// Include language files (if required)
$lang = $this->getLang();
if($lang != 'en') {
// TODO Check for existence of locale to avoid unnecessary 404s from the CDN
Requirements::javascript(
sprintf(
THIRDPARTY_DIR . '/jquery-ui/minified/i18n/jquery.ui.datepicker-%s.min.js',
// can be a mix between names (e.g. 'de') and combined locales (e.g. 'zh-TW')
$lang
));
}
if ($this->jqueryLocaleFile){
Requirements::javascript($this->jqueryLocaleFile);
}
Requirements::javascript(FRAMEWORK_DIR . "/javascript/DateField.js");
}
@ -578,12 +604,12 @@ class DateField_View_JQuery extends Object {
'/^d([^d])/' => 'd$1',
'/([^d])d$/' => '$1d',
'/dd/' => 'dd',
'/EEEE/' => 'DD',
'/EEE/' => 'D',
'/SS/' => '',
'/eee/' => 'd',
'/e/' => 'N',
'/D/' => '',
'/EEEE/' => 'DD',
'/EEE/' => 'D',
'/w/' => '',
// make single "M" lowercase
'/([^M])M([^M])/' => '$1m$2',

View File

@ -0,0 +1,25 @@
AUTHOR: Martine Bloem (http://www.balbuss.com)
**********************************************
jQuery UI DatePicker localization files for SilverStripe 3.0
------------------------------------------------------------
These files are adaptations of the official localization files that can be found here:
http://jquery-ui.googlecode.com/svn/trunk/ui/i18n/
Day- and monthnames have been changed to match the values Zend Date uses, to make
the following dateformats validate:
EEE: weekday short
EEEE: weekday
MMM: monthname short
MMMM: monthname
For locales for which no file exists (yet), the DatePicker will revert to a numeric
format, that will validate, and after being saved will be displayed in the
required format.
To create your own language fiel, download the original file from the URL above,
find the Zend Date locale file in framework/Zend/Locale/Data and make sure that
- monthNames, monthNamesShort and dayNames are equivalent to Zend (Gregorian) names
- dayNamesShort should be the first 3 characters of dayNames

View File

@ -0,0 +1,25 @@
/*
* Danish (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['da'] = {
closeText: 'Luk',
prevText: '<Forrige',
nextText: 'Næste>',
currentText: 'Idag',
monthNames: ['januar','februar','marts','april','maj','juni','juli','august','september','oktober','november','december'],
monthNamesShort: ['jan.','feb.','mar.','apr.','maj','jun.','jul.','aug.','sep.','okt.','nov.','dec.'],
dayNames: ['søndag','mandag','tirsdag','onsdag','torsdag','fredag','lørdag'],
dayNamesShort: ['søn','man','tir','ons','tor','fre','lør'],
dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'],
weekHeader: 'Uge',
dateFormat: 'dd-mm-yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['da']);
});

View File

@ -0,0 +1,25 @@
/*
* German (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['de'] = {
closeText: 'schließen',
prevText: '<zurück',
nextText: 'Vor>',
currentText: 'heute',
monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],
dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
dayNamesShort: ['Son','Mon','Die','Mit','Don','Fre','Sam'],
dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
weekHeader: 'Wo',
dateFormat: 'dd.mm.yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['de']);
});

View File

@ -0,0 +1,24 @@
/*
* English/UK (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['en-GB'] = {
closeText: 'Done',
prevText: 'Prev',
nextText: 'Next',
currentText: 'Today',
monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'],
weekHeader: 'Wk',
dateFormat: 'dd/mm/yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['en-GB']);
});

View File

@ -0,0 +1,25 @@
/*
* English (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['en'] = {
closeText: 'Done',
prevText: 'Prev',
nextText: 'Next',
currentText: 'Today',
monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'], // For formatting
monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'],
weekHeader: 'Wk',
dateFormat: 'mm/dd/yy',
firstDay: 0,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''
$.datepicker.setDefaults($.datepicker.regional['en']);
});

View File

@ -0,0 +1,27 @@
/*
* Spanish (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['es'] = {
closeText: 'Cerrar',
prevText: '<Ant',
nextText: 'Sig>',
currentText: 'Hoy',
monthNames: ['enero','febrero','marzo','abril','mayo','junio','julio','agosto','septiembre','octubre','noviembre','diciembre'],
monthNamesShort: ['ene','feb','mar','abr','may','jun','jul','ago','sep','oct','nov','dic'],
dayNames: ['domingo','lunes','martes','miércoles','jueves','viernes','sábado'],
dayNamesShort: ['dom','lun','mar','mié','juv','vie','sáb'],
dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'],
weekHeader: 'Sm',
dateFormat: 'dd/mm/yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['es']);
});

View File

@ -0,0 +1,24 @@
/*
* French (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['fr'] = {
closeText: 'Fermer',
prevText: '<Préc',
nextText: 'Suiv>',
currentText: 'Courant',
monthNames: ['janvier','février','mars','avril','mai','juin','juillet','août','septembre','octobre','novembre','décembre'],
monthNamesShort: ['janv.','févr.','mars','avr.','mai','juin','juil.','août','sept.','oct.','nov.','déc.'],
dayNames: ['dimanche','lundi','mardi','mercredi','jeudi','vendredi','samedi'],
dayNamesShort: ['dim','lun','mar','mer','jeu','ven','sam'],
dayNamesMin: ['Di','Lu','Ma','Me','Je','Ve','Sa'],
weekHeader: 'Sm',
dateFormat: 'dd/mm/yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['fr']);
});

View File

@ -0,0 +1,24 @@
/*
* Norwegian (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['no'] = {
closeText: 'Lukk',
prevText: '«Forrige',
nextText: 'Neste»',
currentText: 'I dag',
monthNames: ['januar','februar','mars','april','mai','juni','juli','august','september','oktober','november','desember'],
monthNamesShort: ['jan.','feb.','mar.','apr.','mai','juni','juli','aug.','sep.','okt.','nov.','des.'],
dayNames: ['søndag','mandag','tirsdag','onsdag','torsdag','fredag','lørdag'],
dayNamesShort: ['søn','man','tir','ons','tor','fre','lør'],
dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'],
weekHeader: 'Uke',
dateFormat: 'yy-mm-dd',
firstDay: 0,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['no']);
});

View File

@ -0,0 +1,26 @@
/*
* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['nl'] = {
closeText: 'Sluiten',
prevText: '←',
nextText: '→',
currentText: 'Vandaag',
monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni','juli', 'augustus', 'september', 'oktober', 'november', 'december'],
monthNamesShort: ['jan.', 'feb.', 'mrt.', 'apr.', 'mei.', 'jun.','jul.', 'aug.', 'sep.', 'okt.', 'nov.', 'dec.'],
dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],
dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'],
dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],
weekHeader: 'Wk',
dateFormat: 'dd-mm-yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['nl']);
});

View File

@ -0,0 +1,24 @@
/*
* Swedish (UTF-8) initialisation for the jQuery UI date picker plugin.
* Adapted to match the Zend Data localization for SilverStripe CMS
* See: README
*/
jQuery(function($){
$.datepicker.regional['sv'] = {
closeText: 'Stäng',
prevText: '«Förra',
nextText: 'Nästa»',
currentText: 'Idag',
monthNames: ['januari','februari','mars','april','maj','juni','juli','augusti','september','oktober','november','december'],
monthNamesShort: ['jan','feb','mar','apr','maj','jun','jul','aug','sep','okt','nov','dec'],
dayNames: ['söndag','måndag','tisdag','onsdag','torsdag','fredag','lördag'],
dayNamesShort: ['sön','mån','tis','ons','tor','fre','lör'],
dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö'],
weekHeader: 'Ve',
dateFormat: 'yy-mm-dd',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['sv']);
});