Skip to content

Commit

Permalink
#6 Parsing timezone for input-iso8601 has been implemented. All tests…
Browse files Browse the repository at this point in the history
… running, no more skips.
  • Loading branch information
nadnoslen committed Mar 13, 2017
1 parent cf1d800 commit a38bbac
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 46 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ go being all clever trying to do things that are already taken care of for you.
of the day. If set to `true`, this will take precedence over the `endOfDay` property.
* `endOfDay` - **COMING SOON** OPTIONAL, DEFAULT `false`.. When parsing dates, always set them to the last
second of the day.
* `timezone` - **COMING SOON** OPTIONAL, DEFAULT `moment.tz.guess()`. Dates will be parsed and formatted
* `timezone` - OPTIONAL, DEFAULT `moment.tz.guess()`. Dates will be parsed and formatted
in the specified timezone.
* _All the attributes from `ember-cli-text-support-mixins`' {{input-text}}._
See https://github.com/cybertoothca/ember-cli-text-support-mixins#arguments
Expand Down
34 changes: 22 additions & 12 deletions addon/components/input-date.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,37 @@ export default InputText.extend({
actions: {
parse(value) {
if (Ember.isBlank(value)) {
// the text representation of the date has been cleared
// clear error style-class
this.$().closest('.form-group').removeClass('has-error');
// the text representation of the date has been cleared; make sure the date behind the
// formatted value is set to null; this may trigger the `_setValue` observer if the `date`
// was not already null
Ember.trySet(this, 'date', null);
// set the `date` behind the now cleared value to null or if it is already null,
// trigger that the property changed anyway
if (this.get('date') === null) {
this.notifyPropertyChange('date');
} else {
Ember.trySet(this, 'date', null);
}
return true;
}

// attempt to parse the not blank string value to a date; if it can't parse `null` is returned
let parsedDate = Date.parsePlus(value);
if (parsedDate === null) {
// add the error style-class
this.$().closest('.form-group').addClass('has-error');
// force a notification that the `date` property changed, even if it stayed the same (could have
// been null multiple times)
this.notifyPropertyChange('date');
} else {
// clear error style-class
this.$().closest('.form-group').removeClass('has-error');
// date successfully parsed; now put it into the timezone assigned to this input
parsedDate = moment.tz(moment(parsedDate).toArray(), this.get('timezone')).toDate();
}
Ember.trySet(this, 'date', parsedDate);
// set the `date` property
if ((this.get('date') - parsedDate) === 0) {
// the date has not changed; however we want to force the date changed observer to fire anyway
this.notifyPropertyChange('date');
} else {
Ember.trySet(this, 'date', parsedDate);
}
return true;
}
},
Expand Down Expand Up @@ -70,6 +80,10 @@ export default InputText.extend({
this._super(...arguments);
this.send('parse', this.get('value'));
},
/**
* By default guess the client's timezone.
*/
timezone: moment.tz.guess(),
/**
* Don't assign anything to `value`. Instead pass a proper date into the component's `date` attribute.
* @private
Expand All @@ -82,10 +96,6 @@ export default InputText.extend({
id: 'input-date.deprecate-valueFormat',
until: '1.2.0'
}),
/**
* By default guess the client's timezone.
*/
timezone: moment.tz.guess(),
/**
* Every time the `date` property changes, attempt to format the `date` to the String value represented by
* the `displayFormat` mask. If the `date` is not present or is not of `date` type, the formatted value
Expand Down
76 changes: 64 additions & 12 deletions addon/components/input-iso8601.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,57 @@ import InputText from 'ember-cli-text-support-mixins/components/input-text';
export default InputText.extend({
actions: {
parse(value) {
const parsedDate = Date.parsePlus(value);
const iso8601 = Ember.isPresent(parsedDate) ? parsedDate.toISOString() : '';
Ember.trySet(this, 'iso8601', iso8601);
if (Ember.isBlank(value)) {
// the text representation of the date has been cleared
// clear error style-class
this.$().closest('.form-group').removeClass('has-error');
// set the `iso8601` behind the now cleared value to empty-string
// if it is already empty-string notify the iso8601 was changed
if (this.get('iso8601') === '') {
this.notifyPropertyChange('iso8601');
} else {
Ember.trySet(this, 'iso8601', '');
}
return true;
}

if (Ember.isPresent(parsedDate) || Ember.isBlank(value)) {
// attempt to parse the not blank string value to a date; if it can't parse `null` is returned
let parsedDate = Date.parsePlus(value);
let iso8601 = '';
if (parsedDate === null) {
// add the error style-class
this.$().closest('.form-group').addClass('has-error');
} else {
// clear error style-class
this.$().closest('.form-group').removeClass('has-error');
// date successfully parsed; now put it into the timezone assigned to this input
parsedDate = moment.tz(moment(parsedDate).toArray(), this.get('timezone'));
iso8601 = parsedDate.toISOString();
}
// set the `iso8601` property
if (this.get('iso8601') === iso8601) {
// the iso8601 has not changed; however we want to force the iso8601 observer to fire anyway
this.notifyPropertyChange('iso8601');
} else {
this.$().closest('.form-group').addClass('has-error');
Ember.trySet(this, 'iso8601', iso8601);
}

return true;
}
},
change() {
/**
* After `ESCAPE` is pressed and the text is cleared; immediately trigger a parse.
* @param event
* @param component
*/
afterClearAction(event, component) {
component.send('parse', '');
},
/**
* The textbox value changed; trigger a parse of the value.
* @param event
*/
change(event) { // jshint unused:false
this._super(...arguments);
this.send('parse', this.get('value'));
},
classNames: ['input-iso8601'],
Expand All @@ -30,13 +67,22 @@ export default InputText.extend({
*/
displayFormat: 'LL',
'enterWillSubmitForm?': false,
insertNewline(/*event*/) {
/**
* The user pressed enter in the text box; trigger a parse.
* @param event
*/
insertNewline(event) { // jshint unused:false
this._super(...arguments);
this.send('parse', this.get('value'));
},
/**
* REQUIRED. Initialize the date text box and bind it to your model, component, or controller.
*/
iso8601: '',
/**
* By default guess the client's timezone.
*/
timezone: moment.tz.guess(),
/**
* Don't assign anything to `value`. Instead pass a proper iso8601 date string into the component's `iso8601`
* attribute.
Expand All @@ -47,17 +93,23 @@ export default InputText.extend({
* @deprecated please use #displayFormat instead.
*/
valueFormat: Ember.computed.deprecatingAlias('displayFormat', {
id: 'input-date.deprecate-valueFormat',
id: 'input-iso8601.deprecate-valueFormat',
until: '1.2.0'
}),
/**
* Every time the `iso8601` property changes, attempt to format it to the String value matching
* the `displayFormat` mask. If `iso8601` is not present or is not of `date` type, the formatted value
* will be set to empty-string.
*/
_setValue: Ember.on('init', Ember.observer('iso8601', function () {
let value = null;
let formattedValue = '';
if (Ember.isPresent(this.get('iso8601'))) {
const parsedDate = new Date(this.get('iso8601'));
// try to format the date if it is present and resolved to a real date (finite)
if (Ember.isPresent(parsedDate) && isFinite(parsedDate)) {
value = moment(parsedDate).format(this.get('displayFormat'));
formattedValue = moment(parsedDate).tz(this.get('timezone')).format(this.get('displayFormat'));
}
Ember.trySet(this, 'value', value);
}
Ember.trySet(this, 'value', formattedValue);
}))
});
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
"loader.js": "^4.0.10"
},
"keywords": [
"datepickers",
"date picker",
"date chooser",
"momentjs",
"datejs",
"datejs-parse-plus",
Expand Down
1 change: 1 addition & 0 deletions tests/dummy/app/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Ember from 'ember';
export default Ember.Controller.extend({
dateAsParam: new Date().toISOString(),
dateWithTimezone: null,
iso8601WithTimezone: '',
naftaSigned: new Date(1987, 9, 3),
now: new Date(),
submittedIso8601: '',
Expand Down
1 change: 1 addition & 0 deletions tests/dummy/app/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export default Ember.Route.extend({
},
queryParams: {
dateAsParam: {refreshModel: false},
iso8601WithTimezone: {refreshModel: false},
submittedIso8601: {refreshModel: false},
wasEmptyUntilNow: {refreshModel: false}
}
Expand Down
20 changes: 19 additions & 1 deletion tests/dummy/app/templates/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export default Ember.Controller.extend({
</fieldset>
</div>


<div class="form">
<fieldset>
<legend>
Expand Down Expand Up @@ -396,6 +395,25 @@ export default Ember.Controller.extend({
</div>
</fieldset>
</div>

<div class="form">
<fieldset>
<legend>Specific Timezone In Query Parameter</legend>
<div class="form-group">
<label class="control-label">Choose A Date And See It In The URL</label>
{{input-iso8601 classNames="form-control" iso8601=iso8601WithTimezone displayFormat="llll z"
timezone='Pacific/Honolulu' placeholder="Try typing a date and then press enter."}}
<p class="help-block">
</p>
<div class="help-block">
<pre>\{{input-iso8601 classNames="form-control" iso8601=iso8601WithTimezone
displayFormat="llll z" timezone='Pacific/Honolulu'
placeholder="..."}}</pre>
</div>
</div>
</fieldset>
</div>

<form class="form" {{action (route-action "submitIso8601") on="submit"}}>
<fieldset>
<legend>Submitting In A Form</legend>
Expand Down
16 changes: 7 additions & 9 deletions tests/integration/components/input-date-test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* global moment */
import { moduleForComponent, test, skip } from 'ember-qunit';
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import wait from 'ember-test-helpers/wait';

moduleForComponent('input-date', 'Integration | Component | input date', {
integration: true
Expand Down Expand Up @@ -94,14 +93,13 @@ test('when parsing `sep 11 2001` to a date', function (assert) {
assert.equal(this.get('date').toString(), new Date(2001, 8, 11).toString());
});

// Cannot get this test to work; might need to do it with an acceptance test
skip('when typing `bla` the date is parsing fails silently', function (assert) {
this.render(hbs`{{input-date displayFormat="LL"}}`);
test('when typing `bla` the date parsing fails silently', function (assert) {
this.set('date', new Date(2001, 8, 11));
this.render(hbs`{{input-date date=date displayFormat="ll"}}`);
assert.equal(this.$('input').val(), 'Sep 11, 2001');
this.$('input')
.val('bla')
.trigger('change');
return wait().then(() => {
assert.equal(this.$('input').val(), '');
assert.equal(this.$().html(), '');
});
assert.equal(this.$('input').val(), '');
assert.equal(this.get('date'), null);
});
76 changes: 65 additions & 11 deletions tests/integration/components/input-iso8601-test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,51 @@
import { moduleForComponent, test, skip } from 'ember-qunit';
/* global moment */
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';

moduleForComponent('input-iso8601', 'Integration | Component | input iso8601', {
integration: true
});

test('when the default timezone is used for Sept 11 2001 at noon', function (assert) {
this.set('iso8601', new Date(2001, 8, 11, 12).toISOString());
this.render(hbs`{{input-iso8601 iso8601=iso8601 displayFormat="llll z"}}`);
assert.equal(this.$('input').val().trim(), moment(this.get('iso8601')).tz(moment.tz.guess()).format('llll z'));
});

test('when assigning a date for Sept 11 2001 at noon in New York', function (assert) {
this.set('iso8601', moment.tz([2001, 8, 11, 12], 'America/New_York').toISOString());
this.render(hbs`{{input-iso8601 iso8601=iso8601 displayFormat="llll z" timezone="America/New_York"}}`);
assert.equal(this.$('input').val().trim(), 'Tue, Sep 11, 2001 12:00 PM EDT');
});

test('when parsing a date for Sep 11, 2001 at 4pm in New York', function (assert) {
this.set('iso8601', null);
this.render(hbs`{{input-iso8601 iso8601=iso8601 displayFormat="llll z" timezone="America/New_York"}}`);
assert.equal(this.$('input').val().trim(), '');
this.$('input')
.val('sep 11 2001 4pm')
.trigger('change');
assert.equal(this.$('input').val().trim(), 'Tue, Sep 11, 2001 4:00 PM EDT');
assert.equal(this.get('iso8601'), '2001-09-11T20:00:00.000Z');
});

test('when assigning a date for Sept 11 2001 at noon in Vancouver', function (assert) {
this.set('iso8601', moment.tz([2001, 8, 11, 12], 'America/Vancouver').toISOString());
this.render(hbs`{{input-iso8601 iso8601=iso8601 displayFormat="llll z" timezone="America/Vancouver"}}`);
assert.equal(this.$('input').val().trim(), 'Tue, Sep 11, 2001 12:00 PM PDT');
});

test('when parsing a date for Sep 11, 2001 at 4pm in Vancouver', function (assert) {
this.set('iso8601', null);
this.render(hbs`{{input-iso8601 iso8601=iso8601 displayFormat="llll z" timezone="America/Vancouver"}}`);
assert.equal(this.$('input').val().trim(), '');
this.$('input')
.val('sep 11 2001 4pm')
.trigger('change');
assert.equal(this.$('input').val().trim(), 'Tue, Sep 11, 2001 4:00 PM PDT');
assert.equal(this.get('iso8601'), '2001-09-11T23:00:00.000Z');
});

test('when initializing with null the text value remains empty', function (assert) {
this.set('iso8601', null);
this.render(hbs`{{input-iso8601 iso8601=iso8601}}`);
Expand All @@ -30,21 +70,35 @@ test('when initializing with a date the text value formats to whatever format is
assert.equal(this.$('input').val().trim(), 'Sep 11, 2001');
});

skip('when clearing the value the date is set to null', function (assert) {
let sep11 = new Date(2001, 8, 11);
this.set('date', sep11);
this.render(hbs`{{input-date date=date displayFormat="ll"}}`);
test('when clearing the value the iso8601 property is set to empty string', function (assert) {
let sep11 = new Date(2001, 8, 11).toISOString();
this.set('iso8601', sep11);
this.render(hbs`{{input-iso8601 iso8601=iso8601 displayFormat="ll"}}`);
assert.equal(this.$('input').val().trim(), 'Sep 11, 2001');
this.$('input')
.val('')
.trigger('change');
assert.equal(sep11, '');
assert.notOk(Ember.isPresent(sep11), 'The sep11 variable should have been set to null after clearing the value');
assert.equal(this.get('iso8601'), '');
});

skip('when typing `blablabla` the date is parsing fails silently', function (/*assert*/) {
test('when parsing `sep 11 2001` to an iso8601 string', function (assert) {
this.set('iso8601', '');
this.render(hbs`{{input-iso8601 displayFormat="LL" iso8601=iso8601}}`);
assert.equal(this.get('iso8601'), '');
this.$('input')
.val('sep 11 2001')
.trigger('change');
assert.equal(this.$('input').val(), 'September 11, 2001');
assert.equal(this.get('iso8601'), new Date(2001, 8, 11).toISOString());
});

skip('when typing `sep 11 2001` the date is parsed and assigned ', function (/*assert*/) {
test('when typing `bla` the iso8601 parsing fails silently', function (assert) {
this.set('iso8601', new Date(2001, 8, 11).toISOString());
this.render(hbs`{{input-iso8601 iso8601=iso8601 displayFormat="ll"}}`);
assert.equal(this.$('input').val(), 'Sep 11, 2001');
this.$('input')
.val('bla')
.trigger('change');
assert.equal(this.$('input').val(), '');
assert.equal(this.get('iso8601'), '');
});

0 comments on commit a38bbac

Please sign in to comment.