diff --git a/core/core.libraries.yml b/core/core.libraries.yml index 032a36a..c6f780d 100644 --- a/core/core.libraries.yml +++ b/core/core.libraries.yml @@ -132,6 +132,15 @@ drupal.collapse: - core/drupal.form - core/jquery.once +drupal.date: + version: VERSION + js: + misc/date.js: {} + dependencies: + - core/drupal + - core/modernizr + - core/jquery.ui.datepicker + drupal.debounce: version: VERSION js: diff --git a/core/lib/Drupal/Core/Datetime/Element/Datetime.php b/core/lib/Drupal/Core/Datetime/Element/Datetime.php index d298e21..fc6f4d5 100644 --- a/core/lib/Drupal/Core/Datetime/Element/Datetime.php +++ b/core/lib/Drupal/Core/Datetime/Element/Datetime.php @@ -267,6 +267,7 @@ public static function processDatetime(&$element, FormStateInterface $form_state '#attributes' => $element['#attributes'] + $extra_attributes, '#required' => $element['#required'], '#size' => max(12, strlen($element['#value']['date'])), + '#date_date_format' => $element['#date_date_format'], ); // Allows custom callbacks to alter the element. diff --git a/core/lib/Drupal/Core/Render/Element/Date.php b/core/lib/Drupal/Core/Render/Element/Date.php index 8585cb3..2c96fff 100644 --- a/core/lib/Drupal/Core/Render/Element/Date.php +++ b/core/lib/Drupal/Core/Render/Element/Date.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Render\Element; +use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; /** @@ -26,14 +27,38 @@ class Date extends FormElement { */ public function getInfo() { $class = get_class($this); - return array( + return [ '#input' => TRUE, '#theme' => 'input__date', - '#pre_render' => array( - array($class, 'preRenderDate'), - ), - '#theme_wrappers' => array('form_element'), - ); + '#process' => [[$class, 'processDate']], + '#pre_render' => [[$class, 'preRenderDate']], + '#theme_wrappers' => ['form_element'], + ]; + } + + /** + * Processes a date form element. + * + * @param array $element + * The form element to process. Properties used: + * - #attributes: An associative array containing: + * - type: The type of date field rendered. + * - #date_date_format: The date format used in PHP formats. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param array $complete_form + * The complete form structure. + * + * @return array + * The processed element. + */ + public static function processDate(&$element, FormStateInterface $form_state, &$complete_form) { + // Attach JS support, if we can determine which date format should be used. + if ($element['#attributes']['type'] == 'date' && !empty($element['#date_date_format'])) { + $element['#attached']['library'][] = 'core/drupal.date'; + $element['#attributes']['data-drupal-date-format'] = [$element['#date_date_format']]; + } + return $element; } /** @@ -42,6 +67,7 @@ public function getInfo() { * Supports HTML5 types of 'date', 'datetime', 'datetime-local', and 'time'. * Falls back to a plain textfield. Used as a sub-element by the datetime * element type. + * Adds JS fallback support for browsers not understanding date types. * * @param array $element * An associative array containing the properties of the element. diff --git a/core/misc/date.js b/core/misc/date.js new file mode 100644 index 0000000..3f401d5 --- /dev/null +++ b/core/misc/date.js @@ -0,0 +1,55 @@ +(function ($, Modernizr, Drupal) { + + "use strict"; + + /** + * Attach datepicker fallback on date elements. + */ + Drupal.behaviors.date = { + /** + * Attaches the behavior. + * + * @param settings.date + * A list of elements to process, keyed by the HTML ID of the form element + * containing the human-readable value. Each element is an datepicker + * settings object. + */ + attach: function (context, settings) { + var $context = $(context); + // Skip if date are supported by the browser. + if (Modernizr.inputtypes.date === true) { + return; + } + $context.find('input[data-drupal-date-format]').not('.hasDatepicker').each(function () { + var $input = $(this); + var datepickerSettings = {}; + var dateFormat; + dateFormat = $input.data('drupalDateFormat'); + // The date format is saved in PHP style, we need to convert to jQuery + // datepicker. + dateFormat = dateFormat + .replace('Y', 'yy') + .replace('m', 'mm') + .replace('d', 'dd'); + datepickerSettings.dateFormat = dateFormat; + // Add min and max date if set on the input. + if ($input.attr('min')) { + datepickerSettings.minDate = $input.attr('min'); + } + if ($input.attr('max')) { + datepickerSettings.maxDate = $input.attr('max'); + } + $input.datepicker(datepickerSettings); + }); + }, + /** + * Detach the behavior destroying datepickers on effected elements. + */ + detach: function (context, settings, trigger) { + if (trigger === 'unload') { + $(context).find('input[data-drupal-date-format].hasDatepicker').datepicker("destroy"); + } + } + }; + +})(jQuery, Modernizr, Drupal);