ember-material-design-datepicker
Version:
A material design themed datepicker for Ember
376 lines (329 loc) • 12.1 kB
JavaScript
import Ember from 'ember';
import layout from '../templates/components/md-datepicker';
export default Ember.Component.extend({
layout,
classNames: ['md-datepicker-group'],
locale: null,
init() {
this.set('_viewingDate', null);
this.set('isDirty', false);
return this._super(...arguments);
},
didInsertElement() {
// Currently unable to get right click cut/paste to work, so disable right click for now
let self = this;
this.$('input').on('contextmenu', function() {
return false;
});
this.$('input').on('invalid', function(e) {
e.preventDefault();
self.set('isDirty', true);
});
return this._super(...arguments);
},
didReceiveAttrs() {
if ((this.get('mode') !== undefined) && (this.get('mode') !== 'date') && (this.get('mode') !== 'datetime')) {
throw new Error('Unknown mode ' + this.get('mode'));
}
this._super(...arguments);
},
dateText: Ember.computed('selectedDate', 'format', {
set(key, val) {
this.set('_dateText', val);
return val;
},
get() {
let dateText = null;
let _dateText = this.get('_dateText');
let selectedDate = this.get('selectedDate');
if (selectedDate) {
dateText = this.getMoment(selectedDate).format(this.get('format'));
}
else {
dateText = _dateText;
}
this.set('_dateText', dateText);
return dateText;
}
}),
isDateTime: Ember.computed('mode', function() {
if (this.get('mode') === 'datetime') {
return true;
}
}),
daySpans: Ember.computed('viewingDate', 'selectedDate', 'minDate', 'maxDate', 'hourOffset', function() {
let viewingDate = this.get('viewingDate');
let selectedDate = this.get('selectedDate');
let minDate = this.get('minDate');
let maxDate = this.get('maxDate');
let hourOffset = this.get('hourOffset');
let daySpans = Ember.A([]);
// Add blank days from Monday to the first day of the month
let firstDay = Number(this.getMoment(viewingDate).startOf('month').format('E'));
for (let i = 0; i < firstDay - 1; i++) {
daySpans.pushObject({ day: '', today: false, isSelectedDate: false, date: null, disabled: false });
}
// Populate for each day
let daysInMonth = this.getMoment(viewingDate).daysInMonth();
let today = this.getMoment();
for (let i = 0; i < daysInMonth; i++) {
let day = (i + 1);
let momentDate = this.getMoment(this.getMoment(viewingDate).startOf('month')).add(day - 1, 'days');
if (hourOffset) {
momentDate.add(hourOffset, 'hours');
}
let date = momentDate.toDate();
let isSelectedDate = false;
if (selectedDate) {
isSelectedDate = this.getMoment(selectedDate).isSame(date, 'day');
}
let disabled = false;
if (minDate && this.getMoment(minDate).isAfter(date, 'day')) {
disabled = true;
}
else if (maxDate && this.getMoment(maxDate).isBefore(date, 'day')) {
disabled = true;
}
let className = 'btn-date';
if (isSelectedDate) {
className = 'btn-date selected';
}
if (disabled) {
className += ' disabled';
}
daySpans.pushObject({ day: day.toString(), today: today.isSame(date, 'day'), isSelectedDate, date, className, disabled });
}
// Fill out remaining row
let lastDay = Number(this.getMoment(viewingDate).endOf('month').format('E'));
for (let i = lastDay; i < 7; i++) {
daySpans.pushObject({ day: '', today: false, isSelectedDate: false, date: null, disabled: false });
}
return daySpans;
}),
weekSpans: Ember.computed('daySpans.[]', function() {
let daySpans = this.get('daySpans');
let weekSpans = Ember.A([]);
let splitSize = 7;
for (let i = 0; i < daySpans.get('length'); i += splitSize) {
weekSpans.addObject({ daySpans: daySpans.slice(i, i + splitSize) });
}
return weekSpans;
}),
defaultErrorMessage: Ember.computed('format', 'required', 'dateText', 'isEarly', 'isLate', 'minDate', 'maxDate', function() {
let dateText = this.get('dateText');
if (this.get('required') && (dateText === undefined || dateText === null || dateText === '')) {
return 'Date is required';
}
let format = this.get('format');
if (this.get('isEarly')) {
return 'Date entered must be on or after ' + this.getMoment(this.get('minDate')).format(format);
}
if (this.get('isLate')) {
return 'Date entered must be on or before ' + this.getMoment(this.get('maxDate')).format(format);
}
return 'Invalid date, required format is ' + format;
}),
errorMessageShown: Ember.computed('errorMessage', 'isInvalidDate', function() {
return this.get('errorMessage.length') > 0 || this.get('isInvalidDate');
}),
format: Ember.computed('dateFormat', 'timeFormat', 'isDateTime', function() {
let dateFormat = this.get('dateFormat');
let timeFormat = this.get('timeFormat');
let result = 'MM/DD/YYYY';
if (dateFormat) {
result = dateFormat;
}
if (this.get('isDateTime')) {
if (timeFormat) {
result += timeFormat;
}
else {
result += ' HH:mm';
}
}
return result;
}),
isEarly: Ember.computed('dateText', 'minDate', 'format', 'useStrictMode', function() {
let dateText = this.get('dateText');
let minDate = this.get('minDate');
if (!minDate) {
return false;
}
return this.getMoment(dateText, this.get('format'), this.get('useStrictMode')).isBefore(this.getMoment(minDate), 'day');
}),
isLate: Ember.computed('dateText', 'maxDate', 'format', 'useStrictMode', function() {
let dateText = this.get('dateText');
let maxDate = this.get('maxDate');
if (!maxDate) {
return false;
}
return this.getMoment(dateText, this.get('format'), this.get('useStrictMode')).isAfter(this.getMoment(maxDate), 'day');
}),
isValidDate: Ember.computed('dateText', 'required', 'isDirty', 'isEarly', 'isLate', function() {
let dateText = this.get('dateText');
let notRequiredOrNotDirty = !this.get('required') || !this.get('isDirty');
if (notRequiredOrNotDirty && (dateText === undefined || dateText === null || dateText === '')) {
return true;
}
return this.getMoment(dateText, this.get('format'), this.get('useStrictMode')).isValid() && !this.get('isEarly') && !this.get('isLate');
}),
isInvalidDate: Ember.computed.not('isValidDate'),
mdClass: Ember.computed('inputClass', 'isValidDate', 'errorMessage', function() {
let result = '';
let inputClass = this.get('inputClass');
if (inputClass) {
result += inputClass;
}
if (this.get('isValidDate') && !this.get('errorMessage.length')) {
return result;
}
return result === '' ? 'invalid' : result + ' ' + 'invalid';
}),
placeholderClass: Ember.computed('dateText', function() {
if (this.get('dateText.length') > 0) {
return 'text-present';
}
return '';
}),
selectedDayMonth: Ember.computed('selectedDate', 'isInvalidDate', 'dateText', 'locale', function() {
let selectedDate = this.get('selectedDate');
let dateText = this.get('dateText');
if (selectedDate) {
return this.getMoment(selectedDate).format('ddd, MMM D');
}
if (this.get('isInvalidDate')) {
if (this.get('required') && (dateText === undefined || dateText === null || dateText === '')) {
return 'Date is required';
}
return 'Invalid date';
}
return '';
}),
viewingLongMonth: Ember.computed('viewingDate', 'locale', function() {
let viewingDate = this.get('viewingDate');
return this.getMoment(viewingDate).format('MMMM');
}),
viewingYear: Ember.computed('viewingDate', function() {
let viewingDate = this.get('viewingDate');
return this.getMoment(viewingDate).format('YYYY');
}),
selectedYear: Ember.computed('selectedDate', function() {
let selectedDate = this.get('selectedDate');
if (selectedDate) {
return this.getMoment(selectedDate).format('YYYY');
}
return '';
}),
selectedTime: Ember.computed('selectedDate', function() {
let selectedDate = this.get('selectedDate');
if (selectedDate) {
return this.getMoment(selectedDate).format('HH:mm');
}
return '';
}),
viewingDate: Ember.computed('selectedDate', {
set(key, val) {
this.set('_viewingDate', val);
return val;
},
get() {
let selectedDate = this.get('selectedDate');
let _viewingDate = this.get('_viewingDate');
if (selectedDate) {
_viewingDate = selectedDate;
}
else if (_viewingDate) {
return _viewingDate;
}
else {
_viewingDate = this.getMoment().toDate();
}
this.set('_viewingDate', _viewingDate);
return _viewingDate;
}
}),
useStrictMode: Ember.computed('relaxValidation', function() {
if (this.get('relaxValidation')) {
return false;
}
return true;
}),
weekDays: Ember.computed('locale', function() {
const locale = this.get('locale');
let days = Ember.A([]);
for (let i = 1; i < 8; ++i) {
days.pushObject(moment().isoWeekday(i).locale(locale).format('dd').toUpperCase()[0]);
}
return days;
}),
dropUpDownClass: Ember.computed('dropUp', function() {
return this.get('dropUp') ? 'drop-up' : 'drop-down';
}),
getMoment(date, format, useStrictMode) {
let datetime;
if (this.get('utc')) {
datetime = moment.utc(date, format, useStrictMode);
}
else {
datetime = moment(date, format, useStrictMode);
}
return datetime.locale(this.get('locale'));
},
actions: {
absorbMouseDown() {
// Used to retain focus in the input by absorbing mouse down 'clicks' on the datepicker that do not have explicit actions
},
dateClicked(dayspan) {
let date = dayspan.date;
let isValid = true;
// Preserve selected time
let selectedDate = this.get('selectedDate');
if (selectedDate) {
date.setHours(this.getMoment(selectedDate).format('HH'));
date.setMinutes(this.getMoment(selectedDate).format('mm'));
date.setSeconds(this.getMoment(selectedDate).format('ss'));
}
if (!dayspan.disabled) {
this.sendAction('dateChanged', dayspan.date, isValid);
if (this.get('clearErrorMessageOnChange')) {
this.set('errorMessage', null);
}
let autoHide = this.get('autoHideAfterSelection');
if (autoHide === undefined || autoHide === null) {
autoHide = true;
}
if (autoHide) {
this.$('input').blur();
}
}
},
downArrowClick() {
this.$('input').focus();
},
focusOut() {
this.set('isDirty', true);
},
keyUp() {
this.set('isDirty', true);
let dateText = this.get('dateText');
let isValid = this.get('isValidDate');
if (isValid && dateText !== undefined && dateText !== null && dateText !== '') {
let momentDate = this.getMoment(dateText, this.get('format'));
let hourOffset = this.get('hourOffset');
if (hourOffset) {
momentDate.add(hourOffset, 'hours');
}
this.sendAction('dateChanged', momentDate.toDate(), isValid);
}
else {
this.sendAction('dateChanged', null, isValid);
}
if (this.get('clearErrorMessageOnChange')) {
this.set('errorMessage', null);
}
},
monthToggle(value) {
this.set('viewingDate', this.getMoment(this.get('viewingDate')).add(Number(value), 'months').toDate());
}
}
});