237 lines
5.8 KiB
JavaScript
237 lines
5.8 KiB
JavaScript
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, moment) {
|
|
super($element, $scope);
|
|
this.weekDays = vnWeekDays.locales;
|
|
this.defaultDate = Date.vnNew();
|
|
this.displayControls = true;
|
|
this.moment = moment;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
);
|
|
}
|
|
|
|
lastDay() {
|
|
return new Date(
|
|
this.defaultDate.getFullYear(),
|
|
this.defaultDate.getMonth() + 1,
|
|
0
|
|
).getDate();
|
|
}
|
|
|
|
/**
|
|
* Repaints the calendar.
|
|
*/
|
|
repaint() {
|
|
const firstWeekday = this.firstDay(this.defaultDate).getDay() - 1;
|
|
this.weekdayOffset = firstWeekday >= 0 ? firstWeekday : 6;
|
|
|
|
let dayIndex = new Date(this.defaultDate.getTime());
|
|
dayIndex.setDate(1 - this.weekdayOffset);
|
|
|
|
this.days = [];
|
|
|
|
for (let i = 1; i <= 42; i++) {
|
|
this.days.push(new Date(dayIndex.getTime()));
|
|
dayIndex.setDate(dayIndex.getDate() + 1);
|
|
}
|
|
|
|
this.getWeekdays();
|
|
}
|
|
|
|
getWeekdays() {
|
|
if (!this.moment) return;
|
|
|
|
const totalSlots = this.lastDay() + this.weekdayOffset;
|
|
const weeks = Math.ceil(totalSlots / 7);
|
|
|
|
const dated = this.moment(this.defaultDate);
|
|
const firstWeekNumber = dated.set('date', 1).isoWeek();
|
|
|
|
const weekNumbers = [];
|
|
for (let w = 0; w < weeks; w++) {
|
|
let weekNumber = firstWeekNumber;
|
|
if (dated.get('month') == 0 && firstWeekNumber > 1 && w > 0)
|
|
weekNumber = 0;
|
|
|
|
weekNumbers.push(weekNumber + w);
|
|
}
|
|
|
|
this.weekNumbers = weekNumbers;
|
|
}
|
|
|
|
/**
|
|
* Gets CSS classes to apply to the specified day.
|
|
*
|
|
* @param {Date} date The date
|
|
* @return {Object} The CSS classes to apply
|
|
*/
|
|
getDayClasses(date) {
|
|
let day = date.getDate();
|
|
let wday = date.getDay();
|
|
let month = date.getMonth();
|
|
|
|
const currentDay = Date.vnNew().getDate();
|
|
const currentMonth = Date.vnNew().getMonth();
|
|
|
|
let classes = {
|
|
today: day === currentDay && month === currentMonth,
|
|
weekend: wday === 6 || wday === 0,
|
|
previous: month < this.month,
|
|
current: month == this.month,
|
|
next: month > this.month,
|
|
event: this.hasEvents({$day: date})
|
|
};
|
|
|
|
let userClass = this.getClass({$day: date});
|
|
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($event, day) {
|
|
if (!this.editable) return;
|
|
this.change(day);
|
|
this.emit('selection', {
|
|
$event: $event,
|
|
$days: [day],
|
|
$type: 'day'
|
|
});
|
|
|
|
// Repaint only if 'selection' event is not listening
|
|
if (!this.$events || this.$events && !this.$events['selection'])
|
|
this.repaint();
|
|
}
|
|
|
|
/*
|
|
* WeekDay selection event
|
|
*/
|
|
selectWeekDay($event, 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', {
|
|
$event: $event,
|
|
$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', 'moment'];
|
|
|
|
ngModule.vnComponent('vnCalendar', {
|
|
template: require('./index.html'),
|
|
controller: Calendar,
|
|
bindings: {
|
|
defaultDate: '=?',
|
|
hasEvents: '&?',
|
|
getClass: '&?',
|
|
formatDay: '&?',
|
|
displayControls: '<?',
|
|
hideYear: '<?',
|
|
hideContiguous: '<?',
|
|
hideWeeks: '<?'
|
|
}
|
|
});
|