Bug 1363672 - Add step support to date picker

This commit is contained in:
janekptacijarabaci 2018-03-30 20:56:33 +02:00 • committed by Roy Tam
commit 1cca8d40f3
5 changed files with 64 additions and 18 deletions

View file

@ -1728,9 +1728,10 @@ let DateTimePickerListener = {
// element's value. // element's value.
value: Object.keys(value).length > 0 ? value value: Object.keys(value).length > 0 ? value
: this._inputElement.value, : this._inputElement.value,
step: this._inputElement.step,
min: this._inputElement.min, min: this._inputElement.min,
max: this._inputElement.max, max: this._inputElement.max,
step: this._inputElement.getStep(),
stepBase: this._inputElement.getStepBase(),
}, },
}); });
break; break;

View file

@ -45,18 +45,21 @@ function DateKeeper(props) {
* @param {Number} day * @param {Number} day
* @param {String} min * @param {String} min
* @param {String} max * @param {String} max
* @param {Number} step
* @param {Number} stepBase
* @param {Number} firstDayOfWeek * @param {Number} firstDayOfWeek
* @param {Array<Number>} weekends * @param {Array<Number>} weekends
* @param {Number} calViewSize * @param {Number} calViewSize
*/ */
init({ year, month, day, min, max, firstDayOfWeek = 0, weekends = [0], calViewSize = 42 }) { init({ year, month, day, min, max, step, stepBase, firstDayOfWeek = 0, weekends = [0], calViewSize = 42 }) {
const today = new Date(); const today = new Date();
const isDateSet = year != undefined && month != undefined && day != undefined; const isDateSet = year != undefined && month != undefined && day != undefined;
this.state = { this.state = {
firstDayOfWeek, weekends, calViewSize, step, firstDayOfWeek, weekends, calViewSize,
min: new Date(min != undefined ? min : MIN_DATE), min: new Date(min != undefined ? min : MIN_DATE),
max: new Date(max != undefined ? max : MAX_DATE), max: new Date(max != undefined ? max : MAX_DATE),
stepBase: new Date(stepBase),
today: this._newUTCDate(today.getFullYear(), today.getMonth(), today.getDate()), today: this._newUTCDate(today.getFullYear(), today.getMonth(), today.getDate()),
weekHeaders: this._getWeekHeaders(firstDayOfWeek, weekends), weekHeaders: this._getWeekHeaders(firstDayOfWeek, weekends),
years: [], years: [],
@ -192,33 +195,50 @@ function DateKeeper(props) {
* } * }
*/ */
getDays() { getDays() {
// TODO: add step support
const firstDayOfMonth = this._getFirstCalendarDate(this.state.dateObj, this.state.firstDayOfWeek); const firstDayOfMonth = this._getFirstCalendarDate(this.state.dateObj, this.state.firstDayOfWeek);
const month = this.month; const month = this.month;
let days = []; let days = [];
for (let i = 0; i < this.state.calViewSize; i++) { for (let i = 0; i < this.state.calViewSize; i++) {
const dateObj = this._newUTCDate(firstDayOfMonth.getUTCFullYear(), firstDayOfMonth.getUTCMonth(), firstDayOfMonth.getUTCDate() + i); const dateObj = this._newUTCDate(firstDayOfMonth.getUTCFullYear(),
firstDayOfMonth.getUTCMonth(),
firstDayOfMonth.getUTCDate() + i);
let classNames = []; let classNames = [];
let enabled = true; let enabled = true;
if (this.state.weekends.includes(dateObj.getUTCDay())) {
const isWeekend = this.state.weekends.includes(dateObj.getUTCDay());
const isCurrentMonth = month == dateObj.getUTCMonth();
const isSelection = this.state.selection.year == dateObj.getUTCFullYear() &&
this.state.selection.month == dateObj.getUTCMonth() &&
this.state.selection.day == dateObj.getUTCDate();
const isOutOfRange = dateObj.getTime() < this.state.min.getTime() ||
dateObj.getTime() > this.state.max.getTime();
const isToday = this.state.today.getTime() == dateObj.getTime();
const isOffStep = this._checkIsOffStep(dateObj,
this._newUTCDate(dateObj.getUTCFullYear(),
dateObj.getUTCMonth(),
dateObj.getUTCDate() + 1));
if (isWeekend) {
classNames.push("weekend"); classNames.push("weekend");
} }
if (month != dateObj.getUTCMonth()) { if (!isCurrentMonth) {
classNames.push("outside"); classNames.push("outside");
} }
if (this.state.selection.year == dateObj.getUTCFullYear() && if (isSelection && !isOutOfRange && !isOffStep) {
this.state.selection.month == dateObj.getUTCMonth() &&
this.state.selection.day == dateObj.getUTCDate()) {
classNames.push("selection"); classNames.push("selection");
} }
if (dateObj.getTime() < this.state.min.getTime() || dateObj.getTime() > this.state.max.getTime()) { if (isOutOfRange) {
classNames.push("out-of-range"); classNames.push("out-of-range");
enabled = false; enabled = false;
} }
if (this.state.today.getTime() == dateObj.getTime()) { if (isToday) {
classNames.push("today"); classNames.push("today");
} }
if (isOffStep) {
classNames.push("off-step");
enabled = false;
}
days.push({ days.push({
dateObj, dateObj,
classNames, classNames,
@ -228,6 +248,24 @@ function DateKeeper(props) {
return days; return days;
}, },
/**
* Check if a date is off step given a starting point and the next increment
* @param {Date} start
* @param {Date} next
* @return {Boolean}
*/
_checkIsOffStep(start, next) {
// If the increment is larger or equal to the step, it must not be off-step.
if (next - start >= this.state.step) {
return false;
}
// Calculate the last valid date
const lastValidStep = Math.floor((next - 1 - this.state.stepBase) / this.state.step);
const lastValidTimeInMs = lastValidStep * this.state.step + this.state.stepBase.getTime();
// The date is off-step if the last valid date is smaller than the start date
return lastValidTimeInMs < start.getTime();
},
/** /**
* Get week headers for calendar * Get week headers for calendar
* @param {Number} firstDayOfWeek * @param {Number} firstDayOfWeek

View file

@ -22,6 +22,8 @@ function DatePicker(context) {
* {Number} date [optional] * {Number} date [optional]
* {String} min * {String} min
* {String} max * {String} max
* {Number} step
* {Number} stepBase
* {Number} firstDayOfWeek * {Number} firstDayOfWeek
* {Array<Number>} weekends * {Array<Number>} weekends
* {Array<String>} monthStrings * {Array<String>} monthStrings
@ -41,10 +43,10 @@ function DatePicker(context) {
* Set initial date picker states. * Set initial date picker states.
*/ */
_setDefaultState() { _setDefaultState() {
const { year, month, day, min, max, firstDayOfWeek, weekends, const { year, month, day, min, max, step, stepBase, firstDayOfWeek, weekends,
monthStrings, weekdayStrings, locale } = this.props; monthStrings, weekdayStrings, locale } = this.props;
const dateKeeper = new DateKeeper({ const dateKeeper = new DateKeeper({
year, month, day, min, max, firstDayOfWeek, weekends, year, month, day, min, max, step, stepBase, firstDayOfWeek, weekends,
calViewSize: CAL_VIEW_SIZE calViewSize: CAL_VIEW_SIZE
}); });

View file

@ -169,6 +169,8 @@
locale, locale,
min: detail.min, min: detail.min,
max: detail.max, max: detail.max,
step: detail.step,
stepBase: detail.stepBase,
} }
}); });
break; break;

View file

@ -232,12 +232,14 @@ button.month-year.active::after {
color: var(--weekend-outside-font-color); color: var(--weekend-outside-font-color);
} }
.days-view > .out-of-range { .days-view > .out-of-range,
.days-view > .off-step {
color: var(--weekday-disabled-font-color); color: var(--weekday-disabled-font-color);
background: var(--disabled-fill-color); background: var(--disabled-fill-color);
} }
.days-view > .out-of-range.weekend { .days-view > .out-of-range.weekend,
.days-view > .off-step.weekend {
color: var(--weekend-disabled-font-color); color: var(--weekend-disabled-font-color);
} }
@ -245,7 +247,8 @@ button.month-year.active::after {
font-weight: bold; font-weight: bold;
} }
.days-view > .out-of-range::before { .days-view > .out-of-range::before,
.days-view > .off-step::before {
display: none; display: none;
} }
@ -341,7 +344,7 @@ button.month-year.active::after {
} }
.spinner-container > .spinner:not(.scrolling) > div.selection, .spinner-container > .spinner:not(.scrolling) > div.selection,
.calendar-container .days-view > div.selection:not(.out-of-range) { .calendar-container .days-view > div.selection {
color: var(--selected-font-color); color: var(--selected-font-color);
} }