Problem/Motivation

Implement the strategy we have in #1252178: Add Modernizr to core for date inputs.

Some browsers doesn't support the HTML 5 date input, so we need to add a JS fallback to support those.

This should improve the usability for people using there browsers (like firefox, IE) dramatically, as all people expect to get support entering a date with the correct format in a date field.

Note this issue it not about the design of the date picker in various core themes.

Proposed resolution

Add a JS falback using modenizr

Remaining tasks

User interface changes

API changes

Data model changes

Testing

Before patch

Use a browser that doesn't support html5 date input fields like firefox, result no datepicker available.

After patch

Use a browser that doesn't support html5 date input fields like firefox, result datepicker is now available.Use a browser that support html5 date input fields like Chrome, result native datepicker is still being used.

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task
Issue priority Major because this is really important for end users
Prioritized changes The main goal of this issue is usability
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nod_’s picture

Parts of the patch from #501428-50: Date and time field type in core. Parts of it are missing apparently, wasn't too careful during the extraction of this changes.

KarenS’s picture

FileSize
6.83 KB

That patch is missing things, it's more like this.

KarenS’s picture

FileSize
7.4 KB

Actually that's still missing things, it's this.

rupl’s picture

Status: Postponed » Active

Marking this active since #1252178: Add Modernizr to core is pending!

KarenS’s picture

And #1252178: Add Modernizr to core is committed! I'm not quite sure how to implement this, I'm hoping someone can provide a patch or example.

rupl’s picture

I can certainly help with the Modernizr part! Since this looks to be mainly JavaScript changes, you can access the relevant test by writing a conditional like so:

if (Modernizr.inputtypes.date) {
  // Rely on native support
}
else {
  // Summon the polyfill!
}

Or if you only want to cover the NOT:

if (!Modernizr.inputtypes.date) {
  // Polyfill code
}

You can see the full list of support within your browser by going to your browser's JS console and evaluating Modernizr.inputtypes. It will return an Object full of booleans corresponding to each test result. Here's the output I got from Chrome 23.0.1271.64 on OSX:

> Modernizr.inputtypes
  Object
    color: true
    date: true
    datetime: false
    datetime-local: false
    email: true
    month: false
    number: true
    range: true
    search: true
    tel: true
    time: true
    url: true
    week: false
klonos’s picture

Mark Trapp’s picture

Also coming from there. I've been maintaining Date Popup Authored, which was borne out of that issue, for d6 and d7, but all it really does is replace the Authored On textfield element with (contrib) Date's date_popup element (plus a few extra things to ensure Drupal gets the correct input).

Looks like this pretty much obsoletes the module for D8, am I right?

KarenS’s picture

Splitting the authored on field into HTML5 date and time elements is covered in #501428: Date and time field type in core. If the polyfill is added we'll also have a fallback to the jQuery datepicker. So yes, I think this will obsolete the Date Popup Authored module.

sun’s picture

Component: javascript » datetime.module
Issue tags: +JavaScript, +html5, +polyfill
webchick’s picture

Issue summary: View changes
Priority: Normal » Major
Status: Active » Needs review
FileSize
21.43 KB
7.88 KB

Hm. I think this (or another issue that covers this) might be major, or possibly critical...

Here's what a datetime field looks like on Chrome:

Lovely date picker

So far, so good...

But here's what it looks like in Firefox:

Two blank textfields

There's absolutely no guidance about what to do until you submit the form and get an error message. :(

Also, since there's a patch here, marking needs review.

nod_’s picture

Status: Needs review » Needs work
Related issues: +#2088383: Datetime FAPI DX

This should user Modernizr for feature detection.

And see #2088383: Datetime FAPI DX for the whole date input thing.

(and yay for collapsed text format!)

klonos’s picture

Parent issue: » #501428: Date and time field type in core
Sharique’s picture

Status: Needs work » Needs review
FileSize
6.64 KB

Trying to add jquery popup widget for date.

Sharique’s picture

Status: Needs review » Needs work

This is not working perfectly, I wasn't expecting tests to be passed, hoping failed test might be help find right path.

Sharique’s picture

Status: Needs work » Needs review
FileSize
3.14 KB

Here is updated patch, atleast jquery popup is working now.

googletorp’s picture

I've reposted the patch from #2467351: Add jQuery UI datepicker for the Date element of the datetime field here.

I've taken a very different approach than the current patch. The idea is to add a JS fallback to all date fields instead of creating a separate widget for it.

GaëlG’s picture

Status: Needs review » Reviewed & tested by the community

#17 works well on Firefox, and Chrome behavior is unchanged (Chrome natively handles the input type date). We needed #2467449: jQuery UI datepicker styles broken in Seven for datepicker styling.
There is no timepicker for hours and minutes, but I guess this is another issue?

The last submitted patch, 3: jquery-datepicker.patch, failed testing.

googletorp’s picture

googletorp’s picture

nod_’s picture

Status: Reviewed & tested by the community » Needs work

Sorry not there yet. New direction looks good though.

We don't use $.each, use a filtered for loop, better yet, see below for using data attribute.
The behavior needs a detach function
I would do the format translation in the JS side, in case someone wants to override the jquery ui lib and use their own stuff that has a different time format format.
We're trying to get rid of ids in the JS, can you put the date format in a data-drupal-date-format attribute (or something with a better name), like we're doing with #states? (see states.js and the data-drupal-states attribute).

Thanks!

googletorp’s picture

Assigned: Unassigned » googletorp

@nod_ Thanks for the review, I'll look into this

googletorp’s picture

Status: Needs work » Needs review
FileSize
5.16 KB
3.43 KB

I've followed the guidelines in #22, putting the settings on the element and adding a detach method to the behavior.

Status: Needs review » Needs work

The last submitted patch, 24: polyfill_date_input_type-1835016-24.patch, failed testing.

The last submitted patch, 24: polyfill_date_input_type-1835016-24.patch, failed testing.

googletorp’s picture

Status: Needs work » Needs review

So test bot is finally working again - ready for review :)

nod_’s picture

Status: Needs review » Needs work

Still an eslint error:

