Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow multiple input formats, add onClear callback for better Ember/Knockout/etc integration and allow other date libraries instead of Moment.js #134

Closed
wants to merge 7 commits into from

Conversation

bjbrewster
Copy link

Thanks for creating this awesome and yet simple date picker. We are using this library on a fundraising portal raising money for charity so know that its helping make a difference in the world. We needed a few changes to make it easier to integrate with Ember.js so I would like to contribute back to your project.

This change is loosely based on #57 to add callback on clear/invalid date and also fixes #61, #48, #15, #93, #98. I decided upon onClear for the name of the callback, in the same vein as onSelect, named after the method clearDate() that I extracted from setDate(). Feel free to suggest better names. It was very tempting to call onSelect callback with null for empty/invalid date, but this would most likely break a lot of code by the Pikaday community that relies on the callback always having a valid date so a new callback must be introduced instead. I would also like to add a suite of automated JS tests to improve code quality.

  • Cleaned up setDate() so both null date and invalid date string clear the current selection.
  • Extracted clearDate() method from setDate() for clearing the current selection with options for clearing the input field (if set) and preventing onClear callback.
  • onClear callback is called by clearDate() so users can be notified of invalid/empty date. The user's callback can get the field text value to show a required validation message if empty or invalid date validation message if not empty.
  • onSelect and onClear are useful when integrating with MVC frameworks such as Knockout.js and Ember.js where onSelect and onClear sets and clears the binding/component's date value.
  • Added examples for Knockout (knockout.js integration #48) and Ember.
  • clearInvalidInput option can be set to true to automatically clear the input field value (if field is set) on invalid input. This is a simple way of telling the user the entered date is invalid.
  • parseDate() method was extracted from _onInputChange() to remove duplicate date string parsing in Pikaday constructor for defaultDate and in setDate() (was only parsing with JS Date.parse?).
  • parseDate() method was added to Pikaday prototype instead of a helper/private method to allow for overriding both toString() and parseDate() on Pikaday.prototype to support other JS date libraries.
    See Datejs and Sugar examples.
  • Fixed issue Set blank default date #98 with Datejs where Date.parse() returns null instead of NaN for invalid input which caused a default date of 1/1/1970 in empty input fields.
  • A big feature of Moment.js is that it allows for multiple input formats. inputFormats option was added to allow users to specify an array of allowed input formats. Defaults to the display format. Moment example updated accordingly.
  • Added fix for issue wrong month shown when setting minDate to a later year #93 where wrong month is sometimes shown when minDate's year > default selected date. There's a separate issue where setMinDate does not update the internal min/maxMonth and min/maxYear used in draw method.
  • README updated accordingly (including defaultDate expected type Format of defaultDate #15)

- Cleaned up `setDate()` so both null date and invalid date string
clear the current selection.
- Extracted `clearDate()` method from `setDate()` for clearing the
current selection with options for clearing the input field (if set)
and preventing `onClear` callback.
- `onClear` callback is called by `clearDate()` so users can be
notified of invalid/empty date. The user's callback can get the field
text value to show a required validation message if empty or invalid
date validation message if not empty.
- `onSelect` and `onClear` are useful when integrating with MVC
frameworks such as Knockout.js and Ember.js where `onSelect` and
`onClear` sets and clears the component's date value.
- `clearInvalidInput` option can be set to `true` to automatically
clear the input field value (if `field` is set) on invalid input.
@@ -580,7 +608,33 @@
*/
toString: function(format)
{
return !isDate(this._d) ? '' : hasMoment ? moment(this._d).format(format || this._o.format) : this._d.toDateString();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I hate seeing nested ternary operators on a single line.

@bjbrewster bjbrewster changed the title Add onClear callback and clearInvalidInput option Add onClear, clearInvalidInput, and inputFormats options and parseDate method Mar 25, 2014
@@ -79,6 +79,7 @@ Pikaday has many useful options:
* `bound` automatically show/hide the datepicker on `field` focus (default `true` if `field` is set)
* `position` preferred position of the datepicker relative to the form field, e.g.: `top right`, `bottom right` **Note:** automatic adjustment may occur to avoid datepicker from being displayed outside the viewport, see [positions example][] (default to 'bottom left')
* `format` the default output format for `.toString()` and `field` value (requires [Moment.js][moment] for custom formatting)
* `inputFormats` optional array of allowed input formats for `field` value and `.setDate()` with string (requires [Moment.js][moment] for custom parsing). **Note:** The default output `format` will be added to `inputFormats` if not already included. See the [moment.js example][] for example usage.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also thinking of parseFormats for this option name as it is used by parseDate() and seemed more explicit. Feel free to suggest better names for any of these option and method names etc.

Brendan Brewster added 2 commits March 27, 2014 23:22
- `parseDate()` method was extracted from `_onInputChange()` to remove
duplicate date string parsing in Pikaday constructor for `defaultDate`
and in `setDate()` (was only parsing with JS Date.parse?).
- `parseDate()` method was added to Pikaday prototype instead of a
helper/private method to allow for overriding both `toString()` and
`parseDate()` to support other JS date libraries. See Sugar example.
- A big feature of Moment.js is that it allows for multiple input
formats. `inputFormats` option was added to allow users to specify
an array of allowed input formats. Defaults to the display format.
Moment example updated accordingly.
@bjbrewster bjbrewster changed the title Add onClear, clearInvalidInput, and inputFormats options and parseDate method Allow multiple input formats, add onClear callback for better Ember/Knockout/etc integration and allow other date libraries instead of Moment.js Mar 27, 2014
@@ -233,7 +244,7 @@ Hide the picker making it invisible.

Hide the picker and remove all event listeners — no going back!

### Internationalization
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't think this section belonged under the Methods heading

Brendan Brewster added 2 commits March 28, 2014 16:33
- Added expected type of `defaultDate` option similar to `minDate` and
`maxDate` to remove confusion (Pikaday#15).
The wrong month is sometimes shown when minDate  year > default date's

From the issue's description:
When you set minDate for a date after the currently selected date, the calendar, when shown, should display the month where minDate is. This works if both dates are in the same year, but if the new minDate's year is greater than the selected one, the month shown will be a mix of the selected date's month with the minDate's year.

There is a separate issue in that `setMinDate` and `setMaxDate` do not
update the min/maxMonth and min/maxYear internal options.
this._m = minMonth;
}
this._m = minMonth;
} else if (this._y == minYear && !isNaN(minMonth) && this._m < minMonth) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this is checking if min/maxMonth isNan? As far as I can tell, the config function checks the min and max dates are valid dates before extracting the min and max months. I think minMonth and maxMonth should be defaulted to 0 and 11 instead of undefined, however.

This was referenced Mar 30, 2014
@@ -11,7 +11,7 @@ Pikaday

![Pikaday Screenshot][screenshot]

**Production ready?** Since version 1.0.0 Pikaday is stable and used in production. If you do however find bugs or have feature requests please submit them to the [GitHub issue tracker][issues].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces on the eol are significant in markdown.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I wasn't sure about this. I'll fixup the README accordingly. Any other feedback? :-)

@rikkert
Copy link
Member

rikkert commented Apr 8, 2014

Do you mind rebasing from master?

@bjbrewster
Copy link
Author

Sure. I'm almost done adding some Mocha tests too.

On Tue, Apr 8, 2014 at 4:23 PM, Ramiro Rikkert notifications@github.comwrote:

Do you mind rebasing from master?

Reply to this email directly or view it on GitHubhttps://github.com//pull/134#issuecomment-39815402
.

Datejs replaces the native Date.parse method with one that understands
basic natual language. Unfortunately, it returns a Date object or null
on error unlike the native Date.parse method that returns milliseconds
since the UNIX epoch 1/1/1970 or NaN on error that Pikaday relied on.

- I have updated the parseDate method to check the result of
Date.parse instead of using it immediately in a new Date constructor
- A Datejs example has been added and the README updated accordingly
- Sugar.js example also updated to support format option and remove
mention of customising single Pikaday instance due to bug with Pikaday
constructor parsing default value string from field with normal
parseDate before it could be updated by user with this method. This
would require a new config option for custom formatter and parser for
Pikaday instance.
- README also updated to fix Knockout link and Javascript renamed to
JavaScript for consistency
@bjbrewster
Copy link
Author

I've just come back from holidays so I'll get back on top of this PR and hope to have it done soon. I'll put up an early example of the test framework I've made to see if it's on the right track.

@rikkert
Copy link
Member

rikkert commented Apr 28, 2014

I have a test suite ruining trough testing.
Could you already push your tests on your fork so I could move these in already?
Thanks!

@bjbrewster
Copy link
Author

I used Mocha as you asked and created a tests folder with a pikaday.html file with the following:

<html>
<head>
  <meta charset="utf-8">
  <title>Pikaday Tests</title>
  <link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
</head>
<body>
  <div id="mocha"></div>
  <script src="../node_modules/mocha/mocha.js"></script>
  <script src="../node_modules/should/should.js"></script>
  <script src="../pikaday.js"></script>
  <script>
    mocha.setup('bdd')

    describe('Pikaday', function() {
      describe('#toString()', function() {
        it('should return empty string when date not set', function() {
          var pikaday = new Pikaday();
          pikaday.toString().should.equal('');
        })

        it('should return date string when date is set', function() {
          var date = new Date('2014-04-25');
          var pikaday = new Pikaday();
          pikaday.setDate(date);
          pikaday.toString().should.equal(date.toDateString());
        })
      })

      describe('#getDate()', function() {
        it('', function() {
        })
      })

      describe('#setDate()', function() {
        it('', function() {
        })
      })

      describe('#clearDate()', function() {
        it('', function() {
        })
      })

      describe('#parseDate()', function() {
        it('', function() {
        })
      })

      describe('#gotoDate()', function() {
        it('', function() {
        })
      })

      ...
    })

    mocha.checkLeaks();
    mocha.globals(['jQuery']);
    mocha.run();
  </script>
</body>
</html>

I wasn't sure how to have an html test file that uses Moment and one without Moment. Including pikaday.js automatically includes Moment.js as it finds the exports interface from Node.js (as used by Mocha) and auto loads it. So I was going to flesh out this html test suite assuming Moment.js was available. I couldn't find any other way of running client-side feature tests using Mocha. Writing standard js unit tests with Mocha and run at the command line complain about missing objects and methods such as window.addEventListener.

Was this the kind of test suite and setup you had in mind with Mocha?

@rikkert
Copy link
Member

rikkert commented Apr 30, 2014

Check out the test framework and test stubs that I added.
They run using mocha / expect.js / browserify / testling.
Is it possible to split out this PR to smaller ones that include tests and docs?

@bjbrewster
Copy link
Author

Sure, i can do that. Am busy with work this week so will continue on the
weekend. Thanks for adding the test stubs, that will make my life easier.

On Thursday, 1 May 2014, Ramiro Rikkert notifications@github.com wrote:

Check out the test framework and test stubs that I added.
They run using mocha / expect.js / browserify / testling.
Is it possible to split out this PR to smaller ones that include tests and
docs?


Reply to this email directly or view it on GitHubhttps://github.com//pull/134#issuecomment-41831870
.

@bjbrewster
Copy link
Author

@rikkert How do I create multiple PRs for Pikaday from my bjbrewster/Pikaday fork? I guess I could fork Pikaday multiple times or scale back my single PR to a smaller set of fixes and once you've merged that I can create another PR etc?

@rikkert
Copy link
Member

rikkert commented Jun 30, 2014

Easiest is to make a new branch for each PR of the relevant commit.
After you can create a new PR using that branch.
Would be great to get this ball rolling again.

@mhkeller
Copy link

Have these been merged somewhere or is this still in the works? I would love to start using some of these features.

@bjbrewster
Copy link
Author

Hello,

I got a bit lost regarding creating many PRs from my own repo. I'll try to
get the ball rolling again and see this through.

Cheers,
Bren

On Fri, Sep 12, 2014 at 12:00 PM, Michael Keller notifications@github.com
wrote:

Have these been merged somewhere or is this still in the works? I would
love to start using some of these features.


Reply to this email directly or view it on GitHub
#134 (comment).

@mhkeller
Copy link

Great! In the meantime I'm just using your fork.

I have one suggestion: when you call clearDate in my use case it's also be desirable to clear the min and max date. Perhaps that could be integrated into that method.

EDITED to remove the question on a proper way to clear min and max time since I just figured it out.

@bjbrewster
Copy link
Author

Not sure if clearDate() should also clear the min and max dates. That should be separate method(s) in my opinion. clearDate() is more for clearing the selected date, which shouldn't affect the min/max validation.

@mhkeller
Copy link

Ya it might not be for everybody. I'm setting the min/max more dynamically based on what the user has filled into the other box as opposed to hard limits for the page's state. Perhaps it's an argument the same way you have a boolean for clearing the display. But, again, if it's a small use case, setting it in the callback is easy enough.

@drewcovi
Copy link

So is this PR dead?

@mhkeller
Copy link

I still think it's an improvement.

@mazing
Copy link

mazing commented Dec 28, 2015

Great PR. Why isn't it accepted?

@jaconi
Copy link

jaconi commented Dec 31, 2015

I find this PR very useful. Any chances it will be accepted?

@gliesche
Copy link

+1

@foohooboo
Copy link

@bjbrewster @mhkeller Is this PR dead? Is it safe to replace into my existing code that is already using the current pikaday? The functionality I'm wanting is the multiple input formats.

@rikkert
Copy link
Member

rikkert commented Jun 29, 2017

Yes, use the parse and toString method that have been added.

@rikkert rikkert closed this Jun 29, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update maxDate() and Clear options?
8 participants