import ngModule from '../../module'; import FormInput from '../form-input'; import './style.scss'; /** * Flat calendar. * * @property {Array} defaultDate Array of events * @property {Function} hasEvents Determines if an events exists for a day * @property {Function} getClass Class to apply to specific day * @event selection Emitted when day or weekday is selected * @event move Emitted when month changes */ export default class Calendar extends FormInput { constructor($element, $scope, vnWeekDays) { super($element, $scope); this.weekDays = vnWeekDays.locales; this.defaultDate = new Date(); this.displayControls = true; } /** * The initial date * * @return {Date} - Default date */ get defaultDate() { return this._defaultDate; } set defaultDate(value) { if (value) { value = new Date(value); value.setHours(0, 0, 0, 0); value.setDate(1); } this._defaultDate = value; this.month = value.getMonth(); this.repaint(); } /** * Returns first day of month from a given date * * @param {Date} date - Origin date * @return {Integer} */ firstDay(date) { return new Date( date.getFullYear(), date.getMonth(), 1 ); } /** * Repaints the calendar. */ repaint() { const firstWeekday = this.firstDay(this.defaultDate).getDay() - 1; let weekdayOffset = firstWeekday >= 0 ? firstWeekday : 6; let dayIndex = new Date(this.defaultDate.getTime()); dayIndex.setDate(1 - weekdayOffset); this.days = []; for (let i = 1; i <= 42; i++) { this.days.push(new Date(dayIndex.getTime())); dayIndex.setDate(dayIndex.getDate() + 1); } } /** * Gets CSS classes to apply to the specified day. * * @param {Date} day The day * @return {Object} The CSS classes to apply */ getDayClasses(day) { let wday = day.getDay(); let month = day.getMonth(); let classes = { weekend: wday === 6 || wday === 0, previous: month < this.month, current: month == this.month, next: month > this.month, event: this.hasEvents({$day: day}) }; let userClass = this.getClass({$day: day}); if (userClass) classes[userClass] = true; return classes; } /** * Moves to next month(s) */ moveNext() { this.move(1); } /** * Moves to previous month(s) */ movePrevious() { this.move(-1); } /** * Moves @direction months backwards/forwards. * * @param {Number} direction Negative to move backwards, positive forwards */ move(direction) { let date = new Date(this.defaultDate.getTime()); date.setMonth(date.getMonth() + direction); this.defaultDate = date; this.repaint(); this.emit('move', {$date: date}); } /* * Day selection event */ select(day) { if (!this.editable) return; this.change(day); this.emit('selection', { $days: [day], $type: 'day' }); this.repaint(); } /* * WeekDay selection event */ selectWeekDay(weekday) { if (!this.editable) return; let days = []; for (let day of this.days) { if (day.getDay() === weekday && day.getMonth() == this.month) days.push(day); } this.field = days[0]; this.emit('selection', { $days: days, $type: 'weekday', $weekday: weekday }); this.repaint(); } hasEvents() { return false; } getClass() { return ''; } repeatLast() { if (!this.formatDay) return; let days = this.element.querySelectorAll('.days > .day'); for (let i = 0; i < days.length; i++) { this.formatDay({ $day: this.days[i], $element: days[i] }); } } } Calendar.$inject = ['$element', '$scope', 'vnWeekDays']; ngModule.vnComponent('vnCalendar', { template: require('./index.html'), controller: Calendar, bindings: { defaultDate: '=?', hasEvents: '&?', getClass: '&?', formatDay: '&?', displayControls: '