From e4455e28b0fdd3186819804d1eedde5915a97230 Mon Sep 17 00:00:00 2001 From: Vavooon Date: Fri, 28 Apr 2017 10:35:20 +0300 Subject: [PATCH] Max and min allowed dates support --- lib/js/index.js | 122 ++++++++++++++++++++++++- lib/scss/material-datetime-picker.scss | 13 ++- 2 files changed, 130 insertions(+), 5 deletions(-) diff --git a/lib/js/index.js b/lib/js/index.js index 9b803cf..4582aa1 100644 --- a/lib/js/index.js +++ b/lib/js/index.js @@ -59,6 +59,19 @@ class DateTimePicker extends Events { this.options.el.dispatchEvent(event); } }); + + if (this.options.startDate || this.options.endDate) { + this.startDate = this.options.startDate || moment(0); + this.endDate = this.options.endDate || moment(8640000000000000); + + this.dateValidator = (date) => { + return !this.startDate.clone().startOf('day').isAfter(date) && !this.endDate.clone().endOf('day').isBefore(date); + }; + + this.timeValidator = (date) => { + return !this.startDate.isAfter(date) && !this.endDate.isBefore(date); + }; + } } // intialize the rom calendar with our default date and @@ -91,13 +104,13 @@ class DateTimePicker extends Events { // and deal with updating the view only). // For now this allows us to set the default time using the same quantize // rules as setting the date explicitly. Setting this.value meets setTime|Date's - // expectation that we have a value, and `0` guarantees that we will detect + // expectation that we have a value, and `0` guarantees that we will detect this.value = moment(0); this.setDate(this.options.default); this.setTime(this.options.default); } - this.initializeRome(this.$(`.${this.options.styles.container}`), this.options.dateValidator); + this.initializeRome(this.$(`.${this.options.styles.container}`), this.dateValidator); this._show(); } @@ -127,6 +140,10 @@ class DateTimePicker extends Events { return this; } + _dateIsBetween(startDate, endDate, date) { + return !startDate.isAfter(date) && !endDate.isBefore(date); + } + delegateEvents() { this.$('.js-cancel') .addEventListener('click', () => this.clickCancel(), false); @@ -201,6 +218,18 @@ class DateTimePicker extends Events { return this; } + setDateInsideLimits() { + if (this.startDate) { + if (this.startDate.isAfter(this.value)) { + this.set(this.startDate); + } + + if (this.endDate.isBefore(this.value)) { + this.set(this.endDate); + } + } + } + onChangeDate(dateString) { const newValue = moment(this.value); const [year, month, date] = dateString.split('-'); @@ -242,6 +271,69 @@ class DateTimePicker extends Events { } } + disableDateOptions(type) { + if (this.timeValidator) { + switch (type) { + case 'ampm': { + if (this.startDate || this.endDate) { + const amStart = this.value.clone().startOf('day'); + const amEnd = amStart.clone().add(12, 'hours').add(-1, 'minutes'); + + const pmStart = amStart.clone().add(12, 'hours'); + const pmEnd = pmStart.clone().add(12, 'hours').add(-1, 'minutes'); + + if (this._dateIsBetween(this.startDate, this.endDate, amStart) + || this._dateIsBetween(this.startDate, this.endDate, amEnd)) { + this.$('.c-datepicker__clock__am-pm-toggle label')[0].setAttribute('disabled', ''); + } else { + this.$('.c-datepicker__clock__am-pm-toggle label')[0].setAttribute('disabled', 'disabled'); + } + + if (this._dateIsBetween(this.startDate, this.endDate, pmStart) + || this._dateIsBetween(this.startDate, this.endDate, pmEnd)) { + this.$('.c-datepicker__clock__am-pm-toggle label')[1].setAttribute('disabled', ''); + } else { + this.$('.c-datepicker__clock__am-pm-toggle label')[1].setAttribute('disabled', 'disabled'); + } + } + break; + } + case 'hours': { + let hoursOffset = 0; + if (this.meridiem === 'pm') { + hoursOffset = 12; + } + + const hours = this.$('.c-datepicker__clock__hours .c-datepicker__clock__num'); + for (let i = 0; i < hours.length; i += 1) { + const date = this.value.clone().startOf('hour').hour(parseInt(hours[i].getAttribute('data-number'), 10) + hoursOffset); + if (this.timeValidator(date)) { + hours[i].classList.remove('c-datepicker__clock__num--disabled'); + } else { + hours[i].classList.add('c-datepicker__clock__num--disabled'); + } + } + break; + } + case 'minutes': { + const minutes = this.$('.c-datepicker__clock__minutes .c-datepicker__clock__num'); + for (let i = 0; i < minutes.length; i += 1) { + const date = this.value.clone().minute(minutes[i].getAttribute('data-number')); + if (this.timeValidator(date)) { + minutes[i].classList.remove('c-datepicker__clock__num--disabled'); + } else { + minutes[i].classList.add('c-datepicker__clock__num--disabled'); + } + } + break; + } + default: + break; + } + } + return this; + } + clickAm() { const newValue = moment(this.value); if (this.meridiem === 'pm') { @@ -249,6 +341,8 @@ class DateTimePicker extends Events { newValue.hour(newValue.hour() - 12); } this.set(newValue); + this.disableDateOptions('hours'); + this.disableDateOptions('minutes'); return this; } @@ -259,6 +353,8 @@ class DateTimePicker extends Events { newValue.hour(newValue.hour() + 12); } this.set(newValue); + this.disableDateOptions('hours'); + this.disableDateOptions('minutes'); return this; } @@ -268,6 +364,7 @@ class DateTimePicker extends Events { this.$('.js-clock-minutes').classList.remove('active'); this.$('.js-date-hours').classList.add('active'); this.$('.js-date-minutes').classList.remove('active'); + this.disableDateOptions('hours'); } showMinuteClock() { @@ -276,6 +373,7 @@ class DateTimePicker extends Events { this.$('.js-clock-minutes').classList.add('active'); this.$('.js-date-hours').classList.remove('active'); this.$('.js-date-minutes').classList.add('active'); + this.disableDateOptions('minutes'); } clickShowCalendar() { @@ -286,6 +384,7 @@ class DateTimePicker extends Events { clickShowClock() { this.$('.js-show-clock').classList.add('is-selected'); this.$('.js-show-calendar').classList.remove('is-selected'); + this.disableDateOptions('ampm'); } data(val) { @@ -311,8 +410,8 @@ class DateTimePicker extends Events { ) { this.setDate(m); evts.push('change:date'); - } - + } + if (m.hour() !== this.value.hour() || m.minutes() !== this.value.minutes() ) { @@ -352,6 +451,7 @@ class DateTimePicker extends Events { this.value.year(m.year()); this.value.month(m.month()); this.value.date(m.date()); + this.setDateInsideLimits(); return this; } @@ -388,6 +488,7 @@ class DateTimePicker extends Events { this.value.hours(m.hours()); this.value.minutes(m.minutes()); this.meridiem = this.value.format('a'); + this.setDateInsideLimits(); if (this.meridiem === 'pm') { this.amToggleEl.removeAttribute('checked'); @@ -400,6 +501,19 @@ class DateTimePicker extends Events { this.pmToggleEl.parentElement.classList.remove('c-datepicker__toggle--checked'); this.amToggleEl.parentElement.classList.add('c-datepicker__toggle--checked'); } + + return this; + } + + // set minimum allowed time date to select + setStartDate(date) { + this.startDate = moment(date); + return this; + } + + // set maximum allowed time date to select + setEndDate(date) { + this.endDate = moment(date); return this; } diff --git a/lib/scss/material-datetime-picker.scss b/lib/scss/material-datetime-picker.scss index 76a418f..ac4efe6 100644 --- a/lib/scss/material-datetime-picker.scss +++ b/lib/scss/material-datetime-picker.scss @@ -238,6 +238,7 @@ $primary: #00bcd4 !default; cursor: pointer; } +.c-datepicker__day--disabled, .rd-day-prev-month { opacity: 0.1; pointer-events: none; @@ -315,6 +316,11 @@ $primary: #00bcd4 !default; display: none; } +.c-datepicker__clock__num--disabled { + opacity: 0.1; + pointer-events: none; +} + @mixin putOnCircle( $nb-items, //Number of items $circle-size, //Parent size @@ -425,7 +431,7 @@ $primary: #00bcd4 !default; -.c-datepicker__day-body, .c-datepicker__clock__num { +.c-datepicker__day-body:not(.c-datepicker__day--disabled), .c-datepicker__clock__num { @extend .u-hover-ball-effect; &--active:not(.hide-hand) { @@ -538,6 +544,11 @@ $primary: #00bcd4 !default; padding: 20px; line-height: 40px; + label[disabled="disabled"] { + opacity: 0.1; + pointer-events: none; + } + label { width: 40px; position: absolute;