Skip to content

Instantly share code, notes, and snippets.

@fhrbek
Last active May 5, 2016 12:23
Show Gist options
  • Save fhrbek/8c55788a4e6d4e9932368182d8784314 to your computer and use it in GitHub Desktop.
Save fhrbek/8c55788a4e6d4e9932368182d8784314 to your computer and use it in GitHub Desktop.
Datetime Range Picker - copy on change
import Ember from 'ember';
import DatetimeObject from '../datetime-input/datetime-object';
import DatetimeRangeObject from '../datetime-range-input/datetime-range-object';
export default Ember.Controller.extend({
appName: 'PE Datetime Range Selector Demo',
datetimeRange: DatetimeRangeObject.create(),
init () {
this.reset();
},
reset () {
var date = moment().utc(),
from, to;
to = date.format('YYYY-MM-DD [00:00]');
date.subtract(1, 'day');
from = date.format('YYYY-MM-DD [00:00]');
this.updateObject(this.get('datetimeRange'), {
'from': {
'timestamp': from
},
'to': {
'timestamp': to
}
});
},
updateObject: function (obj, diff) {
var properties = Object.keys(diff);
properties.forEach((property) => {
var value = diff[property],
orig = obj.get(property);
if (orig instanceof Ember.Object) {
if (Ember.Copyable.detect(orig)) {
orig = Ember.copy(orig);
obj.set(property, orig);
}
this.updateObject(orig, value)
} else {
obj.set(property, value);
}
});
},
actions: {
valueChanged: function (diff) {
this.updateObject(this.get('datetimeRange'), diff);
},
reset: function () {
this.reset();
}
}
});
import Ember from 'ember';
import DatetimeObject from './datetime-object';
export default Ember.Component.extend({
tagName: 'span',
datetimeObject: DatetimeObject.create(),
classNames: ['datetime-input'],
classNameBindings: ['workDatetimeObject.isValid::invalid'],
didReceiveAttrs () {
this._super(...arguments);
this.set('workDatetimeObject', DatetimeObject.create({
'timestamp': this.get('datetimeObject.normalizedTimestamp')
}));
},
sendChangeAction: function () {
this.sendAction('valueChangedAction', {'timestamp': this.get('workDatetimeObject.timestamp')});
},
actions: {
workValueChanged: function (timestamp) {
this.set('workDatetimeObject.timestamp', timestamp);
},
workValueConfirmed: function (timestamp) {
this.set('workDatetimeObject.timestamp', timestamp);
this.sendChangeAction();
},
onKeyDown: function (event) {
switch (event.keyCode) {
case 27:
this.sendAction('valueChangedAction', {'timestamp': this.get('datetimeObject.timestamp')});
case 13:
Ember.run.next( () => {
this.$('input').select();
});
break;
}
}
}
});
import Ember from 'ember';
var DatetimeObject = Ember.Object.extend(Ember.Copyable, {
/* BEGIN properties */
timestamp: '',
/* END properties */
normalFormat: 'YYYY-MM-DD HH:mm',
acceptedFormats: [
'YYYY',
'YYYYMM',
'YYYY-MM',
'YYYYMMDD',
'YYYY-MM-DD',
'YYYYMMDDHH',
'YYYY-MM-DD HH',
'YYYYMMDDHHmm',
'YYYY-MM-DD HH:mm',
'H',
'HA',
'H:m',
'H:mA'
],
copy: function (obj, deep) {
return DatetimeObject.create({
timestamp: this.get('timestamp')
});
},
parsedTimestamp: Ember.computed('timestamp', 'acceptedFormats', 'acceptedFormats.[]', function () {
var tstr = this.get('timestamp');
if (Ember.isBlank(tstr)) {
return null;
}
var result = moment(tstr, this.get('acceptedFormats'), true);
return result.isValid() ? result : false;
}),
normalizedTimestamp: Ember.computed('parsedTimestamp', 'normalFormat', function () {
var ts = this.get('parsedTimestamp');
if (ts !== false) {
if (ts === null) {
return null;
} else {
return ts.format(this.get('normalFormat'));
}
}
return this.get('timestamp');
}),
isValid: Ember.computed('timestamp', function () {
return this.get('parsedTimestamp') !== false;
})
});
export default DatetimeObject;
<input value={{workDatetimeObject.timestamp}} oninput={{action "workValueChanged" value="target.value"}} onchange={{action "workValueConfirmed" value="target.value"}} onkeydown={{action "onKeyDown"}}>
import Ember from 'ember';
import DatetimeRangeObject from './datetime-range-object';
export default Ember.Component.extend({
tagName: 'span',
datetimeRangeObject: DatetimeRangeObject.create(),
classNames: ['datetime-range-input'],
classNameBindings: ['datetimeRangeObject.isValid::invalid'],
actions: {
fromChanged: function (diff) {
this.sendAction('valueChangedAction', {'from': diff});
},
toChanged: function (diff) {
this.sendAction('valueChangedAction', {'to': diff});
}
}
});
import Ember from 'ember';
import DatetimeObject from '../datetime-input/datetime-object';
var DatetimeRangeObject = Ember.Object.extend(Ember.Copyable, {
/* BEGIN properties */
from: DatetimeObject.create(),
to: DatetimeObject.create(),
/* END properties */
copy: function (obj, deep) {
var from = this.get('from'),
to = this.get('to');
return DatetimeRangeObject.create({
from: deep ? Ember.copy(from, true) : from,
to: deep ? Ember.copy(to, true) : to
});
},
isValid: Ember.computed('from.timestamp', 'to.timestamp', function () {
var from = this.get('from'),
to = this.get('to');
return from.get('isValid') && to.get('isValid') &&
(from.get('parsedTimestamp') === null || to.get('parsedTimestamp') === null ||
from.get('parsedTimestamp').isSameOrBefore(to.get('parsedTimestamp')));
}),
err: Ember.computed('from.timestamp', 'to.timestamp', 'isValid', function () {
var from = this.get('from'),
to = this.get('to'),
err = '';
if (!from.get('isValid')) {
err += 'Timestamp from is not valid;';
}
if (!to.get('isValid')) {
err += 'Timestamp to is not valid;';
}
if (from.get('isValid') && to.get('isValid') && !this.get('isValid')) {
err = 'Individual timestamps are valid but the range is invalid';
}
return err;
})
});
export default DatetimeRangeObject;
{{datetime-input datetimeObject=datetimeRangeObject.from valueChangedAction="fromChanged"}}
<span class="delimiter">-</span>
{{datetime-input datetimeObject=datetimeRangeObject.to valueChangedAction="toChanged"}}
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
button {
margin-top: 1em;
}
label {
margin-right: 1em;
}
.datetime-range-input.invalid input,
.datetime-input.invalid input {
background-color: #ffaaaa;
}
.datetime-range-input .delimiter {
margin-left: .5em;
margin-right: .5em;
}
.info {
color: #bbb;
}
.error {
color: #f55;
}
<h1>{{appName}}</h1>
<br>
<br>
<label>Datetime range:</label>
{{datetime-range-input datetimeRangeObject=datetimeRange valueChangedAction="valueChanged"}}
<br>
<br>
{{#if datetimeRange.isValid}}
<div class="info">User wants data from <span class="fromDatetime">{{datetimeRange.from.normalizedTimestamp}}</span> to <span class="toDatetime">{{datetimeRange.to.normalizedTimestamp}}</span></div>
{{else}}
<div class="error">The selection is invalid: {{datetimeRange.err}}</div>
{{/if}}
<button {{action "reset"}}>Reset</button>
{
"version": "0.7.2",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": true,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.4.4/ember.debug.js",
"ember-data": "https://cdnjs.cloudflare.com/ajax/libs/ember-data.js/2.4.3/ember-data.js",
"ember-template-compiler": "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.4.4/ember-template-compiler.js",
"moment": "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.js"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment