import '../css/chromecalendar.css';
import ACore from "../ACore";
import * as datetime from 'absol/src/Time/datetime';
import EventEmitter from 'absol/src/HTML5/EventEmitter';
import Dom from "absol/src/HTML5/Dom";
import {VScroller} from "./Scroller";
import {
beginOfDay,
beginOfMonth, beginOfWeek, beginOfYear,
compareDate,
compareMonth, ddmmyyyy,
formatDateString,
nextDate, nextMonth,
prevDate, prevMonth, weekIndexOf
} from "absol/src/Time/datetime";
import DomSignal from "absol/src/HTML5/DomSignal";
import OOP from "absol/src/HTML5/OOP";
import {zeroPadding} from "./utils";
var _ = ACore._;
var $ = ACore.$;
/**
* @extends AElement
* @constructor
*/
function ChromeCalendar() {
var thisCal = this;
this._startDayOfWeek = 0;
this._level = "day";
this.$years = $('.absol-chrome-calendar-years', this);
this._fillYearList(this.$years);
this.$title = $('.absol-chrome-calendar-title', this)
.on('click', this.eventHandler.clickTitle);
this.$titleTime = $('.title-time', this.$title);
this.$instance = $('.absol-chrome-calendar-instance', this);
this.$era = $('.absol-chrome-calendar-era', this)
.on('scroll', this.eventHandler.eraScroll)
.on('click', this.eventHandler.clickEra);
this._fillEra();
this.$month = $('.absol-chrome-calendar-month', this);
this.$dayOfWeek = $('.absol-chrome-calendar-dayofweek', this);
this._min = new Date(1890, 0, 1);
this._max = new Date(2090, 0, 1);
this._selectedDates = [datetime.beginOfDay(new Date())];
this._viewDate = new Date();
this.$prevBtn = $('.absol-chrome-calendar-header-buttons > button.prev-btn', this)
.on('click', this.eventHandler.clickPrev);
this.$todayBtn = $('.absol-chrome-calendar-header-buttons > button.today-btn', this)
.on('click', this.eventHandler.clickToday);
this.$nextBtn = $('.absol-chrome-calendar-header-buttons > button.next-btn', this)
.on('click', this.eventHandler.clickNext);
/***
*
* @type {VScroller}
*/
this.$yearScroller = $('vscroller.absol-chrome-calendar-years', this);
this.$yearItems = [];
$('.absol-chrome-calendar-year', this.$yearScroller, function (e) {
thisCal.$yearItems.push(e);
});
this.$attachHook = _('attachhook').addTo(this);
this.domSignal = new DomSignal((this.$attachHook))
.on('level_change', this.eventHandler.levelChange)
.on('request_update_buttons', this._updateButtons.bind(this))
.on('request_update_month', this._updateMonth.bind(this, this.$month))
.on('request_update_open_year', this._updateOpenYear.bind(this))
.on('request_update_disabled_year_in_era', this._updateDisabledYearInEra.bind(this))
.on('request_update_picked_years', this._updatePickedYears.bind(this));
this.sync = new Promise(function (rs) {
thisCal.$attachHook.on('attached', rs);
});
this.domSignal.emit('level_change');
this.sync.then('attached', function () {
thisCal.$yearScroller.requestUpdateSize();
thisCal.expandYear(thisCal._viewDate.getFullYear());
thisCal._updateYearInEra();
});
OOP.drillProperty(this, this, 'minLimitDate', 'min');
OOP.drillProperty(this, this, 'minDateLimit', 'min');
OOP.drillProperty(this, this, 'maxLimitDate', 'max');
OOP.drillProperty(this, this, 'maxDateLimit', 'max');
}
ChromeCalendar.tag = 'ChromeCalendar'.toLowerCase();
ChromeCalendar.render = function () {
return _({
class: ['absol-chrome-calendar', 'as-level-day'],
extendEvent: 'pick',
child: [
{
class: 'absol-chrome-calendar-header',
child: [
{
class: 'absol-chrome-calendar-title',
child: [
{
tag: 'span',
class: 'title-time',
child: {text: 'Septemper, 2019'}
},
]
},
{
class: 'absol-chrome-calendar-header-buttons',
child: [
{
tag: 'button',
class: 'prev-btn',
child: 'span.mdi.mdi-menu-left',
attr: {
title: 'Previous Month'
}
},
{
tag: 'button',
class: 'today-btn',
child: 'span.mdi.mdi-circle-medium',
attr: {
title: 'Today'
}
},
{
tag: 'button',
class: 'next-btn',
child: 'span.mdi.mdi-menu-right',
attr: {
title: 'Next Month'
}
}
]
}
]
},
{
class: 'absol-chrome-calendar-instance',
child: [
{
class: 'absol-chrome-calendar-dayofweek',
child: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'].map(function (text) {
return {
child: {text: text}
}
})
},
{
class: 'absol-chrome-calendar-month',
child: Array(6).fill(0).map(function (u, i) {
return {
class: 'absol-chrome-calendar-week-in-month',
child: Array(7).fill(0).map(function (v, j) {
return {
child: {text: i * 7 + j + ''}
}
})
}
})
},
{
tag: 'vscroller',
class: 'absol-chrome-calendar-years',
child: {}
},
{
class: "absol-chrome-calendar-era"
}
]
}
]
});
};
/**
* @param {Date} date
* @returns {Boolean}
*/
ChromeCalendar.prototype._isSelectedDate = function (date) {
for (var i = 0; i < this._selectedDates.length; ++i) {
if (compareDate(date, this._selectedDates[i]) === 0) return true;
}
return false;
};
/**
* @param {Date} date
* @returns {Boolean}
*/
ChromeCalendar.prototype._isSelectedMonth = function (date) {
for (var i = 0; i < this._selectedDates.length; ++i) {
if (compareMonth(date, this._selectedDates[i]) === 0) return true;
}
return false;
};
/**
* @param {Date} date
* @returns {Boolean}
*/
ChromeCalendar.prototype._isSelectedYear = function (date) {
for (var i = 0; i < this._selectedDates.length; ++i) {
if (date.getFullYear() === this._selectedDates[i].getFullYear()) return true;
}
return false;
};
ChromeCalendar.prototype._dayCmpLimit = function (date) {
if (compareDate(date, this._min) < 0) return -1;
if (compareDate(date, this._max) > 0) return 1;
return 0;
};
ChromeCalendar.prototype._monthCmpLimit = function (date) {
var startOfMonth = beginOfMonth(date);
var endOfMonth = nextMonth(date);
var minMil = Math.max(startOfMonth.getTime(), this._min.getTime());
var maxMil = Math.min(endOfMonth.getTime(), nextDate(this._max).getTime());
if (minMil < maxMil) return 0;
return this._dayCmpLimit(date);
};
ChromeCalendar.prototype._yearCmpLimit = function (date) {
var startOfYear = beginOfYear(date);
var endOfYear = new Date(date.getFullYear() + 1, 0, 1);
var minMil = Math.max(startOfYear.getTime(), this._min.getTime());
var maxMil = Math.min(endOfYear.getTime(), nextDate(this._max).getTime());
if (minMil < maxMil) return 0;
return this._dayCmpLimit(date);
};
/***
*
* @param {Date} date
* @param event
*/
ChromeCalendar.prototype.pickDate = function (date, event) {
date = beginOfDay(date);
this._selectedDates = [date];
this._updateMonth(this.$month);
if (this.$lastOpenYearItem) this.$lastOpenYearItem.$months.updateActiveMonth();
this.emit('pick', {
type: 'pick', value: date,
isTrusted: event && event.isTrusted,
originEvent: event,
selectedDates: this.selectedDates
});
};
/***
*
* @param {Date} date
* @param event
*/
ChromeCalendar.prototype.pickMonth = function (date, event) {
date = beginOfMonth(date);
this._selectedDates = [date];
if (this.$lastOpenYearItem) this.$lastOpenYearItem.$months.updateActiveMonth();
this.emit('pick', {
type: 'pick', value: date,
isTrusted: event && event.isTrusted,
originEvent: event,
selectedDates: this.selectedDates
});
};
ChromeCalendar.prototype._updatePickedYears = function () {
var yearElt;
var self = this;
while (this.$lastPickYears && this.$lastPickYears.length > 0) {
yearElt = this.$lastPickYears.pop();
yearElt.removeClass('absol-chrome-calendar-selected');
}
this.$lastPickYears = this._selectedDates.map(function (date) {
var yearElt = self._yearInAre(date.getFullYear());
yearElt.addClass('absol-chrome-calendar-selected');
return yearElt;
})
};
ChromeCalendar.prototype.pickYear = function (year, event) {
var date = new Date(year, 0, 1, 0, 0, 0, 0);
this._selectedDates = [date];
this.domSignal.emit('request_update_picked_years');
this.scrollIntoDecade(Math.floor(year / 10) * 10, true);
this.emit('pick', {
type: 'pick', value: date,
isTrusted: event && event.isTrusted,
originEvent: event,
});
};
/**
* @param {Element} monthElt
* @param {Date} date
*/
ChromeCalendar.prototype._fillMonth = function (monthElt, date) {
var self = this;
if (monthElt.$cells === undefined) {//for faster, attach event to element
monthElt.$cells = [];
Array.prototype.forEach.call(monthElt.childNodes, function (row) {
row.on('click', function (event) {
if (event.target !== this) return;
var pickedElt = this.firstChild;
var pickDate = this.firstChild.__date__;
self.pickDate(pickDate, event);
if (pickedElt.hasClass('absol-chrome-calendar-not-in-month')) {
if (pickDate.getDate() < 15) {
self.viewNexMonth();
} else {
self.viewPrevMonth();
}
}
});
});
$('.absol-chrome-calendar-week-in-month > div', this.$month, function (elt) {
monthElt.$cells.push(elt);
elt.on('click', function (event) {
var pickedElt = elt;
var pickDate = this.__date__;
if (self._level === 'week') {
pickDate = beginOfWeek(pickDate, false, self._startDayOfWeek);
pickedElt = elt.parentElement.firstChild;
}
self.pickDate(pickDate, event);
if (pickedElt.hasClass('absol-chrome-calendar-not-in-month')) {
if (pickDate.getDate() < 15) {
self.viewNexMonth();
} else {
self.viewPrevMonth();
}
}
});
});
}
var currentDate = datetime.beginOfWeek(datetime.beginOfMonth(date), false, this._startDayOfWeek);
var d;
var cell;
for (var i = 0; i < monthElt.$cells.length; ++i) {
cell = monthElt.$cells[i];
d = currentDate.getDate();
cell.innerHTML = '' + d;
cell.__date__ = datetime.beginOfDay(currentDate);
currentDate = datetime.nextDate(currentDate);
}
Array.prototype.forEach.call(monthElt.childNodes, function (row) {
var weekIdx = weekIndexOf(row.firstChild.__date__, false, self._startDayOfWeek);
row.attr('data-week-idx-text', zeroPadding(1 + weekIdx, 2) + '');
});
};
ChromeCalendar.prototype._updateMonth = function (monthElt) {
if (!monthElt.$cells) return; // days weren't filled
var now = new Date();
var viewM = this._viewDate.getMonth();
var m;
var cell;
var currentDate;
var selectedWeeks = {};
for (var i = 0; i < monthElt.$cells.length; ++i) {
cell = monthElt.$cells[i];
currentDate = cell.__date__;
m = currentDate.getMonth();
if (m != viewM)
cell.addClass('absol-chrome-calendar-not-in-month');
else
cell.removeClass('absol-chrome-calendar-not-in-month');
if (datetime.compareDate(currentDate, now) === 0)
cell.addClass('absol-chrome-calendar-today');
else
cell.removeClass('absol-chrome-calendar-today');
if (this._isSelectedDate(currentDate)) {
cell.addClass('absol-chrome-calendar-selected');
selectedWeeks[weekIndexOf(currentDate, false, this._startDayOfWeek)] = true;
} else
cell.removeClass('absol-chrome-calendar-selected');
if (datetime.compareDate(this._min, currentDate) > 0 || datetime.compareDate(currentDate, this._max) > 0) {
cell.addClass('absol-chrome-calendar-date-disabled');
} else {
cell.removeClass('absol-chrome-calendar-date-disabled');
}
}
Array.prototype.forEach.call(monthElt.childNodes, function (row) {
var weekIdx = weekIndexOf(row.firstChild.__date__, false, this._startDayOfWeek);
if (selectedWeeks[weekIdx]) {
row.addClass('as-week-selected');
} else {
row.removeClass('as-week-selected');
}
}.bind(this))
};
ChromeCalendar.prototype._fillYearList = function (ctn) {
var thisCal = this;
_({
child: Array(200).fill(0).map(function (u, i) {
return {
class: 'absol-chrome-calendar-year',
child: [
{
class: 'absol-chrome-calendar-year-head',
child: {text: i + 1890 + ''},
}
],
props: {
__year__: i + 1890
},
on: {
click: function () {
thisCal.expandYear(this.__year__);
}
}
};
})
}).addTo(ctn);
};
ChromeCalendar.prototype._fillEra = function () {
var now = new Date();
var cYear = now.getFullYear();
var rows = Array(50).fill(0).map(function (u, i) {
return _({
class: 'absol-chrome-calendar-era-row',
child: Array(4).fill(0).map(function (u1, j) {
var classList = ['absol-chrome-calendar-era-year'];
var year = 1890 + i * 4 + j;
if (cYear === year) {
classList.push('absol-chrome-calendar-today');
}
return {
class: classList,
child: {text: year + ''},
props: {
__year__: year
}
};
})
});
});
this.$era.addChild(rows);
}
ChromeCalendar.prototype.viewNexMonth = function () {
var self = this;
this.sync = this.sync.then(function () {
return new Promise(function (rs) {
var oldBound = self.$month.getBoundingClientRect();
var oldMonth = self.$month.cloneNode(true);
var instanceBound = self.$instance.getBoundingClientRect();
if (self.$lastAnimationCtn) {
self.$lastAnimationCtn.removeClass('new').addClass('old');
}
var oldMonthCnt = _({
class: ['absol-chrome-calendar-month-animation-container', 'old'],
style: {
top: oldBound.top - instanceBound.top + 'px',
height: oldBound.height + 'px',
width: oldBound.width + 'px'
},
child: oldMonth
}).addTo(self.$instance);
self._viewDate = datetime.nextMonth(self._viewDate);
self.viewMonth();
var newMonth = self.$month.cloneNode(true);
var overlap = 0;
var j = 41;
while (j >= 0 && self.$month.$cells[j].hasClass('absol-chrome-calendar-not-in-month')) {
overlap += oldBound.height / 6;
j -= 7;
}
var newMonthCtn = _({
class: ['absol-chrome-calendar-month-animation-container', 'new'],
style: {
top: oldBound.top + oldBound.height - instanceBound.top - overlap + 'px',
height: oldBound.height + 'px',
width: oldBound.width + 'px'
},
child: newMonth
}).addTo(self.$instance);
self.$lastAnimationCtn = newMonthCtn;
setTimeout(function () {
oldMonthCnt.addStyle('top', oldBound.top - oldBound.height + overlap - instanceBound.top + 'px');
newMonthCtn.addStyle('top', oldBound.top - instanceBound.top + 'px');
}, 20);
setTimeout(function () {
self.$lastAnimationCtn = undefined;
oldMonthCnt.remove();
newMonthCtn.remove();
}, 220);
setTimeout(rs, 22);
});
});
return this.sync;
};
ChromeCalendar.prototype.viewPrevMonth = function () {
var self = this;
this.sync = this.sync.then(function () {
return new Promise(function (rs) {
var oldBound = self.$month.getBoundingClientRect();
var oldMonth = self.$month.cloneNode(true);
var instanceBound = self.$instance.getBoundingClientRect();
if (self.$lastAnimationCtn) {
self.$lastAnimationCtn.removeClass('new').addClass('old');
}
var oldMonthCnt = _({
class: ['absol-chrome-calendar-month-animation-container', 'old'],
style: {
top: oldBound.top - instanceBound.top + 'px',
height: oldBound.height + 'px',
width: oldBound.width + 'px'
},
child: oldMonth
}).addTo(self.$instance);
self._viewDate = datetime.prevMonth(self._viewDate);
self.viewMonth();
var newMonth = self.$month.cloneNode(true);
var overlap = 0;
var j = 0;
while (j < 42 && self.$month.$cells[j].hasClass('absol-chrome-calendar-not-in-month')) {
overlap += oldBound.height / 6;
j += 7;
}
var newMonthCtn = _({
class: ['absol-chrome-calendar-month-animation-container', 'new'],
style: {
top: oldBound.top - oldBound.height + overlap - instanceBound.top + 'px',
height: oldBound.height + 'px',
width: oldBound.width + 'px'
},
child: newMonth
}).addTo(self.$instance);
self.$lastAnimationCtn = newMonthCtn;
setTimeout(function () {
oldMonthCnt.addStyle('top', oldBound.top + oldBound.height - overlap - instanceBound.top + 'px');
newMonthCtn.addStyle('top', oldBound.top - instanceBound.top + 'px');
}, 20);
setTimeout(function () {
self.$lastAnimationCtn = undefined;
oldMonthCnt.remove();
newMonthCtn.remove();
}, 220);
setTimeout(rs, 22);
})
});
return this.sync;
};
ChromeCalendar.prototype.viewToday = function () {
this._viewDate = new Date();
switch (this._level) {
case "day":
case 'week':
this.viewMonth();
break;
case "month":
break;
case "year":
this.viewEra(true);
break;
}
};
ChromeCalendar.prototype.viewMonth = function () {
this._updateButtons();
this.removeClass('view-year')
.removeClass('view-era')
.addClass('view-month');
this._fillMonth(this.$month, this._viewDate);
this._updateMonth(this.$month);
this.$titleTime.innerHTML = datetime.formatDateString(this._viewDate, 'mmmm, yyyy');
};
ChromeCalendar.prototype.viewYear = function () {
this.removeClass('view-month')
.removeClass('view-era')
.addClass('view-year');
this.expandYear(this._viewDate.getFullYear());
this.$yearScroller.requestUpdateSize();
};
ChromeCalendar.prototype.viewEra = function (animation) {
this.removeClass('view-month')
.removeClass('view-year')
.addClass('view-era');
this.scrollIntoDecade(Math.floor(this._viewDate.getFullYear() / 10) * 10, animation);
};
ChromeCalendar.prototype.viewNextDecade = function (animation) {
this._viewDate = new Date(Math.min(2080, Math.floor(this._viewDate.getFullYear() / 10) * 10 + 10), 0, 1);
this._viewDate = new Date(Math.min(this._viewDate.getTime(), prevDate(this._max).getTime()));
this.viewEra(animation);
};
ChromeCalendar.prototype.viewPrevDecade = function (animation) {
this._viewDate = new Date((Math.max(1890, Math.floor(this._viewDate.getFullYear() / 10) * 10 - 10)), 0, 1);
this._viewDate = new Date(Math.max(this._viewDate.getTime(), this._min.getTime()));
this.viewEra(animation);
};
ChromeCalendar.prototype.expandYear = function (year) {
if (this._level === 'month') {
this._viewDate = new Date(year, 0, 1);
this.$titleTime.innerHTML = formatDateString(this._viewDate, 'mmmm, yyyy');
this.domSignal.emit('request_update_buttons');
}
var fontSize = this.getFontSize();
var self = this;
var lastItemElt = this.$lastOpenYearItem;
var itemElt = this.$yearItems[year - 1890];
var lastYear = 100000000;
if (lastItemElt && lastItemElt.__year__ !== year) {
lastYear = lastItemElt.__year__;
lastItemElt.addClass('start-closing');
setTimeout(function () {
lastItemElt.removeClass('start-closing').addClass('closing');
}, 0);
setTimeout(function () {
lastItemElt.removeClass('closing');
lastItemElt.$months.remove();
lastItemElt.$months = undefined;
}, 100);
}
if (lastItemElt !== itemElt) {
if (!itemElt.$months) {
itemElt.$months = this._createMonths(year).addTo(itemElt);
itemElt.addClass('start-opening');
setTimeout(function () {
itemElt.removeClass('start-opening').addClass('opening');
}, 1);
setTimeout(function () {
itemElt.removeClass('opening');
}, 100);
}
}
var dy = itemElt.getBoundingClientRect().top - self.$yearScroller.getBoundingClientRect().top - fontSize * 0.45;
if (itemElt.__year__ > lastYear) {
dy -= 6 * fontSize;
}
self.$yearScroller.scrollBy(dy, 100);
this.$lastOpenYearItem = itemElt;
itemElt.$months.updateActiveMonth();
};
ChromeCalendar.prototype.scrollIntoDecade = function (startYear, animation) {
if (!this.isDescendantOf(document.body)) {
return this.sync.then(this.scrollIntoDecade.bind(this));
}
var thisCal = this;
return new Promise(function (resolve) {
var eraBound = thisCal.$era.getBoundingClientRect();
var rowIdx = Math.floor((startYear - 1890) / 4);
if (thisCal._decadeScrollTimeout > 0) {
clearTimeout(thisCal._decadeScrollTimeout);
thisCal._decadeScrollTimeout = -1;
}
if (thisCal.scrollIntoDecadeResolve) {
thisCal.scrollIntoDecadeResolve();
thisCal.scrollIntoDecadeResolve = null;
}
thisCal.scrollIntoDecadeResolve = resolve;
var t0 = new Date().getTime();
var t1 = t0 + 250;
var y0 = thisCal.$era.scrollTop;
var y1 = rowIdx * eraBound.height / 4;
if (animation) {
thisCal._decadeScrollTimeout = setTimeout(function tick() {
var tc = new Date().getTime();
var yc = Math.min(1, Math.pow((tc - t0) / (t1 - t0), 2)) * (y1 - y0) + y0;
thisCal.$era.scrollTop = yc;
if (tc < t1) {
thisCal._decadeScrollTimeout = setTimeout(tick, 30);
} else {
thisCal._decadeScrollTimeout = -1;
thisCal.scrollIntoDecadeResolve = null;
resolve();
}
}, 30);
} else {
thisCal.$era.scrollTop = y1;
}
});
};
ChromeCalendar.prototype._updateButtons_day = function () {
if (this._monthCmpLimit(prevMonth(this._viewDate)) < 0) {
this.$prevBtn.addClass('absol-chrome-calendar-button-disabled');
} else {
this.$prevBtn.removeClass('absol-chrome-calendar-button-disabled');
}
if (this._monthCmpLimit(nextMonth(this._viewDate)) > 0) {
this.$nextBtn.addClass('absol-chrome-calendar-button-disabled');
} else {
this.$nextBtn.removeClass('absol-chrome-calendar-button-disabled');
}
var now = new Date();
if (this._monthCmpLimit(now) === 0) {
this.$todayBtn.removeClass('absol-chrome-calendar-button-disabled');
} else {
this.$todayBtn.addClass('absol-chrome-calendar-button-disabled');
}
};
ChromeCalendar.prototype._updateButtons_week = ChromeCalendar.prototype._updateButtons_day;
ChromeCalendar.prototype._updateButtons_year = function () {
if (!this._viewDate) return;
var year = Math.floor(this._viewDate.getFullYear() / 10) * 10;
if (this._yearCmpLimit(new Date(year - 1, 0, 1)) < 0) {
this.$prevBtn.addClass('absol-chrome-calendar-button-disabled');
} else {
this.$prevBtn.removeClass('absol-chrome-calendar-button-disabled');
}
if (this._yearCmpLimit(new Date(year + 10, 0, 1)) > 0) {
this.$nextBtn.addClass('absol-chrome-calendar-button-disabled');
} else {
this.$nextBtn.removeClass('absol-chrome-calendar-button-disabled');
}
var now = new Date();
if (this._yearCmpLimit(now) === 0) {
this.$todayBtn.removeClass('absol-chrome-calendar-button-disabled');
} else {
this.$todayBtn.addClass('absol-chrome-calendar-button-disabled');
}
};
ChromeCalendar.prototype._updateButtons_month = function () {
if (this._yearCmpLimit(new Date(this._viewDate.getFullYear() + 1, 0, 1)) > 0) {
this.$nextBtn.addClass('absol-chrome-calendar-button-disabled');
} else {
this.$nextBtn.removeClass('absol-chrome-calendar-button-disabled');
}
if (this._yearCmpLimit(new Date(this._viewDate.getFullYear() - 1, 0, 1)) < 0) {
this.$prevBtn.addClass('absol-chrome-calendar-button-disabled');
} else {
this.$prevBtn.removeClass('absol-chrome-calendar-button-disabled');
}
};
ChromeCalendar.prototype._updateButtons = function () {
var fName = '_updateButtons_' + this._level;
this[fName] && this[fName]();
};
ChromeCalendar.prototype._createMonths = function (year) {
var now = new Date();
var self = this;
var res = _({
class: 'absol-chrome-calendar-year-mounths',
child: Array(3).fill('').map(function (u, i) {
return {
class: 'absol-chrome-calendar-year-row-months',
child: Array(4).fill(0).map(function (v, j) {
var date = new Date(year, i * 4 + j, 1, 0, 0, 0, 0, 0);
return {
class: ['absol-chrome-calendar-year-month']
.concat((year == now.getFullYear() && now.getMonth() == i * 4 + j) ? ['absol-chrome-calendar-today'] : [])
.concat(self._isSelectedMonth(date) ? ['absol-chrome-calendar-selected'] : [])
,
child: {text: datetime.monthNames[i * 4 + j].substr(0, 3)},
on: {
click: function () {
}
},
props: {
__date__: date
}
}
})
}
}),
on: {
click: this.eventHandler.clickMonthsInYear
}
});
res.$monthList = [];
$('.absol-chrome-calendar-year-month', res, function (e) {
res.$monthList.push(e);
});
res.updateActiveMonth = function () {
res.$monthList.forEach(function (e) {
now = new Date();
if (datetime.compareMonth(e.__date__, now) == 0) {
e.addClass('absol-chrome-calendar-today');
} else {
e.removeClass('absol-chrome-calendar-today');
}
if (self._isSelectedMonth(e.__date__)) {
e.addClass('absol-chrome-calendar-selected');
} else {
e.removeClass('absol-chrome-calendar-selected');
}
var beginOfMonth = datetime.beginOfMonth(e.__date__);
var endOfMonth = datetime.prevDate(datetime.nextMonth(e.__date__));
if (datetime.compareDate(self._min, endOfMonth) > 0 || datetime.compareDate(beginOfMonth, self._max) > 0) {
e.addClass('absol-chrome-calendar-date-disabled');
} else {
e.removeClass('absol-chrome-calendar-date-disabled');
}
});
}
return res;
};
ChromeCalendar.prototype._yearInAre = function (year) {
var d = year - 1890;
var rowIdx = Math.floor(d / 4);
var colIdx = d % 4;
return this.$era.childNodes[rowIdx] && this.$era.childNodes[rowIdx].childNodes[colIdx];
};
ChromeCalendar.prototype._clearYearInAre = function (startYear) {
var cellElt;
for (var i = 0; i < 10; ++i) {
cellElt = this._yearInAre(startYear + i);
if (cellElt) cellElt.removeClass('absol-chrome-calendar-in-decade');
}
};
ChromeCalendar.prototype._activeYearInAre = function (startYear) {
var cellElt;
for (var i = 0; i < 10; ++i) {
cellElt = this._yearInAre(startYear + i);
if (cellElt) cellElt.addClass('absol-chrome-calendar-in-decade');
}
};
ChromeCalendar.prototype._updateYearInEra = function () {
var eraBound = this.$era.getBoundingClientRect();
var startYear = 1890 + 4 * Math.ceil((this.$era.scrollTop - eraBound.height / 16) * 4 / eraBound.height);
var startDecade = Math.floor(startYear / 10) * 10;
if ((startDecade + 10 - startYear) < 8) startDecade += 10;
if (this._lastStartDecade !== startDecade) {
if (this._lastStartDecade > 0) {
this._clearYearInAre(this._lastStartDecade);
}
this._lastStartDecade = startDecade;
this._activeYearInAre(startDecade);
if (this._level === 'year') {
this.$titleTime.innerHTML = startDecade + '-' + (startDecade + 10);
if (!this._decadeScrollTimeout || this._decadeScrollTimeout < 0) {
if (this._yearCmpLimit(new Date(startDecade, 0, 1)) === 0)
this._viewDate = new Date(startDecade, 0, 1);
}
}
this.domSignal.emit('request_update_buttons');
}
};
ChromeCalendar.prototype._updateDisabledYearInEra = function () {
var self = this;
Array.prototype.forEach.call(this.$era.childNodes, function (rowElt) {
Array.prototype.forEach.call(rowElt.childNodes, function (cellElt) {
if (cellElt.__year__) {
if (self._yearCmpLimit(new Date(cellElt.__year__, 0, 1)) === 0) {
cellElt.removeClass('absol-chrome-calendar-date-disabled');
} else {
cellElt.addClass('absol-chrome-calendar-date-disabled');
}
}
});
});
};
ChromeCalendar.prototype._updateOpenYear = function () {
if (this.$lastOpenYearItem) {
this.$lastOpenYearItem.$months.updateActiveMonth();
}
};
ChromeCalendar.property = {};
ChromeCalendar.property.selectedDates = {
set: function (value) {
value = value || [];
if (value instanceof Date) value = [value];
this._selectedDates = value;
this._viewDate = this._selectedDates[0] || new Date();
this.domSignal.emit('level_change');
if (this._level === 'year')
this.domSignal.emit('request_update_picked_years');
},
get: function () {
return this._selectedDates;
}
};
ChromeCalendar.property.min = {
set: function (value) {
if (!value) value = new Date(1890, 0, 1);
if (typeof value == 'number') value = new Date(value);
value = beginOfDay(value);
value = new Date(Math.max(new Date(1890, 0, 1).getTime(), value.getTime()));
this._min = value;
this.domSignal.emit('request_update_buttons');
this.domSignal.emit('request_update_month');
this.domSignal.emit('request_update_open_year');
this.domSignal.emit('request_update_disabled_year_in_era');
},
get: function () {
return this._min;
}
};
//include maxLimitDate
ChromeCalendar.property.max = {
set: function (value) {
if (!value) value = new Date(2090, 0, 1);
if (typeof value == 'number') value = new Date(value);
if (value.getTime() > beginOfDay(value).getTime()) value = nextDate(beginOfDay(value));
value = new Date(Math.min(new Date(2090, 0, 1).getTime(), value.getTime()));
this._max = value;
this.domSignal.emit('request_update_buttons');
this.domSignal.emit('request_update_month');
this.domSignal.emit('request_update_open_year');
this.domSignal.emit('request_update_disabled_year_in_era');
},
get: function () {
return this._max;
}
};
ChromeCalendar.property.multiSelect = {
set: function (value) {
throw new Error('Not support yet!')
var lastValue = this.multiSelect;
value = !!value;
if (lastValue != value) {
if (value) {
this.addClass('multi-select')
} else {
this.removeClass('multi-select');
}
this._updateMonth(this.$month);
}
},
get: function () {
return this.hasClass('multi-select');
}
};
ChromeCalendar.property.level = {
set: function (value) {
value = (value || '') + '';
value = value.toLowerCase();
if (['day', 'week', 'month', 'year'].indexOf(value) < 0) value = 'day';
if (this._level === value) return;
this.removeClass('as-level-' + this._level);
this._level = value;
this.addClass('as-level-' + this._level);
this.domSignal.emit('level_change');
if (this._level === 'year')
this.domSignal.emit('request_update_picked_years');
},
get: function () {
return this._level;
}
};
ChromeCalendar.prototype.dayInWeekTexts = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
ChromeCalendar.property.startDayOfWeek = {
set: function (value) {
value = Math.max(0, Math.min(Math.floor(value || 0), 6));
if (this._startDayOfWeek !== value) {
this._startDayOfWeek = value;
Array.prototype.forEach.call(this.$dayOfWeek.childNodes, function (e, i) {
e.firstChild.data = this.dayInWeekTexts[(i + value) % 7];
}.bind(this));
}
this._updateMonth(this.$month);
},
get: function () {
return this._startDayOfWeek;
}
};
ChromeCalendar.property.viewDate = {
set: function (date) {
this._viewDate = date;
this.domSignal.emit('level_change');
},
get: function () {
return this._viewDate;
}
}
ChromeCalendar.eventHandler = {};
ChromeCalendar.eventHandler.eraScroll = function () {
this._updateYearInEra();
};
ChromeCalendar.eventHandler.clickEra = function (event) {
var yearElt = event.target;
var year = yearElt.__year__;
if (typeof year !== "number") return;
this.pickYear(year, event);
};
ChromeCalendar.eventHandler.clickPrev = function () {
switch (this._level) {
case "day":
case 'week':
this.viewPrevMonth();
break;
case "month":
this.expandYear(Math.min(this._max.getFullYear(), this._viewDate.getFullYear() - 1));
break;
case "year":
if (!this._decadeScrollTimeout || this._decadeScrollTimeout < 0)
this.viewPrevDecade(true);
break;
}
};
ChromeCalendar.eventHandler.clickNext = function () {
switch (this._level) {
case "day":
case 'week':
this.viewNexMonth();
break;
case "month":
this.expandYear(Math.max(prevDate(this._min).getFullYear(), this._viewDate.getFullYear() + 1));
break;
case "year":
if (!this._decadeScrollTimeout || this._decadeScrollTimeout < 0)
this.viewNextDecade(true);
break;
}
};
ChromeCalendar.eventHandler.clickToday = function (event) {
this.viewToday();
switch (this._level) {
case "day":
this.pickDate(new Date(), event);
break;
case 'week':
this.pickDate(beginOfWeek(new Date(), false, this.startDayOfWeek), event)
break;
case "month":
this.expandYear(new Date().getFullYear());
this.pickMonth(beginOfMonth(new Date()), event);
break;
case "year":
this.pickYear(new Date().getFullYear());
this._viewDate = new Date(new Date().getFullYear(), 0, 1);
this.viewEra(true);
break;
}
};
ChromeCalendar.eventHandler.clickTitle = function (event) {
switch (this._level) {
case "day":
case "week":
this.viewYear();
break;
case "month":
break;
case "year":
break;
}
};
ChromeCalendar.eventHandler.clickMonthsInYear = function (event) {
var monthElt = event.target;
var date = monthElt.__date__;
if (!date) return;
switch (this._level) {
case "day":
case "week":
this._viewDate = date;
this.viewMonth();
break;
case "month":
this.pickMonth(date, event);
break;
case "year":
break;
}
};
ChromeCalendar.eventHandler.levelChange = function () {
switch (this._level) {
case "day":
case "week":
this.viewMonth();
break;
case "month":
this.viewYear();
break;
case "year":
this.viewEra();
break;
}
};
ACore.install(ChromeCalendar);
ChromeCalendar._session = Math.random() * 10000000000 >> 0;
ChromeCalendar._listener = undefined;
ChromeCalendar.showWhenClick = function (element, calendarProps, anchor, calendarPickListener, darkTheme) {
var res = {
calendarProps: Object.assign({maxDateLimit: null, minDateLimit: null}, calendarProps),
anchor: anchor,
currentSession: undefined,
element: element,
calendarPickListener: calendarPickListener,
darkTheme: darkTheme,
setDateValue: function (value) {
if (this.currentSession == ChromeCalendar._session) {
ChromeCalendar.$calendar.selectedDates = [value];
}
},
cancel: function () {
}
};
var clickHandler = function () {
if (element.hasClass('as-read-only')) return;
if (ChromeCalendar._session == res.currentSession) return;
res.currentSession = ChromeCalendar.show(res.element, res.calendarProps, res.anchor, res.calendarPickListener, res.darkTheme);
var finish = function (event) {
if (event && event.target && EventEmitter.hitElement(ChromeCalendar.$calendar, event)) return;
document.body.removeEventListener('click', finish, false);
ChromeCalendar.close(res.currentSession);
ChromeCalendar.$calendar.off('pick', finish);
res.currentSession = undefined;
res.cancel = function () {
};
};
setTimeout(function () {
document.body.addEventListener('click', finish, false);
ChromeCalendar.$calendar.on('pick', finish);
res.cancel = finish;
}, 10)
};
res.remove = function () {
element.removeEventListener('click', clickHandler, false);
};
element.addEventListener('click', clickHandler, false);
return res;
};
ChromeCalendar.show = function (element, calendarProps, anchor, calendarPickListener, darkTheme) {
ChromeCalendar._session = Math.random() * 10000000000 >> 0;
function exec() {
if (!ChromeCalendar.$ctn) {
ChromeCalendar.$ctn = _('.absol-context-hinge-fixed-container');
ChromeCalendar.$follower = _('follower').addTo(ChromeCalendar.$ctn);
ChromeCalendar.$calendar = _('chromecalendar.as-dropdown-box-common-style')
.on('pick', function (event) {
if (typeof ChromeCalendar._listener == 'function') {
ChromeCalendar._listener(event.value);
}
}).addTo(ChromeCalendar.$follower);
}
ChromeCalendar.$ctn.addTo(document.body);
// only one value need
if (calendarProps instanceof Date) calendarProps = {selectedDates: [calendarProps]};
if (calendarProps instanceof Array) calendarProps = {selectedDates: calendarProps};
Object.assign(ChromeCalendar.$calendar, calendarProps);
if (darkTheme) ChromeCalendar.$ctn.addClass('dark');
else ChromeCalendar.$ctn.removeClass('dark');
ChromeCalendar.$follower.followTarget = element;
ChromeCalendar.$follower.anchor = anchor;
ChromeCalendar.$calendar.addStyle('visibility', 'hidden');//for prevent size change blink
ChromeCalendar._listener = calendarPickListener;
setTimeout(function () {
ChromeCalendar.$follower.updatePosition();
ChromeCalendar.$calendar.removeStyle('visibility');
}, 2);
}
if (document.body)
exec();
else
Dom.documentReady.then(exec);
return ChromeCalendar._session;
};
ChromeCalendar.close = function (session) {
if (session !== true && session != ChromeCalendar._session) return;
function exec() {
ChromeCalendar.followTarget = undefined;
ChromeCalendar._listener = undefined;
ChromeCalendar.$ctn.remove();
}
if (document.body) exec();
else Dom.documentReady.then(exec);
};
export default ChromeCalendar;