core/misc/date.js
  22:10  error  Split 'var' declaration into multiple statements  one-var
  1. +++ b/core/lib/Drupal/Core/Datetime/Element/Datetime.php
    @@ -267,6 +267,7 @@ public static function processDatetime(&$element, FormStateInterface $form_state
    +        '#date_date_format' => $element['#date_date_format'],
    
    +++ b/core/lib/Drupal/Core/Render/Element/Date.php
    @@ -37,11 +41,37 @@ public function getInfo() {
    +      $element['#attributes']['data-drupal-date-format'] = array($element['#date_date_format']);
    
    +++ b/core/misc/date.js
    @@ -0,0 +1,54 @@
    +          dateFormat = $(this).data('drupalDateFormat');
    ...
    +          dateFormat = dateFormat
    +            .replace('Y', 'yy')
    +            .replace('m', 'mm')
    +            .replace('d', 'dd');
    +          datepickerSettings.dateFormat = dateFormat;
    

    I've looked up the HTML5 spec, the format is hardcoded for the date field, no need to make it customizable or anything. We can just hardcode it

  2. +++ b/core/misc/date.js
    @@ -0,0 +1,54 @@
    +      if (Modernizr.inputtypes.date === false) {
    

    Let's inverse this and reduce nesting:

    if (Modernizr.inputtypes.date) {
      return;
    }
    
  3. +++ b/core/misc/date.js
    @@ -0,0 +1,54 @@
    +        $context.find('input[data-drupal-date-format]').each(function() {
    ...
    +        $(context).find('input[data-drupal-date-format].hasDatepicker')
    

    Since we don't need to have a configurable date format (the HTML5 spec say that the format is always yyyy-mm-dd) we can select input[type="date"]. It's also more in the spirit of a polyfill than relying on a data attribute.

  4. +++ b/core/misc/date.js
    @@ -0,0 +1,54 @@
    +          if ($(this).attr('min')) {
    

    you're reusing $(this) 5 times in the worst case. Let's put that in a variable like $input = $(this) and use that afterwards.

  5. +++ b/core/misc/date.js
    @@ -0,0 +1,54 @@
    +        $(context).find('input[data-drupal-date-format].hasDatepicker')
    +          .datepicker("destroy")
    +          .removeClass("hasDatepicker");
    

    Where does this class comes from? I would expect jquery ui to remove it on destroy.

    We have an api for that stuff:

    $(context).find('input[type="date"]').removeOnce('date-polyfill').datepicker('destroy');
    

    Makes me remember you need to use .once in the attach function.

googletorp’s picture

Regarding 1 + 3

Date fields, in core or contrib might allow that you enter the date in more than one way. Eventhough the format is hardcoded in html5 date fields, the format the the end users will see is localized. This means that the JavaScript fallback will stick out to the end users.
If we want this to be usable, we need to make it flexible. As I already have made one Drupal 8 site, where I implemeted a fallback JS datepicker, I know that this is a real requirement, which is important for some site owners.

I know we can save a few lines of code by not supporting this, but seeing how few countries actually support the Y-m-d date format (http://en.wikipedia.org/wiki/Date_format_by_country) I vote for making it configurable.

I've addressed the other issues in the review.

googletorp’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 31: polyfill_date_input_type-1835016-31.patch, failed testing.

googletorp’s picture

Seems patch from #31 was an interdiff as well - uploading the correct patch instead.

googletorp’s picture

Status: Needs work » Needs review
googletorp’s picture

I fixed a few lint issues, now I'm finally using the proper Drupal ESLint conf.

Status: Needs review » Needs work

The last submitted patch, 36: polyfill_date_input_type-1835016-36.patch, failed testing.

googletorp’s picture

Status: Needs work » Needs review
FileSize
5.28 KB
1.37 KB

Something went haywire in the last patch, so fixed that. Also fixed array using the short syntax instead.

mgifford’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

@googletorp - can you describe how to test this?

Unfortunately, it needs a reroll.

Nitesh Sethia’s picture

Assigned: googletorp » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
5.32 KB

Rerolled the patch successfully as per the latest D8 release.

googletorp’s picture

@mgifford To test this, you need to use a browser which doesn't support HTML 5 date fields and edit a date field (fx node creation time).

Before the patch, you need to enter the date by hand, after the patch the jQuery datepicker should be used. You should also test that the jQuery datepicker is not used for browsers that do support native HTML5 date field.

Firefox doesn't support, but chrome does (last time I tested)

droplet’s picture

Issue summary: View changes
FileSize
29.08 KB

I'm an unluckily developer, my clients always blame me and asked "WHY THIS IS DIFFERENT STYLE!!!"

+++ b/core/misc/date.js
@@ -0,0 +1,55 @@
+      if (Modernizr.inputtypes.date === true) {

We should add an option here to save all unluckily developers

mpdonadio’s picture

This will need an IS and Beta update to it before we can proceed to RTBC. How to test will also need to be added to the IS.

googletorp’s picture

Issue summary: View changes
googletorp’s picture

Issue summary: View changes
googletorp’s picture

Added beta evaluation, and better issue summary including how to test.

mpdonadio’s picture

Thanks @googletorp. I'll do manual testing tonight, but I think this is good to go and will improve UX.

@droplet, what did you have in mind? I think normalizing the appearance is definitely out of scope for this issue, though.

andypost’s picture

+++ b/core/misc/date.js
@@ -0,0 +1,55 @@
+      // Skip if date are supported by the browser.
+      if (Modernizr.inputtypes.date === true) {

it makes sense to file follow-up for "time" that firefox still have no support

mpdonadio’s picture

Status: Needs review » Needs work
Issue tags: +Needs manual testing

OK, got a close look at this. The patch works well, and I think this will be a good addition. I verified it with fields from the DateTime module, as well as timestamp fields (eg, created on entities), and it works as described. Since this works w/ DateTime uninstalled on timestamps only, having the JS live in core/misc/ is a good idea.

  1. +++ b/core/lib/Drupal/Core/Datetime/Element/Datetime.php
    @@ -267,7 +267,7 @@ public static function processDatetime(&$element, FormStateInterface $form_state
    -        '#error_no_message' => TRUE,
    +        '#date_date_format' => $element['#date_date_format'],
    

    I am a little confused why this was there in the first place, but why does the patch remove this line?

  2. +++ b/core/lib/Drupal/Core/Render/Element/Date.php
    @@ -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
    

    I think this comment is misplaced. Nothing in getInfo() changed. Perhaps this should be added to processDate() instead?

  3. +++ b/core/lib/Drupal/Core/Render/Element/Date.php
    @@ -26,14 +27,38 @@ class Date extends FormElement {
    +  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'])) {
    
  4. The comment here is a little cryptic. JS support for what? Maybe when combined with the comment above, a description can be added to processDate, that reads something like "If the element is an HTML5 date a date format is provided, then the necessary attributes are added to enable the jQuery UI Datepicker on the element."

Should be easy to fix, and then I think this is RTBC.

mpdonadio’s picture

Still trying to triage all of these issues, some of which are pretty old...

But re #48 we already have #1838234: Add jQuery Timepicker for the Time element of the datetime field.

googletorp’s picture

Status: Needs work » Needs review
FileSize
5.34 KB
2.12 KB

@mpdonadio Thanks for the feedback.

#1 I think this is an error, nice catch, reintroduced the deleted line.
#2 I reworded the comment a bit, to make it more clear.
#3 Same as 2, tried to make the comment a bit more clear.

mpdonadio’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

I think this is good to go. Manual testing w/ Firefox 38.0.5 on OSX 10.10 (latest version as of 2015/06/24) was fine. Removed a bit from the IS that doesn't seem to apply to the patch anymore (datepicker in Seven works fine for me).

nod_’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
5.43 KB
2.58 KB

updated the docs according to documenting behaviors (it's brand new, you didn't miss anything :)

Used .once instead of classes, since that's what should be used to do this. and simplified a bit the use of dateFormat in the js.

googletorp’s picture

Status: Needs review » Reviewed & tested by the community

I've tested this manually and reviewed the patch changes, looks good to me, RTBC imo.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed b04d55e and pushed to 8.0.x. Thanks!

Thanks for adding the beta evaluation to the issue summary.

  • alexpott committed b04d55e on 8.0.x
    Issue #1835016 by googletorp, nod_, KarenS, Sharique, Nitesh Sethia,...
TR’s picture

This change is causing the testbot to generate some exceptions for my tests:

"Undefined index: type Notice Date.php 58 Drupal\Core\Render\Element\Date::processDate()"

I don't see any mention above about API changes that would require me to do something different in my own code that uses a date form element, and I don't see anything above that mentions impact on contrib. (And in fact there's really no documentation on the date form element to begin with ...) processDate() was added by this patch, thus it's not something I invoke directly.

So maybe a change record to tell contrib developers what they need to change because of this patch?

mpdonadio’s picture

googletorp’s picture

@TR can you post in the some info about what you are doing that is generating notices, the root cause could be both core and in your contrib project.

TR’s picture

Crossposting from #2528482: Fix notice in Date::processDate ..

To reproduce, create a form with this element:

    $form['adate'] = array(
      '#type' => 'date',
      '#description' => $this->t('Enter a date.'),
      '#default_value' => '',
    );

Just visit the form, no need to submit. The notice will be shown in /admin/reports/dblog.

The nasty-looking HTML generated by this is:

      <form class="datetest-settings-form" data-drupal-selector="datetest-settings-form" action="/admin/people/datetest" method="post" id="datetest-settings-form" accept-charset="UTF-8">
  <div class="form-item js-form-type-date form-type-date form-item-adate form-no-label">
        <input data-drupal-selector="edit-adate" aria-describedby="edit-adate--description" type="date" id="edit-adate" name="adate" value="" class="form-date" />

            <div id="edit-adate--description" class="description">
      Enter a date.
    </div>
  </div>
<input data-drupal-selector="form-blof8rbyocufy2s5dlrfnl3i53jfkgztigfbh2dwqms" type="hidden" name="form_build_id" value="form-blOf8RBYocuFY2S5dLrfnL3i53JfKGztIgfBH2DwQMs" />
<input data-drupal-selector="edit-datetest-settings-form-form-token" type="hidden" name="form_token" value="LC0uSawhPy7bdWDq90CauOpNmlAs_gPngeCmKGkvbtk" />
<input data-drupal-selector="edit-datetest-settings-form" type="hidden" name="form_id" value="datetest_settings_form" />
<div data-drupal-selector="edit-actions" class="form-actions js-form-wrapper form-wrapper" id="edit-actions"><input data-drupal-selector="edit-submit" type="submit" id="edit-submit" name="op" value="Save configuration" class="button button--primary js-form-submit form-submit" />
</div>


</form>
TR’s picture

Oh, and the datepicker doesn't work with this example either ...

mpdonadio’s picture

No need to crosspost; that is what the followup is for. We will work through it there. Thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.