salix/front/core/components/calendar/index.js

249 lines
6.2 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.displayControls = true;
this.moment = moment;
this.defaultDate = Date.vnNew();
}
/**
* 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();
let year = date.getFullYear();
const currentDay = Date.vnNew().getDate();
const currentMonth = Date.vnNew().getMonth();
const currentYear = Date.vnNew().getFullYear();
let classes = {
today: day === currentDay && month === currentMonth && year === currentYear,
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) {
const days = this.element.querySelectorAll('.days > .day');
for (let i = 0; i < days.length; i++) {
this.formatDay({
$day: this.days[i],
$element: days[i]
});
}
}
if (this.formatWeek) {
const weeks = this.element.querySelectorAll('.weeks > .day');
for (const week of weeks) {
this.formatWeek({
$element: week
});
}
}
}
}
Calendar.$inject = ['$element', '$scope', 'vnWeekDays', 'moment'];
ngModule.vnComponent('vnCalendar', {
template: require('./index.html'),
controller: Calendar,
bindings: {
defaultDate: '=?',
hasEvents: '&?',
getClass: '&?',
formatDay: '&?',
formatWeek: '&?',
displayControls: '<?',
hideYear: '<?',
hideContiguous: '<?',
hideWeeks: '<?'
}
});