UNPKG

@sheng/date-week-range

Version:

This is a week range selector.

293 lines (242 loc) 9.53 kB
import DateTable from 'element-ui/packages/date-picker/src/basic/date-table.vue'; import { getFirstDayOfMonth, getDayCountOfMonth, getWeekNumber, prevDate, nextDate, isDate, clearTime as _clearTime } from 'element-ui/src/utils/date-util'; import { arrayFind } from 'element-ui/src/utils/util'; const getDateTimestamp = function(time) { if (typeof time === 'number' || typeof time === 'string') { return _clearTime(new Date(time)).getTime(); } else if (time instanceof Date) { return _clearTime(time).getTime(); } else { return NaN; } }; export default { mixins: [DateTable], computed: { minDateTimestamp() { return getDateTimestamp(this.minDate) }, maxDateTimestamp() { return getDateTimestamp(this.maxDate) }, rows() { // TODO: refactory rows / getCellClasses const date = new Date(this.year, this.month, 1); let day = getFirstDayOfMonth(date); // day of first day const dateCountOfMonth = getDayCountOfMonth(date.getFullYear(), date.getMonth()); const dateCountOfLastMonth = getDayCountOfMonth(date.getFullYear(), (date.getMonth() === 0 ? 11 : date.getMonth() - 1)); day = (day === 0 ? 7 : day); const offset = this.offsetDay; const rows = this.tableRows; let count = 1; const startDate = this.startDate; const disabledDate = this.disabledDate; const cellClassName = this.cellClassName; const selectedDate = []; const now = getDateTimestamp(new Date()); for (let i = 0; i < 6; i++) { const row = rows[i]; if (this.showWeekNumber) { if (!row[0]) { row[0] = { type: 'week', text: getWeekNumber(nextDate(startDate, i * 7 + 1)) }; } } for (let j = 0; j < 7; j++) { let cell = row[this.showWeekNumber ? j + 1 : j]; if (!cell) { cell = { row: i, column: j, type: 'normal', inRange: false, start: false, end: false }; } cell.type = 'normal'; const index = i * 7 + j; const time = nextDate(startDate, index - offset).getTime(); cell.inRange = time >= this.minDateTimestamp && time <= this.maxDateTimestamp; cell.start = this.minDate && time === this.minDateTimestamp; cell.end = this.maxDate && time === this.maxDateTimestamp; const isToday = time === now; if (isToday) { cell.type = 'today'; } if (i >= 0 && i <= 1) { const numberOfDaysFromPreviousMonth = day + offset < 0 ? 7 + day + offset : day + offset; if (j + i * 7 >= numberOfDaysFromPreviousMonth) { cell.text = count++; } else { cell.text = dateCountOfLastMonth - (numberOfDaysFromPreviousMonth - j % 7) + 1 + i * 7; cell.type = 'prev-month'; } } else { if (count <= dateCountOfMonth) { cell.text = count++; } else { cell.text = count++ - dateCountOfMonth; cell.type = 'next-month'; } } const cellDate = new Date(time); cell.disabled = typeof disabledDate === 'function' && disabledDate(cellDate); cell.selected = arrayFind(selectedDate, date => date.getTime() === cellDate.getTime()); cell.customClass = typeof cellClassName === 'function' && cellClassName(cellDate); this.$set(row, this.showWeekNumber ? j + 1 : j, cell); } } return rows; } }, methods: { getCellClasses(cell) { const defaultValue = this.defaultValue ? Array.isArray(this.defaultValue) ? this.defaultValue : [this.defaultValue] : []; const classes = []; if ((cell.type === 'normal' || cell.type === 'today') && !cell.disabled) { classes.push('available'); if (cell.type === 'today') { classes.push('today'); } } else { classes.push(cell.type); } if (cell.type === 'normal' && defaultValue.some(date => this.cellMatchesDate(cell, date))) { classes.push('default'); } if (cell.inRange && ((cell.type === 'normal' || cell.type === 'today')) ) { if(isDate(this.minDate) && isDate(this.maxDate) || this.rangeState.selecting) { classes.push('in-range'); } if (cell.start) { classes.push('start-date'); } else if (cell.end) { classes.push('end-date'); } } if (cell.disabled) { classes.push('disabled'); } if (cell.selected) { classes.push('selected'); } if (cell.customClass) { classes.push(cell.customClass); } return classes.join(' '); }, isWeekActive(cell) { const newDate = new Date(this.year, this.month, 1); const year = newDate.getFullYear(); const month = newDate.getMonth(); if (cell.type === 'prev-month') { newDate.setMonth(month === 0 ? 11 : month - 1); newDate.setFullYear(month === 0 ? year - 1 : year); } if (cell.type === 'next-month') { newDate.setMonth(month === 11 ? 0 : month + 1); newDate.setFullYear(month === 11 ? year + 1 : year); } newDate.setDate(parseInt(cell.text, 10)); if (isDate(this.value)) { const dayOffset = (this.value.getDay() - this.firstDayOfWeek + 7) % 7 - 1; const weekDate = prevDate(this.value, dayOffset); return weekDate.getTime() === newDate.getTime(); } return false; }, handleMouseMove(event, isManual) { if (!this.rangeState.selecting) return; let target = event.target; if (target.tagName === 'SPAN') { target = target.parentNode.parentNode; } if (target.tagName === 'DIV') { target = target.parentNode; } if (target.tagName !== 'TD') return; const row = target.parentNode.rowIndex - 1; const isMinGreatMax = +new Date(this.rangeState.startDate) >= +new Date(this.getDateOfCell(row, 6)); let column = isMinGreatMax ? 0 : 6; const findIndex = this.rows[row].findIndex(item => !item.disabled); const isExistDis = this.rows[row].some(item => item.disabled); if(isExistDis && findIndex >= 0) { column = findIndex; } // can not select disabled date if (this.rows[row][column].disabled) return; // only update rangeState when mouse moves to a new cell // this avoids frequent Date object creation and improves performance if (row !== this.lastRow || column !== this.lastColumn) { const minDateList = this.rangeState.minDateList; const endDate = this.getDateOfCell(row, column); if(!isManual) { if(isMinGreatMax && !this.isMinGreatMax && minDateList.length === 2 || this.minDate.getTime() > endDate.getTime()) { this.$emit('pick', {minDate: minDateList[1], maxDate: null}); this.isMinGreatMax = true; } else if(this.isMinGreatMax && !isMinGreatMax || this.minDate.getTime() < endDate.getTime()) { this.$emit('pick', {minDate: minDateList[0], maxDate: null}); this.isMinGreatMax = false; } } this.$nextTick(() => { this.$emit('changerange', { minDate: this.minDate, maxDate: this.maxDate, rangeState: { selecting: true, endDate, startDate: this.rangeState.startDate, minDateList: this.rangeState.minDateList } }); this.lastRow = row; this.lastColumn = target.cellIndex; }) } }, handleClick(event) { let target = event.target; if (target.tagName === 'SPAN') { target = target.parentNode.parentNode; } if (target.tagName === 'DIV') { target = target.parentNode; } if (target.tagName !== 'TD') return; const row = target.parentNode.rowIndex - 1; let column =this.rangeState.selecting ? 6 : 0; const findIndex = this.rows[row].findIndex(item => !item.disabled); const isExistDis = this.rows[row].some(item => item.disabled); if(this.rangeState.startDate && this.rangeState.selecting) { column = +new Date(this.rangeState.startDate) >= +new Date(this.getDateOfCell(row, 6)) ? 0 : 6; } if(isExistDis && findIndex >= 0) { column = findIndex; } const cell = this.rows[row][column]; if (cell.disabled || cell.type === 'week') return; const newDate = this.getDateOfCell(row, column); if (!this.rangeState.selecting) { this.rangeState.startDate = newDate; this.rangeState.minDateList = [ this.getDateOfCell(row, 0), this.getDateOfCell(row, 6) ]; this.$emit('pick', {minDate: newDate, maxDate: null}); this.rangeState.selecting = true; this.$nextTick(() =>{ this.handleMouseMove({ target: { tagName:'TD', parentNode: { rowIndex: row + 1, cellIndex: column } } }, true) }) } else { if (newDate >= this.minDate) { this.$emit('pick', {minDate: this.minDate, maxDate: newDate}); } else { this.$emit('pick', {minDate: newDate, maxDate: this.minDate}); } this.rangeState.selecting = false; } } } }