mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #6766 from open-sausages/pulls/4.0/6626-remove-jquery-datepicker
HTML5 Date Fields
This commit is contained in:
commit
32578e07d6
@ -4,7 +4,11 @@ summary: How to format and use the DateField class.
|
|||||||
# DateField
|
# DateField
|
||||||
|
|
||||||
This `FormField` subclass lets you display an editable date, in a single text input field.
|
This `FormField` subclass lets you display an editable date, in a single text input field.
|
||||||
It also provides a calendar date picker.
|
It implements the [HTML5 input date type](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date)
|
||||||
|
(with `type=date`). In supported browsers, this will cause a localised date picker to appear for users.
|
||||||
|
HTML5 date fields present and save ISO 8601 date formats (`y-MM-dd`),
|
||||||
|
since the browser takes care of converting to/from a localised presentation.
|
||||||
|
Browsers without support receive an `<input type=text>` based polyfill.
|
||||||
|
|
||||||
The following example will add a simple DateField to your Page, allowing you to enter a date manually.
|
The following example will add a simple DateField to your Page, allowing you to enter a date manually.
|
||||||
|
|
||||||
@ -34,65 +38,28 @@ The following example will add a simple DateField to your Page, allowing you to
|
|||||||
## Custom Date Format
|
## Custom Date Format
|
||||||
|
|
||||||
A custom date format for a [api:DateField] can be provided through `setDateFormat`.
|
A custom date format for a [api:DateField] can be provided through `setDateFormat`.
|
||||||
|
This is only necessary if you want to opt-out of the built-in browser localisation via `type=date`.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
// will display a date in the following format: 31-06-2012
|
// will display a date in the following format: 31/06/2012
|
||||||
DateField::create('MyDate')->setDateFormat('dd-MM-yyyy');
|
DateField::create('MyDate')
|
||||||
|
->setHTML5(false)
|
||||||
|
->setDateFormat('dd/MM/yyyy');
|
||||||
|
|
||||||
<div class="info" markdown="1">
|
<div class="info" markdown="1">
|
||||||
The formats are based on [CLDR format](http://userguide.icu-project.org/formatparse/datetime).
|
The formats are based on [ICU format](http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details).
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
## Min and Max Dates
|
## Min and Max Dates
|
||||||
|
|
||||||
Sets the minimum and maximum allowed date values using the `min` and `max` configuration settings (in ISO format or
|
Sets the minimum and maximum allowed date values using the `min` and `max` configuration settings (in ISO format or
|
||||||
strtotime()).
|
`strtotime()`).
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
DateField::create('MyDate')
|
DateField::create('MyDate')
|
||||||
->setMinDate('-7 days')
|
->setMinDate('-7 days')
|
||||||
->setMaxDate'2012-12-31')
|
->setMaxDate('2012-12-31')
|
||||||
|
|
||||||
## Separate Day / Month / Year Fields
|
|
||||||
|
|
||||||
To display separate input fields for day, month and year separately you can use the `SeparatedDateField` subclass`.
|
|
||||||
HTML5 placeholders 'day', 'month' and 'year' are enabled by default.
|
|
||||||
|
|
||||||
:::php
|
|
||||||
SeparatedDateField::create('MyDate');
|
|
||||||
|
|
||||||
<div class="alert" markdown="1">
|
|
||||||
Any custom date format settings will be ignored.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
## Calendar Picker
|
|
||||||
|
|
||||||
The following setting will add a Calendar to a single DateField, using the jQuery UI DatePicker widget.
|
|
||||||
|
|
||||||
:::php
|
|
||||||
DateField::create('MyDate')
|
|
||||||
->setShowCalendar(true);
|
|
||||||
|
|
||||||
The jQuery date picker will support most custom locale formats (if left as default).
|
|
||||||
If setting an explicit date format via setDateFormat() then the below table of supported
|
|
||||||
characters should be used.
|
|
||||||
|
|
||||||
It is recommended to use numeric format, as `MMM` or `MMMM` month names may not always pass validation.
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
## Formatting Hints
|
## Formatting Hints
|
||||||
|
|
||||||
|
@ -71,18 +71,24 @@ and default alignment of paragraphs and tables to browsers.
|
|||||||
|
|
||||||
### Date and time formats
|
### Date and time formats
|
||||||
|
|
||||||
Formats can be set globally in the i18n class. These settings are currently only picked up by the CMS, you'll need
|
Formats can be set globally in the i18n class.
|
||||||
to write your own logic for any frontend output.
|
You can use these settings for your own view logic.
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
Config::inst()->update('i18n', 'date_format', 'dd.MM.YYYY');
|
Config::inst()->update('i18n', 'date_format', 'dd.MM.YYYY');
|
||||||
Config::inst()->update('i18n', 'time_format', 'HH:mm');
|
Config::inst()->update('i18n', 'time_format', 'HH:mm');
|
||||||
|
|
||||||
Most localization routines in SilverStripe use the [Zend_Date API](http://framework.zend.com/manual/1.12/en/zend.date.overview.html).
|
Localization in SilverStripe uses PHP's [intl extension](http://php.net/intl).
|
||||||
This means all formats are defined in
|
Formats for it's [IntlDateFormatter](http://php.net/manual/en/class.intldateformatter.php)
|
||||||
[ISO date format](http://framework.zend.com/manual/1.12/en/zend.date.constants.html),
|
are defined in [ICU format](http://www.icu-project.org/apiref/icu4c/classSimpleDateFormat.html#details),
|
||||||
not PHP's built-in [date()](http://nz.php.net/manual/en/function.date.php).
|
not PHP's built-in [date()](http://nz.php.net/manual/en/function.date.php).
|
||||||
|
|
||||||
|
These settings are not used for CMS presentation.
|
||||||
|
Users can choose their own locale, which determines the date format
|
||||||
|
that gets presented to them. Currently this is a mix of PHP defaults (for readonly `DateField` and `TimeField`),
|
||||||
|
browser defaults (for `DateField` on browsers supporting HTML5), and [Moment.JS](http://momentjs.com/)
|
||||||
|
client-side logic (for `DateField` polyfills and other readonly dates and times).
|
||||||
|
|
||||||
### Language Names
|
### Language Names
|
||||||
|
|
||||||
SilverStripe comes with a built-in list of common languages, listed by locale and region.
|
SilverStripe comes with a built-in list of common languages, listed by locale and region.
|
||||||
@ -126,32 +132,17 @@ Please refer to [W3C: Introduction to IDN and IRI](http://www.w3.org/Internation
|
|||||||
|
|
||||||
### i18n in Form Fields
|
### i18n in Form Fields
|
||||||
|
|
||||||
Date- and time related form fields support i18n ([api:DateField], [api:TimeField], [api:DatetimeField]).
|
Date and time related form fields are automatically localised ([api:DateField], [api:TimeField], [api:DatetimeField]).
|
||||||
|
Since they use HTML5 `type=date` and `type=time` fields by default, these fields will present dates
|
||||||
|
in a localised format chosen by the browser and operating system.
|
||||||
|
|
||||||
:::php
|
Fields can be forced to use a certain locale and date/time format by calling `setHTML5(false)`,
|
||||||
i18n::set_locale('ca_AD');
|
followed by `setLocale()` or `setDateFormat()`/`setTimeFormat()`.
|
||||||
$field = new DateField(); // will automatically set date format defaults for 'ca_AD'
|
|
||||||
$field->setLocale('de_DE'); // will not update the date formats
|
|
||||||
$field->setConfig('dateformat', 'dd. MMMM YYYY'); // sets typical 'de_DE' date format, shows as "23. Juni 1982"
|
|
||||||
|
|
||||||
Defaults can be applied globally for all field instances through the `DateField.default_config`
|
|
||||||
and `TimeField.default_config` [configuration arrays](/developer_guides/configuration).
|
|
||||||
If no 'locale' default is set on the field, [api:i18n::get_locale()] will be used.
|
|
||||||
|
|
||||||
**Important:** Form fields in the CMS are automatically configured according to the profile settings for the logged-in user (`Member->Locale`, `Member->DateFormat` and `Member->TimeFormat`). This means that in most cases,
|
|
||||||
fields created through [api:DataObject::getCMSFields()] will get their i18n settings from a specific member
|
|
||||||
|
|
||||||
The [api:DateField] API can be enhanced by JavaScript, and comes with
|
|
||||||
[jQuery UI datepicker](http://jqueryui.com/demos/datepicker/) capabilities built-in.
|
|
||||||
The field tries to translate the date formats and locales into a format compatible with jQuery UI
|
|
||||||
(see [api:DateField_View_JQuery::$locale_map_] and [api:DateField_View_JQuery::convert_iso_to_jquery_format()]).
|
|
||||||
|
|
||||||
:::php
|
:::php
|
||||||
$field = new DateField();
|
$field = new DateField();
|
||||||
$field->setLocale('de_AT'); // set Austrian/German locale
|
$field->setLocale('de_AT'); // set Austrian/German locale, defaulting format to dd.MM.y
|
||||||
$field->setConfig('showcalendar', true);
|
$field->setDateFormat('d.M.y'); // set a more specific date format (single digit day/month)
|
||||||
$field->setConfig('jslocale', 'de'); // jQuery UI only has a generic German localization
|
|
||||||
$field->setConfig('dateformat', 'dd. MMMM YYYY'); // will be transformed to 'dd. MM yy' for jQuery
|
|
||||||
|
|
||||||
## Translating text
|
## Translating text
|
||||||
|
|
||||||
|
@ -398,6 +398,19 @@ In templates this can also be invoked as below:
|
|||||||
<%t MyObject.PLURALS 'An item|{count} items' count=$Count %>
|
<%t MyObject.PLURALS 'An item|{count} items' count=$Count %>
|
||||||
|
|
||||||
|
|
||||||
|
#### Removed Member.DateFormat and Member.TimeFormat database settings
|
||||||
|
|
||||||
|
We're using [native HTML5 date and time pickers](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date)
|
||||||
|
in `DateField` and `TimeField` now ([discussion](https://github.com/silverstripe/silverstripe-framework/issues/6626)),
|
||||||
|
where the browser localises the output based on the browser/system preferences.
|
||||||
|
In this context it no longer makes sense to give users control over their own
|
||||||
|
date and time formats in their CMS profile.
|
||||||
|
Consequently, we've also removed `MemberDatetimeOptionsetField`.
|
||||||
|
|
||||||
|
`Member->getDateFormat()` and `Member->getTimeFormat()` still exist, and default to
|
||||||
|
the [IntlDateFormatter defaults](http://php.net/manual/en/class.intldateformatter.php) for the selected locale.
|
||||||
|
|
||||||
|
|
||||||
#### New asset storage mechanism
|
#### New asset storage mechanism
|
||||||
|
|
||||||
File system has been abstracted into an abstract interface. By default, the out of the box filesystem
|
File system has been abstracted into an abstract interface. By default, the out of the box filesystem
|
||||||
@ -1495,19 +1508,25 @@ New `DatetimeField` methods replace `getConfig()` / `setConfig()`:
|
|||||||
|
|
||||||
New `DateField` methods replace `getConfig()` / `setConfig()`:
|
New `DateField` methods replace `getConfig()` / `setConfig()`:
|
||||||
|
|
||||||
* `getShowCalendar()` / `setShowCalendar()`
|
* `getDateFormat()` / `setDateFormat()`
|
||||||
* `getDateFormat()` / `setShowCalendar()`
|
|
||||||
* `getMinDate()` / `setMinDate()`
|
* `getMinDate()` / `setMinDate()`
|
||||||
* `getMaxDate()` / `setMaxDate()`
|
* `getMaxDate()` / `setMaxDate()`
|
||||||
* `getPlaceholders()` / `setPlaceholders()`
|
|
||||||
* `getClientLocale` / `setClientLocale`
|
|
||||||
* `getLocale()` / `setLocale()`
|
* `getLocale()` / `setLocale()`
|
||||||
* option `dmyfields` is now superceded with an `SeparatedDateField` class
|
|
||||||
|
The `DateField` has changed behavior:
|
||||||
|
|
||||||
|
* `DateField` no longer provides a jQuery UI date picker (`showcalendar` option),
|
||||||
|
and uses [HTML5 date pickers](https://www.wufoo.com/html5/types/4-date.html) by default instead.
|
||||||
|
* `DateField` provides an optional polyfill for
|
||||||
|
[browsers without HTML5 date picker support](http://caniuse.com/#feat=input-datetime)
|
||||||
|
* The `dmyfields` option has been replced with native HTML5 behaviour (as one single `<input type=date>`).
|
||||||
|
* `getClientLocale` / `setClientLocale` have been removed (handled by `DateField->locale` and browser settings)
|
||||||
|
|
||||||
New `TimeField` methods replace `getConfig()` / `setConfig()`
|
New `TimeField` methods replace `getConfig()` / `setConfig()`
|
||||||
|
|
||||||
* `getTimeFormat()` / `setTimeFormat()`
|
* `getTimeFormat()` / `setTimeFormat()`
|
||||||
* `getLocale()` / `setLocale()`
|
* `getLocale()` / `setLocale()`
|
||||||
|
* `getClientConfig()` has been removed (in favour of `setHTML5()`)
|
||||||
|
|
||||||
#### <a name="overview-template-removed"></a>Template and Form Removed API
|
#### <a name="overview-template-removed"></a>Template and Form Removed API
|
||||||
|
|
||||||
@ -1550,6 +1569,8 @@ New `TimeField` methods replace `getConfig()` / `setConfig()`
|
|||||||
* `get_source_file_comments()`
|
* `get_source_file_comments()`
|
||||||
* `getOption`
|
* `getOption`
|
||||||
* `setOption`
|
* `setOption`
|
||||||
|
* Removed `MemberDatetimeOptionsetField` (no replacement)
|
||||||
|
* Removed `DateField_View_JQuery` (replaced with native HTML5 support in `DateField`)
|
||||||
|
|
||||||
### <a name="overview-i18n"></a>i18n API
|
### <a name="overview-i18n"></a>i18n API
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\Forms;
|
|||||||
use IntlDateFormatter;
|
use IntlDateFormatter;
|
||||||
use SilverStripe\i18n\i18n;
|
use SilverStripe\i18n\i18n;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use SilverStripe\ORM\FieldType\DBDate;
|
||||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,13 +86,6 @@ class DateField extends TextField
|
|||||||
*/
|
*/
|
||||||
protected $dateLength = null;
|
protected $dateLength = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Set whether to show placeholders
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
protected $placeholders = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override locale for client side.
|
* Override locale for client side.
|
||||||
*
|
*
|
||||||
@ -122,25 +116,27 @@ class DateField extends TextField
|
|||||||
protected $rawValue = null;
|
protected $rawValue = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if calendar should be shown on the frontend
|
* Use HTML5-based input fields (and force ISO 8601 date formats).
|
||||||
*
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $html5 = true;
|
||||||
|
|
||||||
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function getShowCalendar()
|
public function getHTML5()
|
||||||
{
|
{
|
||||||
return $this->showCalendar;
|
return $this->html5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set if calendar should be shown on the frontend.
|
* @param boolean $bool
|
||||||
* @internal WARNING: Experimental and volatile API.
|
|
||||||
*
|
|
||||||
* @param bool $show
|
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setShowCalendar($show)
|
public function setHTML5($bool)
|
||||||
{
|
{
|
||||||
$this->showCalendar = $show;
|
$this->html5 = $bool;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,12 +160,8 @@ class DateField extends TextField
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get length of the date format to use. One of:
|
* Get length of the date format to use.
|
||||||
*
|
* Only applicable with {@link setHTML5(false)}.
|
||||||
* - IntlDateFormatter::SHORT
|
|
||||||
* - IntlDateFormatter::MEDIUM
|
|
||||||
* - IntlDateFormatter::LONG
|
|
||||||
* - IntlDateFormatter::FULL
|
|
||||||
*
|
*
|
||||||
* @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants
|
* @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants
|
||||||
*
|
*
|
||||||
@ -192,6 +184,11 @@ class DateField extends TextField
|
|||||||
*/
|
*/
|
||||||
public function getDateFormat()
|
public function getDateFormat()
|
||||||
{
|
{
|
||||||
|
if ($this->getHTML5()) {
|
||||||
|
// Browsers expect ISO 8601 dates, localisation is handled on the client
|
||||||
|
$this->setDateFormat(DBDate::ISO_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->dateFormat) {
|
if ($this->dateFormat) {
|
||||||
return $this->dateFormat;
|
return $this->dateFormat;
|
||||||
}
|
}
|
||||||
@ -202,6 +199,7 @@ class DateField extends TextField
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set date format in CLDR standard format.
|
* Set date format in CLDR standard format.
|
||||||
|
* Only applicable with {@link setHTML5(false)}.
|
||||||
*
|
*
|
||||||
* @see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Field-Symbol-Table
|
* @see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Field-Symbol-Table
|
||||||
* @param string $format
|
* @param string $format
|
||||||
@ -216,18 +214,40 @@ class DateField extends TextField
|
|||||||
/**
|
/**
|
||||||
* Get date formatter with the standard locale / date format
|
* Get date formatter with the standard locale / date format
|
||||||
*
|
*
|
||||||
|
* @throws \LogicException
|
||||||
* @return IntlDateFormatter
|
* @return IntlDateFormatter
|
||||||
*/
|
*/
|
||||||
protected function getFormatter()
|
protected function getFormatter()
|
||||||
{
|
{
|
||||||
|
if ($this->getHTML5() && $this->dateFormat && $this->dateFormat !== DBDate::ISO_DATE) {
|
||||||
|
throw new \LogicException(
|
||||||
|
'Please opt-out of HTML5 processing of ISO 8601 dates via setHTML5(false) if using setDateFormat()'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getHTML5() && $this->dateLength) {
|
||||||
|
throw new \LogicException(
|
||||||
|
'Please opt-out of HTML5 processing of ISO 8601 dates via setHTML5(false) if using setDateLength()'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getHTML5() && $this->locale) {
|
||||||
|
throw new \LogicException(
|
||||||
|
'Please opt-out of HTML5 processing of ISO 8601 dates via setHTML5(false) if using setLocale()'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$formatter = IntlDateFormatter::create(
|
$formatter = IntlDateFormatter::create(
|
||||||
$this->getLocale(),
|
$this->getLocale(),
|
||||||
$this->getDateLength(),
|
$this->getDateLength(),
|
||||||
IntlDateFormatter::NONE
|
IntlDateFormatter::NONE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($this->getHTML5()) {
|
||||||
|
// Browsers expect ISO 8601 dates, localisation is handled on the client
|
||||||
|
$formatter->setPattern(DBDate::ISO_DATE);
|
||||||
|
} elseif ($this->dateFormat) {
|
||||||
// Don't invoke getDateFormat() directly to avoid infinite loop
|
// Don't invoke getDateFormat() directly to avoid infinite loop
|
||||||
if ($this->dateFormat) {
|
|
||||||
$ok = $formatter->setPattern($this->dateFormat);
|
$ok = $formatter->setPattern($this->dateFormat);
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
throw new InvalidArgumentException("Invalid date format {$this->dateFormat}");
|
throw new InvalidArgumentException("Invalid date format {$this->dateFormat}");
|
||||||
@ -243,59 +263,28 @@ class DateField extends TextField
|
|||||||
*/
|
*/
|
||||||
protected function getISO8601Formatter()
|
protected function getISO8601Formatter()
|
||||||
{
|
{
|
||||||
|
$locale = i18n::config()->uninherited('default_locale');
|
||||||
$formatter = IntlDateFormatter::create(
|
$formatter = IntlDateFormatter::create(
|
||||||
i18n::config()->uninherited('default_locale'),
|
i18n::config()->uninherited('default_locale'),
|
||||||
IntlDateFormatter::MEDIUM,
|
IntlDateFormatter::MEDIUM,
|
||||||
IntlDateFormatter::NONE
|
IntlDateFormatter::NONE
|
||||||
);
|
);
|
||||||
$formatter->setLenient(false);
|
$formatter->setLenient(false);
|
||||||
// CLDR iso8601 date.
|
// CLDR ISO 8601 date.
|
||||||
$formatter->setPattern('y-MM-dd');
|
$formatter->setPattern(DBDate::ISO_DATE);
|
||||||
return $formatter;
|
return $formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function FieldHolder($properties = array())
|
|
||||||
{
|
|
||||||
return $this->renderWithClientView(function () use ($properties) {
|
|
||||||
return parent::FieldHolder($properties);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function SmallFieldHolder($properties = array())
|
|
||||||
{
|
|
||||||
return $this->renderWithClientView(function () use ($properties) {
|
|
||||||
return parent::SmallFieldHolder($properties);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate field with client view enabled
|
|
||||||
*
|
|
||||||
* @param callable $callback
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function renderWithClientView($callback)
|
|
||||||
{
|
|
||||||
$clientView = null;
|
|
||||||
if ($this->getShowCalendar()) {
|
|
||||||
$clientView = $this->getClientView();
|
|
||||||
$clientView->onBeforeRender();
|
|
||||||
}
|
|
||||||
$html = $callback();
|
|
||||||
if ($clientView) {
|
|
||||||
$html = $clientView->onAfterRender($html);
|
|
||||||
}
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAttributes()
|
public function getAttributes()
|
||||||
{
|
{
|
||||||
$attributes = parent::getAttributes();
|
$attributes = parent::getAttributes();
|
||||||
|
|
||||||
// Merge with client config
|
$attributes['lang'] = i18n::convert_rfc1766($this->getLocale());
|
||||||
$config = $this->getClientConfig();
|
|
||||||
foreach ($config as $key => $value) {
|
if ($this->getHTML5()) {
|
||||||
$attributes["data-{$key}"] = $value;
|
$attributes['type'] = 'date';
|
||||||
|
$attributes['min'] = $this->getMinDate();
|
||||||
|
$attributes['max'] = $this->getMaxDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $attributes;
|
return $attributes;
|
||||||
@ -434,7 +423,9 @@ class DateField extends TextField
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caution: Will not update the 'dateformat' config value.
|
* Determines the presented/processed format based on locale defaults,
|
||||||
|
* instead of explicitly setting {@link setDateFormat()}.
|
||||||
|
* Only applicable with {@link setHTML5(false)}.
|
||||||
*
|
*
|
||||||
* @param string $locale
|
* @param string $locale
|
||||||
* @return $this
|
* @return $this
|
||||||
@ -445,29 +436,6 @@ class DateField extends TextField
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get locale code for client-side. Will default to getLocale() if omitted.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getClientLocale()
|
|
||||||
{
|
|
||||||
if ($this->clientLocale) {
|
|
||||||
return $this->clientLocale;
|
|
||||||
}
|
|
||||||
return $this->getLocale();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $clientLocale
|
|
||||||
* @return DateField
|
|
||||||
*/
|
|
||||||
public function setClientLocale($clientLocale)
|
|
||||||
{
|
|
||||||
$this->clientLocale = $clientLocale;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSchemaValidation()
|
public function getSchemaValidation()
|
||||||
{
|
{
|
||||||
$rules = parent::getSchemaValidation();
|
$rules = parent::getSchemaValidation();
|
||||||
@ -475,28 +443,6 @@ class DateField extends TextField
|
|||||||
return $rules;
|
return $rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If placeholders are shown
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function getPlaceholders()
|
|
||||||
{
|
|
||||||
return $this->placeholders;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set if placeholders are shown
|
|
||||||
*
|
|
||||||
* @param bool $placeholders
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setPlaceholders($placeholders)
|
|
||||||
{
|
|
||||||
$this->placeholders = $placeholders;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -533,35 +479,6 @@ class DateField extends TextField
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get client data properties for this field
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getClientConfig()
|
|
||||||
{
|
|
||||||
$view = $this->getClientView();
|
|
||||||
$config = [
|
|
||||||
'showcalendar' => $this->getShowCalendar() ? 'true' : null,
|
|
||||||
'date-format' => $view->getDateFormat(), // https://api.jqueryui.com/datepicker/#option-dateFormat
|
|
||||||
'locale' => $view->getLocale(),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Format min/maxDate in format expected by jquery datepicker
|
|
||||||
$min = $this->getMinDate();
|
|
||||||
if ($min) {
|
|
||||||
// https://api.jqueryui.com/datepicker/#option-minDate
|
|
||||||
$config['min-date'] = $this->iso8601ToLocalised($min);
|
|
||||||
}
|
|
||||||
$max = $this->getMaxDate();
|
|
||||||
if ($max) {
|
|
||||||
// https://api.jqueryui.com/datepicker/#option-maxDate
|
|
||||||
$config['max-date'] = $this->iso8601ToLocalised($max);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert date localised in the current locale to ISO 8601 date
|
* Convert date localised in the current locale to ISO 8601 date
|
||||||
*
|
*
|
||||||
@ -627,12 +544,4 @@ class DateField extends TextField
|
|||||||
}
|
}
|
||||||
return $formatter->format($timestamp);
|
return $formatter->format($timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return DateField_View_JQuery
|
|
||||||
*/
|
|
||||||
protected function getClientView()
|
|
||||||
{
|
|
||||||
return DateField_View_JQuery::create($this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,197 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace SilverStripe\Forms;
|
|
||||||
|
|
||||||
use InvalidArgumentException;
|
|
||||||
use SilverStripe\Core\Config\Config;
|
|
||||||
use SilverStripe\Core\Config\Configurable;
|
|
||||||
use SilverStripe\Core\Injector\Injectable;
|
|
||||||
use SilverStripe\i18n\i18n;
|
|
||||||
use SilverStripe\View\Requirements;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preliminary API to separate optional view properties
|
|
||||||
* like calendar popups from the actual datefield logic.
|
|
||||||
*
|
|
||||||
* Caution: This API is highly volatile, and might change without prior deprecation.
|
|
||||||
*/
|
|
||||||
class DateField_View_JQuery
|
|
||||||
{
|
|
||||||
use Injectable;
|
|
||||||
use Configurable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var DateField
|
|
||||||
*/
|
|
||||||
protected $field;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Maps values from {@link i18n::$all_locales} to
|
|
||||||
* localizations existing in jQuery UI.
|
|
||||||
*/
|
|
||||||
private static $locale_map = array(
|
|
||||||
'en_GB' => 'en-GB',
|
|
||||||
'en_US' => 'en',
|
|
||||||
'en_NZ' => 'en-GB',
|
|
||||||
'fr_CH' => 'fr',
|
|
||||||
'pt_BR' => 'pt-BR',
|
|
||||||
'sr_SR' => 'sr-SR',
|
|
||||||
'zh_CN' => 'zh-CN',
|
|
||||||
'zh_HK' => 'zh-HK',
|
|
||||||
'zh_TW' => 'zh-TW',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param DateField $field
|
|
||||||
*/
|
|
||||||
public function __construct($field)
|
|
||||||
{
|
|
||||||
$this->field = $field;
|
|
||||||
|
|
||||||
// Health check
|
|
||||||
if (!$this->localePath('en')) {
|
|
||||||
throw new InvalidArgumentException("Missing jquery config");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return DateField
|
|
||||||
*/
|
|
||||||
public function getField()
|
|
||||||
{
|
|
||||||
return $this->field;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get path to localisation file for a given locale, if it exists
|
|
||||||
*
|
|
||||||
* @param string $lang
|
|
||||||
* @return string Relative path to file, or null if it isn't available
|
|
||||||
*/
|
|
||||||
protected function localePath($lang)
|
|
||||||
{
|
|
||||||
$path = ADMIN_THIRDPARTY_DIR . "/jquery-ui/datepicker/i18n/jquery.ui.datepicker-{$lang}.js";
|
|
||||||
if (file_exists(BASE_PATH . '/' . $path)) {
|
|
||||||
return $path;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onBeforeRender()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param String $html
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function onAfterRender($html)
|
|
||||||
{
|
|
||||||
if ($this->getField()->getShowCalendar()) {
|
|
||||||
// Load config for this locale if available
|
|
||||||
$locale = $this->getLocale();
|
|
||||||
$localeFile = $this->localePath($locale);
|
|
||||||
if ($localeFile) {
|
|
||||||
Requirements::javascript($localeFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines which language to use for jQuery UI, which
|
|
||||||
* can be different from the value set in i18n.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getLocale()
|
|
||||||
{
|
|
||||||
$locale = $this->getField()->getClientLocale();
|
|
||||||
|
|
||||||
// Check standard mappings
|
|
||||||
$map = Config::inst()->get(__CLASS__, 'locale_map');
|
|
||||||
if (array_key_exists($locale, $map)) {
|
|
||||||
return $map[$locale];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall back to default lang (meaning "en_US" turns into "en")
|
|
||||||
return i18n::getData()->langFromLocale($locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert iso to jquery UI date format.
|
|
||||||
* Needs to be consistent with Zend formatting, otherwise validation will fail.
|
|
||||||
* Removes all time settings like hour/minute/second from the format.
|
|
||||||
* See http://docs.jquery.com/UI/Datepicker/formatDate
|
|
||||||
* From http://userguide.icu-project.org/formatparse/datetime
|
|
||||||
*
|
|
||||||
* @param string $format
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function convert_iso_to_jquery_format($format)
|
|
||||||
{
|
|
||||||
$convert = array(
|
|
||||||
'/([^d])d([^d])/' => '$1d$2',
|
|
||||||
'/^d([^d])/' => 'd$1',
|
|
||||||
'/([^d])d$/' => '$1d',
|
|
||||||
'/dd/' => 'dd',
|
|
||||||
'/SS/' => '',
|
|
||||||
'/eee/' => 'd',
|
|
||||||
'/e/' => 'N',
|
|
||||||
'/D/' => '',
|
|
||||||
'/EEEE/' => 'DD',
|
|
||||||
'/EEE/' => 'D',
|
|
||||||
'/w/' => '',
|
|
||||||
// make single "M" lowercase
|
|
||||||
'/([^M])M([^M])/' => '$1m$2',
|
|
||||||
// make single "M" at start of line lowercase
|
|
||||||
'/^M([^M])/' => 'm$1',
|
|
||||||
// make single "M" at end of line lowercase
|
|
||||||
'/([^M])M$/' => '$1m',
|
|
||||||
// match exactly three capital Ms not preceeded or followed by an M
|
|
||||||
'/(?<!M)MMM(?!M)/' => 'M',
|
|
||||||
// match exactly two capital Ms not preceeded or followed by an M
|
|
||||||
'/(?<!M)MM(?!M)/' => 'mm',
|
|
||||||
// match four capital Ms (maximum allowed)
|
|
||||||
'/MMMM/' => 'MM',
|
|
||||||
'/l/' => '',
|
|
||||||
'/YYYY/' => 'yy',
|
|
||||||
'/yyyy/' => 'yy',
|
|
||||||
// See http://open.silverstripe.org/ticket/7669
|
|
||||||
'/y{1,3}/' => 'yy',
|
|
||||||
'/a/' => '',
|
|
||||||
'/B/' => '',
|
|
||||||
'/hh/' => '',
|
|
||||||
'/h/' => '',
|
|
||||||
'/([^H])H([^H])/' => '',
|
|
||||||
'/^H([^H])/' => '',
|
|
||||||
'/([^H])H$/' => '',
|
|
||||||
'/HH/' => '',
|
|
||||||
// '/mm/' => '',
|
|
||||||
'/ss/' => '',
|
|
||||||
'/zzzz/' => '',
|
|
||||||
'/I/' => '',
|
|
||||||
'/ZZZZ/' => '',
|
|
||||||
'/Z/' => '',
|
|
||||||
'/z/' => '',
|
|
||||||
'/X/' => '',
|
|
||||||
'/r/' => '',
|
|
||||||
'/U/' => '',
|
|
||||||
);
|
|
||||||
$patterns = array_keys($convert);
|
|
||||||
$replacements = array_values($convert);
|
|
||||||
|
|
||||||
return preg_replace($patterns, $replacements, $format);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get client date format
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getDateFormat()
|
|
||||||
{
|
|
||||||
return static::convert_iso_to_jquery_format($this->getField()->getDateFormat());
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,6 +13,10 @@ use SilverStripe\i18n\i18n;
|
|||||||
* If you want to save into {@link Date} or {@link Time} columns,
|
* If you want to save into {@link Date} or {@link Time} columns,
|
||||||
* please instanciate the fields separately.
|
* please instanciate the fields separately.
|
||||||
*
|
*
|
||||||
|
* This field does not implement the <input type="datetime-local"> HTML5 field,
|
||||||
|
* but can use date and time HTML5 inputs separately (through {@link DateField->setHTML5()}
|
||||||
|
* and {@link TimeField->setHTML5()}.
|
||||||
|
*
|
||||||
* # Configuration
|
* # Configuration
|
||||||
*
|
*
|
||||||
* Individual options are configured either on the DatetimeField, or on individual
|
* Individual options are configured either on the DatetimeField, or on individual
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace SilverStripe\Forms;
|
|
||||||
|
|
||||||
use SilverStripe\i18n\i18n;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Date field with separate inputs for d/m/y
|
|
||||||
*/
|
|
||||||
class SeparatedDateField extends DateField
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $separator = '/';
|
|
||||||
|
|
||||||
public function Field($properties = array())
|
|
||||||
{
|
|
||||||
// Three separate fields for day, month and year
|
|
||||||
$valArr = $this->iso8601ToArray($this->dataValue());
|
|
||||||
$fieldDay = NumericField::create($this->name . '[day]', false, $valArr ? $valArr['day'] : null)
|
|
||||||
->addExtraClass('day')
|
|
||||||
->setHTML5(true)
|
|
||||||
->setMaxLength(2);
|
|
||||||
$fieldMonth = NumericField::create($this->name . '[month]', false, $valArr ? $valArr['month'] : null)
|
|
||||||
->addExtraClass('month')
|
|
||||||
->setHTML5(true)
|
|
||||||
->setMaxLength(2);
|
|
||||||
$fieldYear = NumericField::create($this->name . '[year]', false, $valArr ? $valArr['year'] : null)
|
|
||||||
->addExtraClass('year')
|
|
||||||
->setHTML5(true)
|
|
||||||
->setMaxLength(4);
|
|
||||||
|
|
||||||
// Set placeholders
|
|
||||||
if ($this->getPlaceholders()) {
|
|
||||||
$fieldDay->setAttribute('placeholder', _t(__CLASS__ . '.DAY', 'Day'));
|
|
||||||
$fieldMonth->setAttribute('placeholder', _t(__CLASS__ . '.MONTH', 'Month'));
|
|
||||||
$fieldYear->setAttribute('placeholder', _t(__CLASS__ . '.YEAR', 'Year'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$format = $this->getDateFormat();
|
|
||||||
$validFormat = (
|
|
||||||
stripos($format, 'd') !== false
|
|
||||||
&& stripos($format, 'm') !== false
|
|
||||||
&& stripos($format, 'y') !== false
|
|
||||||
);
|
|
||||||
if (!$validFormat) {
|
|
||||||
throw new \InvalidArgumentException(
|
|
||||||
'Invalid date format for field ordering: ' . $format
|
|
||||||
. '. Requires "d", "m", and "y" values to determine order'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$fields = array();
|
|
||||||
$fields[stripos($format, 'd')] = $fieldDay->Field();
|
|
||||||
$fields[stripos($format, 'm')] = $fieldMonth->Field();
|
|
||||||
$fields[stripos($format, 'y')] = $fieldYear->Field();
|
|
||||||
ksort($fields);
|
|
||||||
|
|
||||||
|
|
||||||
// Join all fields
|
|
||||||
$sep = ' <span class="separator">' . $this->getSeparator() . '</span> ';
|
|
||||||
return implode($sep, $fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param $string
|
|
||||||
* @return self
|
|
||||||
*/
|
|
||||||
public function setSeparator($separator)
|
|
||||||
{
|
|
||||||
$this->separator = $separator;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getSeparator()
|
|
||||||
{
|
|
||||||
return $this->separator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert array to timestamp
|
|
||||||
*
|
|
||||||
* @param array $value
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function arrayToISO8601($value)
|
|
||||||
{
|
|
||||||
if ($this->isEmptyArray($value)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure all keys are specified
|
|
||||||
if (!isset($value['month']) || !isset($value['day']) || !isset($value['year'])) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure valid range
|
|
||||||
if (!checkdate($value['month'], $value['day'], $value['year'])) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: Set formatter to strict for array input
|
|
||||||
$formatter = $this->getISO8601Formatter();
|
|
||||||
$timestamp = mktime(0, 0, 0, $value['month'], $value['day'], $value['year']);
|
|
||||||
if ($timestamp === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return $formatter->format($timestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert iso 8601 date to array (day / month / year)
|
|
||||||
*
|
|
||||||
* @param string $date
|
|
||||||
* @return array|null Array form, or null if not valid
|
|
||||||
*/
|
|
||||||
public function iso8601ToArray($date)
|
|
||||||
{
|
|
||||||
if (!$date) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$formatter = $this->getISO8601Formatter();
|
|
||||||
$timestamp = $formatter->parse($date);
|
|
||||||
if ($timestamp === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format time manually into an array
|
|
||||||
return [
|
|
||||||
'day' => date('j', $timestamp),
|
|
||||||
'month' => date('n', $timestamp),
|
|
||||||
'year' => date('Y', $timestamp),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign value posted from form submission
|
|
||||||
*
|
|
||||||
* @param mixed $value
|
|
||||||
* @param mixed $data
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setSubmittedValue($value, $data = null)
|
|
||||||
{
|
|
||||||
// Filter out empty arrays
|
|
||||||
if ($this->isEmptyArray($value)) {
|
|
||||||
$value = null;
|
|
||||||
}
|
|
||||||
$this->rawValue = $value;
|
|
||||||
|
|
||||||
// Null case
|
|
||||||
if (!$value || !is_array($value)) {
|
|
||||||
$this->value = null;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse
|
|
||||||
$this->value = $this->arrayToISO8601($value);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if this array is empty
|
|
||||||
*
|
|
||||||
* @param $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isEmptyArray($value)
|
|
||||||
{
|
|
||||||
return is_array($value) && !array_filter($value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ use IntlDateFormatter;
|
|||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use SilverStripe\i18n\i18n;
|
use SilverStripe\i18n\i18n;
|
||||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||||
|
use SilverStripe\ORM\FieldType\DBTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form field to display editable time values in an <input type="text"> field.
|
* Form field to display editable time values in an <input type="text"> field.
|
||||||
@ -57,6 +58,31 @@ class TimeField extends TextField
|
|||||||
*/
|
*/
|
||||||
protected $timezone = null;
|
protected $timezone = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use HTML5-based input fields (and force ISO 8601 time formats).
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $html5 = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getHTML5()
|
||||||
|
{
|
||||||
|
return $this->html5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param boolean $bool
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setHTML5($bool)
|
||||||
|
{
|
||||||
|
$this->html5 = $bool;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get time format in CLDR standard format
|
* Get time format in CLDR standard format
|
||||||
*
|
*
|
||||||
@ -67,6 +93,11 @@ class TimeField extends TextField
|
|||||||
*/
|
*/
|
||||||
public function getTimeFormat()
|
public function getTimeFormat()
|
||||||
{
|
{
|
||||||
|
if ($this->getHTML5()) {
|
||||||
|
// Browsers expect ISO 8601 times, localisation is handled on the client
|
||||||
|
$this->setTimeFormat(DBTime::ISO_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->timeFormat) {
|
if ($this->timeFormat) {
|
||||||
return $this->timeFormat;
|
return $this->timeFormat;
|
||||||
}
|
}
|
||||||
@ -77,6 +108,7 @@ class TimeField extends TextField
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set time format in CLDR standard format.
|
* Set time format in CLDR standard format.
|
||||||
|
* Only applicable with {@link setHTML5(false)}.
|
||||||
*
|
*
|
||||||
* @see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Field-Symbol-Table
|
* @see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Field-Symbol-Table
|
||||||
* @param string $format
|
* @param string $format
|
||||||
@ -108,12 +140,8 @@ class TimeField extends TextField
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get length of the time format to use. One of:
|
* Get length of the time format to use.
|
||||||
*
|
* Only applicable with {@link setHTML5(false)}.
|
||||||
* - IntlDateFormatter::SHORT E.g. '6:31 PM'
|
|
||||||
* - IntlDateFormatter::MEDIUM E.g. '6:30:48 PM'
|
|
||||||
* - IntlDateFormatter::LONG E.g. '6:32:09 PM NZDT'
|
|
||||||
* - IntlDateFormatter::FULL E.g. '6:32:24 PM New Zealand Daylight Time'
|
|
||||||
*
|
*
|
||||||
* @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants
|
* @see http://php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants
|
||||||
*
|
*
|
||||||
@ -133,6 +161,24 @@ class TimeField extends TextField
|
|||||||
*/
|
*/
|
||||||
protected function getFormatter()
|
protected function getFormatter()
|
||||||
{
|
{
|
||||||
|
if ($this->getHTML5() && $this->timeFormat && $this->timeFormat !== DBTime::ISO_TIME) {
|
||||||
|
throw new \LogicException(
|
||||||
|
'Please opt-out of HTML5 processing of ISO 8601 times via setHTML5(false) if using setTimeFormat()'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getHTML5() && $this->timeLength) {
|
||||||
|
throw new \LogicException(
|
||||||
|
'Please opt-out of HTML5 processing of ISO 8601 times via setHTML5(false) if using setTimeLength()'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getHTML5() && $this->locale) {
|
||||||
|
throw new \LogicException(
|
||||||
|
'Please opt-out of HTML5 processing of ISO 8601 times via setHTML5(false) if using setLocale()'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$formatter = IntlDateFormatter::create(
|
$formatter = IntlDateFormatter::create(
|
||||||
$this->getLocale(),
|
$this->getLocale(),
|
||||||
IntlDateFormatter::NONE,
|
IntlDateFormatter::NONE,
|
||||||
@ -140,8 +186,11 @@ class TimeField extends TextField
|
|||||||
$this->getTimezone()
|
$this->getTimezone()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Don't invoke getDateFormat() directly to avoid infinite loop
|
if ($this->getHTML5()) {
|
||||||
if ($this->timeFormat) {
|
// Browsers expect ISO 8601 times, localisation is handled on the client
|
||||||
|
$formatter->setPattern(DBTime::ISO_TIME);
|
||||||
|
// Don't invoke getTimeFormat() directly to avoid infinite loop
|
||||||
|
} elseif ($this->timeFormat) {
|
||||||
$ok = $formatter->setPattern($this->timeFormat);
|
$ok = $formatter->setPattern($this->timeFormat);
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
throw new InvalidArgumentException("Invalid time format {$this->timeFormat}");
|
throw new InvalidArgumentException("Invalid time format {$this->timeFormat}");
|
||||||
@ -164,35 +213,22 @@ class TimeField extends TextField
|
|||||||
date_default_timezone_get() // Default to server timezone
|
date_default_timezone_get() // Default to server timezone
|
||||||
);
|
);
|
||||||
$formatter->setLenient(false);
|
$formatter->setLenient(false);
|
||||||
// CLDR iso8601 time
|
|
||||||
// Note we omit timezone from this format, and we assume server TZ always.
|
// Note we omit timezone from this format, and we assume server TZ always.
|
||||||
$formatter->setPattern('HH:mm:ss');
|
$formatter->setPattern(DBTime::ISO_TIME);
|
||||||
|
|
||||||
return $formatter;
|
return $formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAttribute($name)
|
public function getAttributes()
|
||||||
{
|
{
|
||||||
$attributes = parent::getAttributes();
|
$attributes = parent::getAttributes();
|
||||||
|
|
||||||
// Merge with client config
|
if ($this->getHTML5()) {
|
||||||
$config = $this->getClientConfig();
|
$attributes['type'] = 'time';
|
||||||
foreach ($config as $key => $value) {
|
|
||||||
$attributes["data-{$key}"] = $value;
|
|
||||||
}
|
|
||||||
return $attributes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return $attributes;
|
||||||
* Get client config options for this field
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getClientConfig()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
// @todo - Support javascript time picker
|
|
||||||
'timeformat' => $this->getTimeFormat(),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Type()
|
public function Type()
|
||||||
@ -302,6 +338,10 @@ class TimeField extends TextField
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Determines the presented/processed format based on locale defaults,
|
||||||
|
* instead of explicitly setting {@link setTimeFormat()}.
|
||||||
|
* Only applicable with {@link setHTML5(false)}.
|
||||||
|
*
|
||||||
* @param string $locale
|
* @param string $locale
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
@ -337,9 +377,19 @@ class TimeField extends TextField
|
|||||||
$fromFormatter = $this->getFormatter();
|
$fromFormatter = $this->getFormatter();
|
||||||
$toFormatter = $this->getISO8601Formatter();
|
$toFormatter = $this->getISO8601Formatter();
|
||||||
$timestamp = $fromFormatter->parse($time);
|
$timestamp = $fromFormatter->parse($time);
|
||||||
|
|
||||||
|
// Try to parse time without seconds, since that's a valid HTML5 submission format
|
||||||
|
// See https://html.spec.whatwg.org/multipage/infrastructure.html#times
|
||||||
|
if ($timestamp === false && $this->getHTML5()) {
|
||||||
|
$fromFormatter->setPattern('HH:mm');
|
||||||
|
$timestamp = $fromFormatter->parse($time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If timestamp still can't be detected, we've got an invalid time
|
||||||
if ($timestamp === false) {
|
if ($timestamp === false) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $toFormatter->format($timestamp);
|
return $toFormatter->format($timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,17 +512,7 @@ class DBDate extends DBField
|
|||||||
public function scaffoldFormField($title = null, $params = null)
|
public function scaffoldFormField($title = null, $params = null)
|
||||||
{
|
{
|
||||||
$field = DateField::create($this->name, $title);
|
$field = DateField::create($this->name, $title);
|
||||||
$format = $field->getDateFormat();
|
$field->setHTML5(true);
|
||||||
|
|
||||||
// Show formatting hints for better usability
|
|
||||||
$now = DBDatetime::now()->Format($format);
|
|
||||||
$field->setDescription(_t(
|
|
||||||
'FormField.EXAMPLE',
|
|
||||||
'e.g. {format}',
|
|
||||||
'Example format',
|
|
||||||
[ 'format' => $now ]
|
|
||||||
));
|
|
||||||
$field->setAttribute('placeholder', $format);
|
|
||||||
|
|
||||||
return $field;
|
return $field;
|
||||||
}
|
}
|
||||||
|
@ -141,19 +141,7 @@ class DBTime extends DBField
|
|||||||
|
|
||||||
public function scaffoldFormField($title = null, $params = null)
|
public function scaffoldFormField($title = null, $params = null)
|
||||||
{
|
{
|
||||||
$field = TimeField::create($this->name, $title);
|
return TimeField::create($this->name, $title);
|
||||||
$format = $field->getTimeFormat();
|
|
||||||
|
|
||||||
// Show formatting hints for better usability
|
|
||||||
$now = DBDatetime::now()->Format($format);
|
|
||||||
$field->setDescription(_t(
|
|
||||||
'FormField.Example',
|
|
||||||
'e.g. {format}',
|
|
||||||
'Example format',
|
|
||||||
[ 'format' => $now ]
|
|
||||||
));
|
|
||||||
$field->setAttribute('placeholder', $format);
|
|
||||||
return $field;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,7 +19,6 @@ use SilverStripe\Forms\DropdownField;
|
|||||||
use SilverStripe\Forms\FieldList;
|
use SilverStripe\Forms\FieldList;
|
||||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorConfig;
|
use SilverStripe\Forms\HTMLEditor\HTMLEditorConfig;
|
||||||
use SilverStripe\Forms\ListboxField;
|
use SilverStripe\Forms\ListboxField;
|
||||||
use SilverStripe\Forms\MemberDatetimeOptionsetField;
|
|
||||||
use SilverStripe\i18n\i18n;
|
use SilverStripe\i18n\i18n;
|
||||||
use SilverStripe\MSSQL\MSSQLDatabase;
|
use SilverStripe\MSSQL\MSSQLDatabase;
|
||||||
use SilverStripe\ORM\ArrayList;
|
use SilverStripe\ORM\ArrayList;
|
||||||
@ -81,9 +80,6 @@ class Member extends DataObject implements TemplateGlobalProvider
|
|||||||
'Locale' => 'Varchar(6)',
|
'Locale' => 'Varchar(6)',
|
||||||
// handled in registerFailedLogin(), only used if $lock_out_after_incorrect_logins is set
|
// handled in registerFailedLogin(), only used if $lock_out_after_incorrect_logins is set
|
||||||
'FailedLoginCount' => 'Int',
|
'FailedLoginCount' => 'Int',
|
||||||
// In ISO format
|
|
||||||
'DateFormat' => 'Varchar(30)',
|
|
||||||
'TimeFormat' => 'Varchar(30)',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
private static $belongs_many_many = array(
|
private static $belongs_many_many = array(
|
||||||
@ -1315,20 +1311,24 @@ class Member extends DataObject implements TemplateGlobalProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the default getter for DateFormat so the
|
* Return the date format based on the user's chosen locale,
|
||||||
* default format for the user's locale is used
|
* falling back to the default format defined by the {@link i18n.get_locale()} setting.
|
||||||
* if the user has not defined their own.
|
|
||||||
*
|
*
|
||||||
* @return string ISO date format
|
* @return string ISO date format
|
||||||
*/
|
*/
|
||||||
public function getDateFormat()
|
public function getDateFormat()
|
||||||
{
|
{
|
||||||
$format = $this->getField('DateFormat');
|
$formatter = new IntlDateFormatter(
|
||||||
if ($format) {
|
$this->getLocale(),
|
||||||
|
IntlDateFormatter::MEDIUM,
|
||||||
|
IntlDateFormatter::NONE
|
||||||
|
);
|
||||||
|
$format = $formatter->getPattern();
|
||||||
|
|
||||||
|
$this->extend('updateDateFormat', $format);
|
||||||
|
|
||||||
return $format;
|
return $format;
|
||||||
}
|
}
|
||||||
return $this->getDefaultDateFormat();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user locale
|
* Get user locale
|
||||||
@ -1343,19 +1343,23 @@ class Member extends DataObject implements TemplateGlobalProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the default getter for TimeFormat so the
|
* Return the time format based on the user's chosen locale,
|
||||||
* default format for the user's locale is used
|
* falling back to the default format defined by the {@link i18n.get_locale()} setting.
|
||||||
* if the user has not defined their own.
|
|
||||||
*
|
*
|
||||||
* @return string ISO date format
|
* @return string ISO date format
|
||||||
*/
|
*/
|
||||||
public function getTimeFormat()
|
public function getTimeFormat()
|
||||||
{
|
{
|
||||||
$timeFormat = $this->getField('TimeFormat');
|
$formatter = new IntlDateFormatter(
|
||||||
if ($timeFormat) {
|
$this->getLocale(),
|
||||||
return $timeFormat;
|
IntlDateFormatter::NONE,
|
||||||
}
|
IntlDateFormatter::MEDIUM
|
||||||
return $this->getDefaultTimeFormat();
|
);
|
||||||
|
$format = $formatter->getPattern();
|
||||||
|
|
||||||
|
$this->extend('updateTimeFormat', $format);
|
||||||
|
|
||||||
|
return $format;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------//
|
//---------------------------------------------------------------------//
|
||||||
@ -1592,112 +1596,11 @@ class Member extends DataObject implements TemplateGlobalProvider
|
|||||||
if ($permissionsTab) {
|
if ($permissionsTab) {
|
||||||
$permissionsTab->addExtraClass('readonly');
|
$permissionsTab->addExtraClass('readonly');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Date format selecter
|
|
||||||
$mainFields->push(
|
|
||||||
$dateFormatField = new MemberDatetimeOptionsetField(
|
|
||||||
'DateFormat',
|
|
||||||
$this->fieldLabel('DateFormat'),
|
|
||||||
$this->getDateFormats()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$formatClass = get_class($dateFormatField);
|
|
||||||
$dateFormatField->setValue($this->DateFormat);
|
|
||||||
$dateTemplate = SSViewer::get_templates_by_class($formatClass, '_description_date', $formatClass);
|
|
||||||
$dateFormatField->setDescriptionTemplate($dateTemplate);
|
|
||||||
|
|
||||||
// Time format selector
|
|
||||||
$mainFields->push(
|
|
||||||
$timeFormatField = new MemberDatetimeOptionsetField(
|
|
||||||
'TimeFormat',
|
|
||||||
$this->fieldLabel('TimeFormat'),
|
|
||||||
$this->getTimeFormats()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$timeFormatField->setValue($this->TimeFormat);
|
|
||||||
$timeTemplate = SSViewer::get_templates_by_class($formatClass, '_description_time', $formatClass);
|
|
||||||
$timeFormatField->setDescriptionTemplate($timeTemplate);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return parent::getCMSFields();
|
return parent::getCMSFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get list of date formats with example values
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getDateFormats()
|
|
||||||
{
|
|
||||||
$defaultDateFormat = $this->getDefaultDateFormat();
|
|
||||||
$formats = [
|
|
||||||
'MMM d, y' => null,
|
|
||||||
'yyyy/MM/dd' => null,
|
|
||||||
'MM/dd/y' => null,
|
|
||||||
'dd/MM/y' => null,
|
|
||||||
];
|
|
||||||
unset($formats[$defaultDateFormat]);
|
|
||||||
$formats[$defaultDateFormat] = null;
|
|
||||||
// Fill in each format with example
|
|
||||||
foreach (array_keys($formats) as $format) {
|
|
||||||
$formats[$format] = DBDatetime::now()->Format($format);
|
|
||||||
}
|
|
||||||
// Mark default format
|
|
||||||
$formats[$defaultDateFormat] .= sprintf(' (%s)', _t('Member.DefaultDateTime', 'default'));
|
|
||||||
return $formats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getDefaultDateFormat()
|
|
||||||
{
|
|
||||||
$formatter = new IntlDateFormatter(
|
|
||||||
$this->getLocale(),
|
|
||||||
IntlDateFormatter::MEDIUM,
|
|
||||||
IntlDateFormatter::NONE
|
|
||||||
);
|
|
||||||
return $formatter->getPattern();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getDefaultTimeFormat()
|
|
||||||
{
|
|
||||||
$formatter = new IntlDateFormatter(
|
|
||||||
$this->getLocale(),
|
|
||||||
IntlDateFormatter::NONE,
|
|
||||||
IntlDateFormatter::MEDIUM
|
|
||||||
);
|
|
||||||
$defaultTimeFormat = $formatter->getPattern();
|
|
||||||
return $defaultTimeFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get list of date formats with example values
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getTimeFormats()
|
|
||||||
{
|
|
||||||
$defaultTimeFormat = $this->getDefaultTimeFormat();
|
|
||||||
$formats = [
|
|
||||||
'h:mm a' => null,
|
|
||||||
'H:mm' => null,
|
|
||||||
];
|
|
||||||
unset($formats[$defaultTimeFormat]);
|
|
||||||
$formats[$defaultTimeFormat] = null;
|
|
||||||
// Fill in each format with example
|
|
||||||
foreach (array_keys($formats) as $format) {
|
|
||||||
$formats[$format] = DBDatetime::now()->Format($format);
|
|
||||||
}
|
|
||||||
// Mark default format
|
|
||||||
$formats[$defaultTimeFormat] .= sprintf(' (%s)', _t('Member.DefaultDateTime', 'default'));
|
|
||||||
return $formats;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bool $includerelations Indicate if the labels returned include relation fields
|
* @param bool $includerelations Indicate if the labels returned include relation fields
|
||||||
* @return array
|
* @return array
|
||||||
@ -1714,8 +1617,6 @@ class Member extends DataObject implements TemplateGlobalProvider
|
|||||||
$labels['PasswordExpiry'] = _t('Member.db_PasswordExpiry', 'Password Expiry Date', 'Password expiry date');
|
$labels['PasswordExpiry'] = _t('Member.db_PasswordExpiry', 'Password Expiry Date', 'Password expiry date');
|
||||||
$labels['LockedOutUntil'] = _t('Member.db_LockedOutUntil', 'Locked out until', 'Security related date');
|
$labels['LockedOutUntil'] = _t('Member.db_LockedOutUntil', 'Locked out until', 'Security related date');
|
||||||
$labels['Locale'] = _t('Member.db_Locale', 'Interface Locale');
|
$labels['Locale'] = _t('Member.db_Locale', 'Interface Locale');
|
||||||
$labels['DateFormat'] = _t('Member.DATEFORMAT', 'Date format');
|
|
||||||
$labels['TimeFormat'] = _t('Member.TIMEFORMAT', 'Time format');
|
|
||||||
if ($includerelations) {
|
if ($includerelations) {
|
||||||
$labels['Groups'] = _t(
|
$labels['Groups'] = _t(
|
||||||
'Member.belongs_many_many_Groups',
|
'Member.belongs_many_many_Groups',
|
||||||
|
@ -85,12 +85,20 @@ class i18n implements TemplateGlobalProvider
|
|||||||
private static $default_locale = 'en_US';
|
private static $default_locale = 'en_US';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* System-wide date format. Will be overruled for CMS UI display
|
||||||
|
* by the format defaults inferred from the browser as well as
|
||||||
|
* any user-specific locale preferences.
|
||||||
|
*
|
||||||
* @config
|
* @config
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private static $date_format = 'yyyy-MM-dd';
|
private static $date_format = 'yyyy-MM-dd';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* System-wide time format. Will be overruled for CMS UI display
|
||||||
|
* by the format defaults inferred from the browser as well as
|
||||||
|
* any user-specific locale preferences.
|
||||||
|
*
|
||||||
* @config
|
* @config
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace SilverStripe\Forms\Tests;
|
namespace SilverStripe\Forms\Tests;
|
||||||
|
|
||||||
|
use IntlDateFormatter;
|
||||||
use SilverStripe\Dev\SapphireTest;
|
use SilverStripe\Dev\SapphireTest;
|
||||||
use SilverStripe\Forms\DateField;
|
use SilverStripe\Forms\DateField;
|
||||||
use SilverStripe\Forms\SeparatedDateField;
|
|
||||||
use SilverStripe\Forms\RequiredFields;
|
use SilverStripe\Forms\RequiredFields;
|
||||||
use SilverStripe\i18n\i18n;
|
use SilverStripe\i18n\i18n;
|
||||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||||
@ -105,21 +105,11 @@ class DateFieldTest extends SapphireTest
|
|||||||
public function testSetValueWithDateString()
|
public function testSetValueWithDateString()
|
||||||
{
|
{
|
||||||
$f = new DateField('Date', 'Date');
|
$f = new DateField('Date', 'Date');
|
||||||
|
$f->setHTML5(false);
|
||||||
$f->setSubmittedValue('29/03/2003');
|
$f->setSubmittedValue('29/03/2003');
|
||||||
$this->assertEquals($f->dataValue(), '2003-03-29');
|
$this->assertEquals($f->dataValue(), '2003-03-29');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetValueWithDateArray()
|
|
||||||
{
|
|
||||||
$f = new SeparatedDateField('Date', 'Date');
|
|
||||||
$f->setSubmittedValue([
|
|
||||||
'day' => 29,
|
|
||||||
'month' => 03,
|
|
||||||
'year' => 2003
|
|
||||||
]);
|
|
||||||
$this->assertEquals($f->dataValue(), '2003-03-29');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testConstructorWithIsoDate()
|
public function testConstructorWithIsoDate()
|
||||||
{
|
{
|
||||||
// used by Form->loadDataFrom()
|
// used by Form->loadDataFrom()
|
||||||
@ -145,84 +135,11 @@ class DateFieldTest extends SapphireTest
|
|||||||
$this->assertFalse($f->validate(new RequiredFields()));
|
$this->assertFalse($f->validate(new RequiredFields()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testEmptyValueValidation()
|
|
||||||
{
|
|
||||||
$validator = new RequiredFields();
|
|
||||||
$field = new SeparatedDateField('Date');
|
|
||||||
$this->assertTrue($field->validate($validator));
|
|
||||||
$field->setSubmittedValue([
|
|
||||||
'day' => '',
|
|
||||||
'month' => '',
|
|
||||||
'year' => '',
|
|
||||||
]);
|
|
||||||
$this->assertTrue($field->validate($validator));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateArray()
|
|
||||||
{
|
|
||||||
$f = new SeparatedDateField('Date', 'Date');
|
|
||||||
$f->setSubmittedValue([
|
|
||||||
'day' => 29,
|
|
||||||
'month' => 03,
|
|
||||||
'year' => 2003
|
|
||||||
]);
|
|
||||||
$this->assertTrue($f->validate(new RequiredFields()));
|
|
||||||
|
|
||||||
$f->setValue(null);
|
|
||||||
$this->assertTrue($f->validate(new RequiredFields()), 'NULL values are validating TRUE');
|
|
||||||
|
|
||||||
$f->setSubmittedValue(array());
|
|
||||||
$this->assertTrue($f->validate(new RequiredFields()), 'Empty array values are validating TRUE');
|
|
||||||
|
|
||||||
$f->setSubmittedValue([
|
|
||||||
'day' => null,
|
|
||||||
'month' => null,
|
|
||||||
'year' => null
|
|
||||||
]);
|
|
||||||
$this->assertTrue($f->validate(new RequiredFields()), 'Empty array values with keys are validating TRUE');
|
|
||||||
$f->setSubmittedValue([
|
|
||||||
'day' => 9999,
|
|
||||||
'month' => 9999,
|
|
||||||
'year' => 9999
|
|
||||||
]);
|
|
||||||
$this->assertFalse($f->validate(new RequiredFields()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateEmptyArrayValuesSetsNullForValueObject()
|
|
||||||
{
|
|
||||||
$f = new SeparatedDateField('Date', 'Date');
|
|
||||||
$f->setSubmittedValue([
|
|
||||||
'day' => '',
|
|
||||||
'month' => '',
|
|
||||||
'year' => ''
|
|
||||||
]);
|
|
||||||
$this->assertNull($f->dataValue());
|
|
||||||
|
|
||||||
$f->setSubmittedValue([
|
|
||||||
'day' => null,
|
|
||||||
'month' => null,
|
|
||||||
'year' => null
|
|
||||||
]);
|
|
||||||
$this->assertNull($f->dataValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidateArrayValue()
|
|
||||||
{
|
|
||||||
$f = new SeparatedDateField('Date', 'Date');
|
|
||||||
$f->setSubmittedValue(['day' => 29, 'month' => 03, 'year' => 2003]);
|
|
||||||
$this->assertTrue($f->validate(new RequiredFields()));
|
|
||||||
|
|
||||||
$f->setSubmittedValue(['month' => 03, 'year' => 2003]);
|
|
||||||
$this->assertFalse($f->validate(new RequiredFields()));
|
|
||||||
|
|
||||||
$f->setSubmittedValue(array('day' => 99, 'month' => 99, 'year' => 2003));
|
|
||||||
$this->assertFalse($f->validate(new RequiredFields()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFormatEnNz()
|
public function testFormatEnNz()
|
||||||
{
|
{
|
||||||
/* We get YYYY-MM-DD format as the data value for DD/MM/YYYY input value */
|
/* We get YYYY-MM-DD format as the data value for DD/MM/YYYY input value */
|
||||||
$f = new DateField('Date', 'Date');
|
$f = new DateField('Date', 'Date');
|
||||||
|
$f->setHTML5(false);
|
||||||
$f->setSubmittedValue('29/03/2003');
|
$f->setSubmittedValue('29/03/2003');
|
||||||
$this->assertEquals($f->dataValue(), '2003-03-29');
|
$this->assertEquals($f->dataValue(), '2003-03-29');
|
||||||
}
|
}
|
||||||
@ -232,6 +149,7 @@ class DateFieldTest extends SapphireTest
|
|||||||
// should get en_NZ by default through setUp()
|
// should get en_NZ by default through setUp()
|
||||||
i18n::set_locale('de_DE');
|
i18n::set_locale('de_DE');
|
||||||
$f = new DateField('Date', 'Date', '29/03/2003');
|
$f = new DateField('Date', 'Date', '29/03/2003');
|
||||||
|
$f->setHTML5(false);
|
||||||
$f->setValue('29.06.2006');
|
$f->setValue('29.06.2006');
|
||||||
$this->assertEquals($f->dataValue(), '2006-06-29');
|
$this->assertEquals($f->dataValue(), '2006-06-29');
|
||||||
}
|
}
|
||||||
@ -242,6 +160,7 @@ class DateFieldTest extends SapphireTest
|
|||||||
public function testMDYFormat()
|
public function testMDYFormat()
|
||||||
{
|
{
|
||||||
$dateField = new DateField('Date', 'Date');
|
$dateField = new DateField('Date', 'Date');
|
||||||
|
$dateField->setHTML5(false);
|
||||||
$dateField->setDateFormat('d/M/y');
|
$dateField->setDateFormat('d/M/y');
|
||||||
$dateField->setSubmittedValue('31/03/2003');
|
$dateField->setSubmittedValue('31/03/2003');
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -251,6 +170,7 @@ class DateFieldTest extends SapphireTest
|
|||||||
);
|
);
|
||||||
|
|
||||||
$dateField2 = new DateField('Date', 'Date');
|
$dateField2 = new DateField('Date', 'Date');
|
||||||
|
$dateField2->setHTML5(false);
|
||||||
$dateField2->setDateFormat('d/M/y');
|
$dateField2->setDateFormat('d/M/y');
|
||||||
$dateField2->setSubmittedValue('04/3/03');
|
$dateField2->setSubmittedValue('04/3/03');
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -259,4 +179,40 @@ class DateFieldTest extends SapphireTest
|
|||||||
"Even if input value hasn't got leading 0's in it we still get the correct data value"
|
"Even if input value hasn't got leading 0's in it we still get the correct data value"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
* @expectedExceptionMessageRegExp /Please opt-out .* if using setDateFormat/
|
||||||
|
*/
|
||||||
|
public function testHtml5WithCustomFormatThrowsException()
|
||||||
|
{
|
||||||
|
$dateField = new DateField('Date', 'Date');
|
||||||
|
$dateField->setValue('2010-03-31');
|
||||||
|
$dateField->setDateFormat('d/M/y');
|
||||||
|
$dateField->Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
* @expectedExceptionMessageRegExp /Please opt-out .* if using setDateLength/
|
||||||
|
*/
|
||||||
|
public function testHtml5WithCustomDateLengthThrowsException()
|
||||||
|
{
|
||||||
|
$dateField = new DateField('Date', 'Date');
|
||||||
|
$dateField->setValue('2010-03-31');
|
||||||
|
$dateField->setDateLength(IntlDateFormatter::MEDIUM);
|
||||||
|
$dateField->Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
* @expectedExceptionMessageRegExp /Please opt-out .* if using setLocale/
|
||||||
|
*/
|
||||||
|
public function testHtml5WithCustomLocaleThrowsException()
|
||||||
|
{
|
||||||
|
$dateField = new DateField('Date', 'Date');
|
||||||
|
$dateField->setValue('2010-03-31');
|
||||||
|
$dateField->setLocale('de_DE');
|
||||||
|
$dateField->Value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace SilverStripe\Forms\Tests;
|
|
||||||
|
|
||||||
use SilverStripe\Dev\SapphireTest;
|
|
||||||
use SilverStripe\Forms\DateField_View_JQuery;
|
|
||||||
|
|
||||||
class DateFieldViewJQueryTest extends SapphireTest
|
|
||||||
{
|
|
||||||
|
|
||||||
public function testConvert()
|
|
||||||
{
|
|
||||||
$this->assertEquals(
|
|
||||||
'M d, yy',
|
|
||||||
DateField_View_JQuery::convert_iso_to_jquery_format('MMM d, yyyy')
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'd/mm/yy',
|
|
||||||
DateField_View_JQuery::convert_iso_to_jquery_format('d/MM/yyyy')
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'dd.m.yy',
|
|
||||||
DateField_View_JQuery::convert_iso_to_jquery_format('dd.M.yyyy'),
|
|
||||||
'Month, no leading zero'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'dd.mm.yy',
|
|
||||||
DateField_View_JQuery::convert_iso_to_jquery_format('dd.MM.yyyy'),
|
|
||||||
'Month, two digit'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'dd.M.yy',
|
|
||||||
DateField_View_JQuery::convert_iso_to_jquery_format('dd.MMM.yyyy'),
|
|
||||||
'Abbreviated month name'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
'dd.MM.yy',
|
|
||||||
DateField_View_JQuery::convert_iso_to_jquery_format('dd.MMMM.yyyy'),
|
|
||||||
'Full month name'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,7 +7,6 @@ use SilverStripe\Control\Controller;
|
|||||||
use SilverStripe\Forms\DatetimeField;
|
use SilverStripe\Forms\DatetimeField;
|
||||||
use SilverStripe\Forms\RequiredFields;
|
use SilverStripe\Forms\RequiredFields;
|
||||||
use SilverStripe\Forms\DateField;
|
use SilverStripe\Forms\DateField;
|
||||||
use SilverStripe\Forms\SeparatedDateField;
|
|
||||||
use SilverStripe\Forms\Tests\DatetimeFieldTest\Model;
|
use SilverStripe\Forms\Tests\DatetimeFieldTest\Model;
|
||||||
use SilverStripe\Forms\TimeField;
|
use SilverStripe\Forms\TimeField;
|
||||||
use SilverStripe\Forms\FieldList;
|
use SilverStripe\Forms\FieldList;
|
||||||
@ -38,6 +37,32 @@ class DatetimeFieldTest extends SapphireTest
|
|||||||
$form = $this->getMockForm();
|
$form = $this->getMockForm();
|
||||||
$form->Fields()->push($dateTimeField);
|
$form->Fields()->push($dateTimeField);
|
||||||
|
|
||||||
|
$dateTimeField->setSubmittedValue([
|
||||||
|
'date' => '2003-03-29',
|
||||||
|
'time' => '23:59:38'
|
||||||
|
]);
|
||||||
|
$validator = new RequiredFields();
|
||||||
|
$this->assertTrue($dateTimeField->validate($validator));
|
||||||
|
$m = new Model();
|
||||||
|
$form->saveInto($m);
|
||||||
|
$this->assertEquals('2003-03-29 23:59:38', $m->MyDatetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFormSaveIntoLocalised()
|
||||||
|
{
|
||||||
|
$dateTimeField = new DatetimeField('MyDatetime');
|
||||||
|
|
||||||
|
$dateTimeField->getDateField()
|
||||||
|
->setHTML5(false)
|
||||||
|
->setLocale('en_NZ');
|
||||||
|
|
||||||
|
$dateTimeField->getTimeField()
|
||||||
|
->setHTML5(false)
|
||||||
|
->setLocale('en_NZ');
|
||||||
|
|
||||||
|
$form = $this->getMockForm();
|
||||||
|
$form->Fields()->push($dateTimeField);
|
||||||
|
|
||||||
// en_NZ standard format
|
// en_NZ standard format
|
||||||
$dateTimeField->setSubmittedValue([
|
$dateTimeField->setSubmittedValue([
|
||||||
'date' => '29/03/2003',
|
'date' => '29/03/2003',
|
||||||
@ -97,6 +122,25 @@ class DatetimeFieldTest extends SapphireTest
|
|||||||
public function testSetValueWithArray()
|
public function testSetValueWithArray()
|
||||||
{
|
{
|
||||||
$datetimeField = new DatetimeField('Datetime', 'Datetime');
|
$datetimeField = new DatetimeField('Datetime', 'Datetime');
|
||||||
|
$datetimeField->setSubmittedValue([
|
||||||
|
'date' => '2003-03-29',
|
||||||
|
'time' => '23:00:00'
|
||||||
|
]);
|
||||||
|
$this->assertEquals($datetimeField->dataValue(), '2003-03-29 23:00:00');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetValueWithArrayLocalised()
|
||||||
|
{
|
||||||
|
$datetimeField = new DatetimeField('Datetime', 'Datetime');
|
||||||
|
|
||||||
|
$datetimeField->getDateField()
|
||||||
|
->setHTML5(false)
|
||||||
|
->setLocale('en_NZ');
|
||||||
|
|
||||||
|
$datetimeField->getTimeField()
|
||||||
|
->setHTML5(false)
|
||||||
|
->setLocale('en_NZ');
|
||||||
|
|
||||||
// Values can only be localized (= non-ISO) in array notation
|
// Values can only be localized (= non-ISO) in array notation
|
||||||
$datetimeField->setSubmittedValue([
|
$datetimeField->setSubmittedValue([
|
||||||
'date' => '29/03/2003',
|
'date' => '29/03/2003',
|
||||||
@ -105,17 +149,6 @@ class DatetimeFieldTest extends SapphireTest
|
|||||||
$this->assertEquals($datetimeField->dataValue(), '2003-03-29 23:00:00');
|
$this->assertEquals($datetimeField->dataValue(), '2003-03-29 23:00:00');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetValueWithDmyArray()
|
|
||||||
{
|
|
||||||
$f = new DatetimeField('Datetime', 'Datetime');
|
|
||||||
$f->setDateField(new SeparatedDateField('Datetime[date]'));
|
|
||||||
$f->setSubmittedValue([
|
|
||||||
'date' => ['day' => 29, 'month' => 03, 'year' => 2003],
|
|
||||||
'time' => '11:00:00 pm'
|
|
||||||
]);
|
|
||||||
$this->assertEquals($f->dataValue(), '2003-03-29 23:00:00');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidate()
|
public function testValidate()
|
||||||
{
|
{
|
||||||
$f = new DatetimeField('Datetime', 'Datetime', '2003-03-29 23:59:38');
|
$f = new DatetimeField('Datetime', 'Datetime', '2003-03-29 23:59:38');
|
||||||
@ -128,11 +161,20 @@ class DatetimeFieldTest extends SapphireTest
|
|||||||
$this->assertFalse($f->validate(new RequiredFields()));
|
$this->assertFalse($f->validate(new RequiredFields()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTimezoneSet()
|
public function testTimezoneSetLocalised()
|
||||||
{
|
{
|
||||||
date_default_timezone_set('Europe/Berlin');
|
date_default_timezone_set('Europe/Berlin');
|
||||||
// Berlin and Auckland have 12h time difference in northern hemisphere winter
|
// Berlin and Auckland have 12h time difference in northern hemisphere winter
|
||||||
$datetimeField = new DatetimeField('Datetime', 'Datetime');
|
$datetimeField = new DatetimeField('Datetime', 'Datetime');
|
||||||
|
|
||||||
|
$datetimeField->getDateField()
|
||||||
|
->setHTML5(false)
|
||||||
|
->setLocale('en_NZ');
|
||||||
|
|
||||||
|
$datetimeField->getTimeField()
|
||||||
|
->setHTML5(false)
|
||||||
|
->setLocale('en_NZ');
|
||||||
|
|
||||||
$datetimeField->setTimezone('Pacific/Auckland');
|
$datetimeField->setTimezone('Pacific/Auckland');
|
||||||
$datetimeField->setValue('2003-12-24 23:59:59');
|
$datetimeField->setValue('2003-12-24 23:59:59');
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -149,11 +191,20 @@ class DatetimeFieldTest extends SapphireTest
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTimezoneFromConfig()
|
public function testTimezoneFromConfigLocalised()
|
||||||
{
|
{
|
||||||
date_default_timezone_set('Europe/Berlin');
|
date_default_timezone_set('Europe/Berlin');
|
||||||
// Berlin and Auckland have 12h time difference in northern hemisphere summer, but Berlin and Moscow only 2h.
|
// Berlin and Auckland have 12h time difference in northern hemisphere summer, but Berlin and Moscow only 2h.
|
||||||
$datetimeField = new DatetimeField('Datetime', 'Datetime');
|
$datetimeField = new DatetimeField('Datetime', 'Datetime');
|
||||||
|
|
||||||
|
$datetimeField->getDateField()
|
||||||
|
->setHTML5(false)
|
||||||
|
->setLocale('en_NZ');
|
||||||
|
|
||||||
|
$datetimeField->getTimeField()
|
||||||
|
->setHTML5(false)
|
||||||
|
->setLocale('en_NZ');
|
||||||
|
|
||||||
$datetimeField->setTimezone('Europe/Moscow');
|
$datetimeField->setTimezone('Europe/Moscow');
|
||||||
$datetimeField->setSubmittedValue([
|
$datetimeField->setSubmittedValue([
|
||||||
// pass in default format, at user time (Moscow)
|
// pass in default format, at user time (Moscow)
|
||||||
@ -170,7 +221,7 @@ class DatetimeFieldTest extends SapphireTest
|
|||||||
$field = new DatetimeField('Datetime', 'Datetime');
|
$field = new DatetimeField('Datetime', 'Datetime');
|
||||||
$field->setForm($form);
|
$field->setForm($form);
|
||||||
$field->setSubmittedValue([
|
$field->setSubmittedValue([
|
||||||
'date' => '24/06/2003',
|
'date' => '2003-06-24',
|
||||||
'time' => '23:59:59',
|
'time' => '23:59:59',
|
||||||
]);
|
]);
|
||||||
$dateField = new DateField('Datetime[date]');
|
$dateField = new DateField('Datetime[date]');
|
||||||
@ -195,8 +246,8 @@ class DatetimeFieldTest extends SapphireTest
|
|||||||
$field = new DatetimeField('Datetime', 'Datetime');
|
$field = new DatetimeField('Datetime', 'Datetime');
|
||||||
$field->setForm($form);
|
$field->setForm($form);
|
||||||
$field->setSubmittedValue([
|
$field->setSubmittedValue([
|
||||||
'date' => '24/06/2003',
|
'date' => '2003-06-24',
|
||||||
'time' => '11:59:59 pm',
|
'time' => '23:59:59',
|
||||||
]);
|
]);
|
||||||
$timeField = new TimeField('Datetime[time]');
|
$timeField = new TimeField('Datetime[time]');
|
||||||
$field->setTimeField($timeField);
|
$field->setTimeField($timeField);
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace SilverStripe\Forms\Tests;
|
|
||||||
|
|
||||||
use SilverStripe\Core\Config\Config;
|
|
||||||
use SilverStripe\Dev\CSSContentParser;
|
|
||||||
use SilverStripe\Dev\SapphireTest;
|
|
||||||
use SilverStripe\Control\Controller;
|
|
||||||
use SilverStripe\Forms\MemberDatetimeOptionsetField;
|
|
||||||
use SilverStripe\Forms\FieldList;
|
|
||||||
use SilverStripe\Forms\Form;
|
|
||||||
use SilverStripe\Forms\RequiredFields;
|
|
||||||
use SilverStripe\i18n\i18n;
|
|
||||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
|
||||||
use SilverStripe\Security\Member;
|
|
||||||
|
|
||||||
class MemberDatetimeOptionsetFieldTest extends SapphireTest
|
|
||||||
{
|
|
||||||
protected static $fixture_file = 'MemberDatetimeOptionsetFieldTest.yml';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Member $member
|
|
||||||
* @return MemberDatetimeOptionsetField
|
|
||||||
*/
|
|
||||||
protected function createDateFormatFieldForMember($member)
|
|
||||||
{
|
|
||||||
$defaultDateFormat = $member->getDefaultDateFormat();
|
|
||||||
$dateFormatMap = array(
|
|
||||||
'yyyy-MM-dd' => DBDatetime::now()->Format('yyyy-MM-dd'),
|
|
||||||
'yyyy/MM/dd' => DBDatetime::now()->Format('yyyy/MM/dd'),
|
|
||||||
'MM/dd/yyyy' => DBDatetime::now()->Format('MM/dd/yyyy'),
|
|
||||||
'dd/MM/yyyy' => DBDatetime::now()->Format('dd/MM/yyyy'),
|
|
||||||
);
|
|
||||||
$dateFormatMap[$defaultDateFormat] = DBDatetime::now()->Format($defaultDateFormat) . ' (default)';
|
|
||||||
$field = new MemberDatetimeOptionsetField(
|
|
||||||
'DateFormat',
|
|
||||||
'Date format',
|
|
||||||
$dateFormatMap
|
|
||||||
);
|
|
||||||
$field->setValue($member->getDateFormat());
|
|
||||||
return $field;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Member $member
|
|
||||||
* @return MemberDatetimeOptionsetField
|
|
||||||
*/
|
|
||||||
protected function createTimeFormatFieldForMember($member)
|
|
||||||
{
|
|
||||||
$defaultTimeFormat = $member->getDefaultTimeFormat();
|
|
||||||
$timeFormatMap = array(
|
|
||||||
'h:mm a' => DBDatetime::now()->Format('h:mm a'),
|
|
||||||
'H:mm' => DBDatetime::now()->Format('H:mm'),
|
|
||||||
);
|
|
||||||
$timeFormatMap[$defaultTimeFormat] = DBDatetime::now()->Format($defaultTimeFormat) . ' (default)';
|
|
||||||
$field = new MemberDatetimeOptionsetField(
|
|
||||||
'TimeFormat',
|
|
||||||
'Time format',
|
|
||||||
$timeFormatMap
|
|
||||||
);
|
|
||||||
$field->setValue($member->getTimeFormat());
|
|
||||||
return $field;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDateFormatDefaultCheckedInFormField()
|
|
||||||
{
|
|
||||||
/** @var Member $member */
|
|
||||||
$member = $this->objFromFixture(Member::class, 'noformatmember');
|
|
||||||
$field = $this->createDateFormatFieldForMember($member);
|
|
||||||
/** @skipUpgrade */
|
|
||||||
$field->setForm(
|
|
||||||
new Form(
|
|
||||||
new Controller(),
|
|
||||||
'Form',
|
|
||||||
new FieldList(),
|
|
||||||
new FieldList()
|
|
||||||
)
|
|
||||||
); // fake form
|
|
||||||
// `MMM d, y` is default format for default locale (en_US)
|
|
||||||
$parser = new CSSContentParser($field->Field());
|
|
||||||
$xmlArr = $parser->getBySelector('#Form_Form_DateFormat_MMM_d_y');
|
|
||||||
$this->assertEquals('checked', (string) $xmlArr[0]['checked']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTimeFormatDefaultCheckedInFormField()
|
|
||||||
{
|
|
||||||
/** @var Member $member */
|
|
||||||
$member = $this->objFromFixture(Member::class, 'noformatmember');
|
|
||||||
$field = $this->createTimeFormatFieldForMember($member);
|
|
||||||
/** @skipUpgrade */
|
|
||||||
$field->setForm(
|
|
||||||
new Form(
|
|
||||||
new Controller(),
|
|
||||||
'Form',
|
|
||||||
new FieldList(),
|
|
||||||
new FieldList()
|
|
||||||
)
|
|
||||||
); // fake form
|
|
||||||
// `h:mm:ss a` is the default for en_US locale
|
|
||||||
$parser = new CSSContentParser($field->Field());
|
|
||||||
$xmlArr = $parser->getBySelector('#Form_Form_TimeFormat_h:mm:ss_a');
|
|
||||||
$this->assertEquals('checked', (string) $xmlArr[0]['checked']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDateFormatChosenIsCheckedInFormField()
|
|
||||||
{
|
|
||||||
/** @var Member $member */
|
|
||||||
$member = $this->objFromFixture(Member::class, 'noformatmember');
|
|
||||||
$member->setField('DateFormat', 'MM/dd/yyyy');
|
|
||||||
$field = $this->createDateFormatFieldForMember($member);
|
|
||||||
/** @skipUpgrade */
|
|
||||||
$field->setForm(
|
|
||||||
new Form(
|
|
||||||
new Controller(),
|
|
||||||
'Form',
|
|
||||||
new FieldList(),
|
|
||||||
new FieldList()
|
|
||||||
)
|
|
||||||
); // fake form
|
|
||||||
$parser = new CSSContentParser($field->Field());
|
|
||||||
$xmlArr = $parser->getBySelector('#Form_Form_DateFormat_MM_dd_yyyy');
|
|
||||||
$this->assertEquals('checked', (string) $xmlArr[0]['checked']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDateFormatCustomFormatAppearsInCustomInputInField()
|
|
||||||
{
|
|
||||||
/** @var Member $member */
|
|
||||||
$member = $this->objFromFixture(Member::class, 'noformatmember');
|
|
||||||
$member->setField('DateFormat', 'dd MM yy');
|
|
||||||
$field = $this->createDateFormatFieldForMember($member);
|
|
||||||
/** @skipUpgrade */
|
|
||||||
$field->setForm(
|
|
||||||
new Form(
|
|
||||||
new Controller(),
|
|
||||||
'Form',
|
|
||||||
new FieldList(),
|
|
||||||
new FieldList()
|
|
||||||
)
|
|
||||||
); // fake form
|
|
||||||
$parser = new CSSContentParser($field->Field());
|
|
||||||
$xmlInputArr = $parser->getBySelector('.valcustom input');
|
|
||||||
$this->assertEquals('checked', (string) $xmlInputArr[0]['checked']);
|
|
||||||
$this->assertEquals('dd MM yy', (string) $xmlInputArr[1]['value']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDateFormValid()
|
|
||||||
{
|
|
||||||
$field = new MemberDatetimeOptionsetField('DateFormat', 'DateFormat');
|
|
||||||
$validator = new RequiredFields();
|
|
||||||
$this->assertTrue($field->validate($validator));
|
|
||||||
$field->setSubmittedValue([
|
|
||||||
'Options' => '__custom__',
|
|
||||||
'Custom' => 'dd MM yyyy'
|
|
||||||
]);
|
|
||||||
$this->assertTrue($field->validate($validator));
|
|
||||||
$field->setSubmittedValue([
|
|
||||||
'Options' => '__custom__',
|
|
||||||
'Custom' => 'sdfdsfdfd1244'
|
|
||||||
]);
|
|
||||||
// @todo - Be less forgiving of invalid CLDR date format strings
|
|
||||||
$this->assertTrue($field->validate($validator));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDescriptionTemplate()
|
|
||||||
{
|
|
||||||
$field = new MemberDatetimeOptionsetField('DateFormat', 'DateFormat');
|
|
||||||
|
|
||||||
$this->assertEmpty($field->getDescription());
|
|
||||||
|
|
||||||
$field->setDescription('Test description');
|
|
||||||
$this->assertEquals('Test description', $field->getDescription());
|
|
||||||
|
|
||||||
$field->setDescriptionTemplate(get_class($field).'_description_time');
|
|
||||||
$this->assertNotEmpty($field->getDescription());
|
|
||||||
$this->assertNotEquals('Test description', $field->getDescription());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
SilverStripe\Security\Member:
|
|
||||||
noformatmember:
|
|
||||||
Email: noformat@test.com
|
|
||||||
delocalemember:
|
|
||||||
Email: delocalemember@test.com
|
|
||||||
Locale: de_DE
|
|
@ -1,53 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace SilverStripe\Forms\Tests;
|
|
||||||
|
|
||||||
use SilverStripe\Dev\SapphireTest;
|
|
||||||
use SilverStripe\Forms\DateField;
|
|
||||||
use SilverStripe\Forms\SeparatedDateField;
|
|
||||||
use SilverStripe\Forms\RequiredFields;
|
|
||||||
use SilverStripe\i18n\i18n;
|
|
||||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
|
||||||
|
|
||||||
class SeparatedDateFieldTest extends SapphireTest
|
|
||||||
{
|
|
||||||
protected function setUp()
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
i18n::set_locale('en_NZ');
|
|
||||||
DBDatetime::set_mock_now('2011-02-01 8:34:00');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFieldOrderingBasedOnLocale()
|
|
||||||
{
|
|
||||||
$dateField = new SeparatedDateField('Date');
|
|
||||||
$dateField->setLocale('en_NZ');
|
|
||||||
$this->assertRegExp('/.*[day].*[month].*[year]/', $dateField->Field());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFieldOrderingBasedOnDateFormat()
|
|
||||||
{
|
|
||||||
$dateField = new SeparatedDateField('Date');
|
|
||||||
$dateField->setDateFormat('y/MM/dd');
|
|
||||||
$this->assertRegExp('/.*[year].*[month].*[day]/', $dateField->Field());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCustomSeparator()
|
|
||||||
{
|
|
||||||
$dateField = new SeparatedDateField('Date');
|
|
||||||
$dateField->setDateFormat('dd/MM/y');
|
|
||||||
$dateField->setSeparator('###');
|
|
||||||
$this->assertRegExp('/.*[day].*###.*[month].*###.*[day]/', $dateField->Field());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @expectedException \InvalidArgumentException
|
|
||||||
* @expectedExceptionMessage Invalid date format
|
|
||||||
*/
|
|
||||||
public function testInvalidDateFormat()
|
|
||||||
{
|
|
||||||
$dateField = new SeparatedDateField('Date');
|
|
||||||
$dateField->setDateFormat('y/MM');
|
|
||||||
$dateField->Field();
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace SilverStripe\Forms\Tests;
|
namespace SilverStripe\Forms\Tests;
|
||||||
|
|
||||||
|
use IntlDateFormatter;
|
||||||
use SilverStripe\Core\Config\Config;
|
use SilverStripe\Core\Config\Config;
|
||||||
use SilverStripe\Dev\SapphireTest;
|
use SilverStripe\Dev\SapphireTest;
|
||||||
use SilverStripe\Forms\TimeField;
|
use SilverStripe\Forms\TimeField;
|
||||||
@ -40,11 +41,23 @@ class TimeFieldTest extends SapphireTest
|
|||||||
$this->assertFalse($f->validate(new RequiredFields()));
|
$this->assertFalse($f->validate(new RequiredFields()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testValidateLenientWithHtml5()
|
||||||
|
{
|
||||||
|
$f = new TimeField('Time', 'Time', '23:59:59');
|
||||||
|
$f->setHTML5(true);
|
||||||
|
$this->assertTrue($f->validate(new RequiredFields()));
|
||||||
|
|
||||||
|
$f = new TimeField('Time', 'Time', '23:59'); // leave out seconds
|
||||||
|
$f->setHTML5(true);
|
||||||
|
$this->assertTrue($f->validate(new RequiredFields()));
|
||||||
|
}
|
||||||
|
|
||||||
public function testSetLocale()
|
public function testSetLocale()
|
||||||
{
|
{
|
||||||
// should get en_NZ by default through setUp()
|
// should get en_NZ by default through setUp()
|
||||||
$f = new TimeField('Time', 'Time');
|
$f = new TimeField('Time', 'Time');
|
||||||
$f->setLocale('de_DE');
|
$f->setHTML5(false);
|
||||||
|
$f->setLocale('fr_FR');
|
||||||
// TODO Find a hour format thats actually different
|
// TODO Find a hour format thats actually different
|
||||||
$f->setValue('23:59');
|
$f->setValue('23:59');
|
||||||
$this->assertEquals($f->dataValue(), '23:59:00');
|
$this->assertEquals($f->dataValue(), '23:59:00');
|
||||||
@ -85,8 +98,7 @@ class TimeFieldTest extends SapphireTest
|
|||||||
public function testOverrideWithNull()
|
public function testOverrideWithNull()
|
||||||
{
|
{
|
||||||
$field = new TimeField('Time', 'Time');
|
$field = new TimeField('Time', 'Time');
|
||||||
|
$field->setValue('11:00:00');
|
||||||
$field->setValue('11:00pm');
|
|
||||||
$field->setValue('');
|
$field->setValue('');
|
||||||
$this->assertEquals($field->dataValue(), '');
|
$this->assertEquals($field->dataValue(), '');
|
||||||
}
|
}
|
||||||
@ -94,33 +106,80 @@ class TimeFieldTest extends SapphireTest
|
|||||||
/**
|
/**
|
||||||
* Test that AM/PM is preserved correctly in various situations
|
* Test that AM/PM is preserved correctly in various situations
|
||||||
*/
|
*/
|
||||||
public function testPreserveAMPM()
|
public function testSetTimeFormat()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Test with timeformat that includes hour
|
// Test with timeformat that includes hour
|
||||||
|
|
||||||
// Check pm
|
// Check pm
|
||||||
$f = new TimeField('Time', 'Time');
|
$f = new TimeField('Time', 'Time');
|
||||||
|
$f->setHTML5(false);
|
||||||
$f->setTimeFormat('h:mm:ss a');
|
$f->setTimeFormat('h:mm:ss a');
|
||||||
$f->setValue('3:59 pm');
|
$f->setValue('3:59 pm');
|
||||||
$this->assertEquals($f->dataValue(), '15:59:00');
|
$this->assertEquals($f->dataValue(), '15:59:00');
|
||||||
|
|
||||||
// Check am
|
// Check am
|
||||||
$f = new TimeField('Time', 'Time');
|
$f = new TimeField('Time', 'Time');
|
||||||
|
$f->setHTML5(false);
|
||||||
$f->setTimeFormat('h:mm:ss a');
|
$f->setTimeFormat('h:mm:ss a');
|
||||||
$f->setValue('3:59 am');
|
$f->setValue('3:59 am');
|
||||||
$this->assertEquals($f->dataValue(), '03:59:00');
|
$this->assertEquals($f->dataValue(), '03:59:00');
|
||||||
|
|
||||||
// Check with ISO date/time
|
// Check with ISO date/time
|
||||||
$f = new TimeField('Time', 'Time');
|
$f = new TimeField('Time', 'Time');
|
||||||
|
$f->setHTML5(false);
|
||||||
$f->setTimeFormat('h:mm:ss a');
|
$f->setTimeFormat('h:mm:ss a');
|
||||||
$f->setValue('15:59:00');
|
$f->setValue('15:59:00');
|
||||||
$this->assertEquals($f->dataValue(), '15:59:00');
|
$this->assertEquals($f->dataValue(), '15:59:00');
|
||||||
|
|
||||||
// ISO am
|
// ISO am
|
||||||
$f = new TimeField('Time', 'Time');
|
$f = new TimeField('Time', 'Time');
|
||||||
|
$f->setHTML5(false);
|
||||||
$f->setTimeFormat('h:mm:ss a');
|
$f->setTimeFormat('h:mm:ss a');
|
||||||
$f->setValue('03:59:00');
|
$f->setValue('03:59:00');
|
||||||
$this->assertEquals($f->dataValue(), '03:59:00');
|
$this->assertEquals($f->dataValue(), '03:59:00');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testLenientSubmissionParseWithoutSecondsOnHtml5()
|
||||||
|
{
|
||||||
|
$f = new TimeField('Time', 'Time');
|
||||||
|
$f->setSubmittedValue('23:59');
|
||||||
|
$this->assertEquals($f->Value(), '23:59:00');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
* @expectedExceptionMessageRegExp /Please opt-out .* if using setTimeFormat/
|
||||||
|
*/
|
||||||
|
public function testHtml5WithCustomFormatThrowsException()
|
||||||
|
{
|
||||||
|
$f = new TimeField('Time', 'Time');
|
||||||
|
$f->setValue('15:59:00');
|
||||||
|
$f->setTimeFormat('mm:HH');
|
||||||
|
$f->Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
* @expectedExceptionMessageRegExp /Please opt-out .* if using setTimeLength/
|
||||||
|
*/
|
||||||
|
public function testHtml5WithCustomDateLengthThrowsException()
|
||||||
|
{
|
||||||
|
$f = new TimeField('Time', 'Time');
|
||||||
|
$f->setValue('15:59:00');
|
||||||
|
$f->setTimeLength(IntlDateFormatter::MEDIUM);
|
||||||
|
$f->Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
* @expectedExceptionMessageRegExp /Please opt-out .* if using setLocale/
|
||||||
|
*/
|
||||||
|
public function testHtml5WithCustomLocaleThrowsException()
|
||||||
|
{
|
||||||
|
$f = new TimeField('Time', 'Time');
|
||||||
|
$f->setValue('15:59:00');
|
||||||
|
$f->setLocale('de_DE');
|
||||||
|
$f->Value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,41 +324,4 @@ class DBDateTest extends SapphireTest
|
|||||||
|
|
||||||
DBDatetime::clear_mock_now();
|
DBDatetime::clear_mock_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see testFormatFromSettings
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function dataTestFormatFromSettings()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['2000-12-31', '31/12/2000'],
|
|
||||||
['31-12-2000', '31/12/2000'],
|
|
||||||
['2014-04-01', '01/04/2014'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider dataTestFormatFromSettings
|
|
||||||
* @param string $from
|
|
||||||
* @param string $to
|
|
||||||
*/
|
|
||||||
public function testFormatFromSettings($from, $to)
|
|
||||||
{
|
|
||||||
$this->suppressNotices();
|
|
||||||
$member = new Member();
|
|
||||||
$member->DateFormat = 'dd/MM/y';
|
|
||||||
|
|
||||||
$date = DBField::create_field('Date', $from);
|
|
||||||
$this->assertEquals($to, $date->FormatFromSettings($member));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that FormatFromSettings without a member defaults to Nice()
|
|
||||||
*/
|
|
||||||
public function testFormatFromSettingsEmpty()
|
|
||||||
{
|
|
||||||
$date = DBfield::create_field('Date', '2000-12-31');
|
|
||||||
$this->assertEquals('31/12/2000', $date->FormatFromSettings());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -204,41 +204,4 @@ class DBDatetimeTest extends SapphireTest
|
|||||||
|
|
||||||
DBDatetime::clear_mock_now();
|
DBDatetime::clear_mock_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dataTestFormatFromSettings()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['2000-12-31 10:11:01', '31/12/2000 10:11:01'],
|
|
||||||
['2000-12-31 1:11:01', '31/12/2000 01:11:01'],
|
|
||||||
['2000-12-12 1:11:01', '12/12/2000 01:11:01'],
|
|
||||||
['2000-12-31', '31/12/2000 00:00:00'],
|
|
||||||
['2014-04-01 10:11:01', '01/04/2014 10:11:01']
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider dataTestFormatFromSettings
|
|
||||||
* @param string $from
|
|
||||||
* @param string $to
|
|
||||||
*/
|
|
||||||
public function testFormatFromSettings($from, $to)
|
|
||||||
{
|
|
||||||
$member = new Member();
|
|
||||||
$member->DateFormat = 'dd/MM/y';
|
|
||||||
$member->TimeFormat = 'HH:mm:ss';
|
|
||||||
|
|
||||||
$date = DBDatetime::create_field('Datetime', $from);
|
|
||||||
$this->assertEquals($to, $date->FormatFromSettings($member));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that FormatFromSettings without a member defaults to Nice()
|
|
||||||
*/
|
|
||||||
public function testFormatFromSettingsEmpty()
|
|
||||||
{
|
|
||||||
$date = DBDatetime::create_field('Datetime', '2000-12-31 10:11:01');
|
|
||||||
|
|
||||||
// note: Some localisation packages exclude the ',' in default medium format
|
|
||||||
$this->assertRegExp('#31/12/2000(,)? 10:11:01 AM#', $date->FormatFromSettings());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -56,35 +56,4 @@ class DBTimeTest extends SapphireTest
|
|||||||
$time = DBTime::create_field('Time', '17:15:55');
|
$time = DBTime::create_field('Time', '17:15:55');
|
||||||
$this->assertEquals('5:15 PM', $time->Short());
|
$this->assertEquals('5:15 PM', $time->Short());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dataTestFormatFromSettings()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['10:11:01', '10:11:01 (AM)'],
|
|
||||||
['21:11:01', '9:11:01 (PM)'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider dataTestFormatFromSettings
|
|
||||||
* @param string $from
|
|
||||||
* @param string $to
|
|
||||||
*/
|
|
||||||
public function testFormatFromSettings($from, $to)
|
|
||||||
{
|
|
||||||
$member = new Member();
|
|
||||||
$member->TimeFormat = 'h:mm:ss (a)';
|
|
||||||
|
|
||||||
$date = DBTime::create_field('Time', $from);
|
|
||||||
$this->assertEquals($to, $date->FormatFromSettings($member));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that FormatFromSettings without a member defaults to Nice()
|
|
||||||
*/
|
|
||||||
public function testFormatFromSettingsEmpty()
|
|
||||||
{
|
|
||||||
$date = DBTime::create_field('Time', '10:11:01');
|
|
||||||
$this->assertEquals('10:11:01 AM', $date->FormatFromSettings());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -395,15 +395,6 @@ class MemberTest extends FunctionalTest
|
|||||||
$member->PasswordExpiry = date('Y-m-d', time() + 86400);
|
$member->PasswordExpiry = date('Y-m-d', time() + 86400);
|
||||||
$this->assertFalse($member->isPasswordExpired());
|
$this->assertFalse($member->isPasswordExpired());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMemberWithNoDateFormatFallsbackToGlobalLocaleDefaultFormat()
|
|
||||||
{
|
|
||||||
// Note: All default strings are based on locale defaults for en_US
|
|
||||||
$member = $this->objFromFixture(Member::class, 'noformatmember');
|
|
||||||
$this->assertEquals('MMM d, y', $member->DateFormat);
|
|
||||||
$this->assertEquals('h:mm:ss a', $member->TimeFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInGroups()
|
public function testInGroups()
|
||||||
{
|
{
|
||||||
$staffmember = $this->objFromFixture(Member::class, 'staffmember');
|
$staffmember = $this->objFromFixture(Member::class, 'staffmember');
|
||||||
|
Loading…
Reference in New Issue
Block a user