长城期货
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2965 lines
88 KiB

;(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.Calendar = factory();
}
}(this, function() {
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/**
* Calendar 类
*/
var Calendar =
/*#__PURE__*/
function () {
/**
* 构造函数
* ========================================================================
* @constructor
* @param {Object} [options] - 日历控件的配置参数
* @param [options.parent] - 日历显示的位置(DOM 节点 ID)
* @param [options.time] - 日历初始化显示的时间
* @param [options.viewMode] - 日历的试图模式:0 - 日期试图(默认值)
* 1 - 月份试图
* 2 - 年代试图
* @param [options.pickMode] - 日历的日期选择模式: single - 单选模式(默认值)
* multiple - 多选模式
* range - 范围选择模式
* week - 星期选择模式
* @param [options.hasSwitcher] - 是否显示上下切换按钮(默认值:true)
* @param [options.hasFooter] - 是否显示日历页脚(默认值:true)
* @param [options.hasClock] - 是否显示当前时间(默认值:true)
* @param [options.onDatePick] - 选择日期后的自定义事件处理器
* @param [options.onMonthPick] - 选择月份后的自定义事件处理器
* @param [options.onYearPick] - 选择年份后的自定义事件处理器
* @param [options.onTodayPick] - 点击当前日期的自定义事件处理器
* @param [options.MONTHS] - 月份常量(格式:去年11/12月 + 今天月份 + 明年1/2月)
* @param [options.DAYS] - 星期常量(周日为一周的第一天,周六为一周的最后一天)
* @param [options.DATES] - 月份天数常量(2月为28天,闰年则 28 + 1)
* @param [options.STYLES] - 日历控件的样式常量
* @returns {Calendar}
*/
function Calendar(options) {
_classCallCheck(this, Calendar);
/**
* Calendar 控件的配置属性
* ========================================================================
*/
this.attributes = {
// 日历显示的位置(DOM 节点 ID)
parent: '',
// 日历初始化显示的时间
time: '',
// 日历的试图模式:
// 0 - 日期试图(默认值)
// 1 - 月份试图
// 2 - 年代试图
viewMode: 0,
// 日历的日期选择模式
// single - 单选模式(默认值)
// multiple - 多选模式
// range - 范围选择模式
// week - 星期选择模式
pickMode: 'single',
// 是否显示上下切换按钮(默认值:true)
hasSwitcher: true,
// 是否显示日历页脚(默认值:true)
hasFooter: true,
// 是否显示当前时间(默认值:true)
hasClock: true,
// 选择日期后的自定义事件处理器
// time - 选中的日期时间范围
// $el - 点击的 DOM 节点
// calendar - 日历控件的实例
// onDatePick: function (time, $el, calendar) {
// console.log('选择时间:' + time)
// console.log('选择的 DOM 节点:' + $el)
// console.log('日历实例:' + calendar)
// },
onDatePick: null,
// 选择月份后的自定义事件处理器
// time - 选中的日期时间
// $el - 点击的 DOM 节点
// calendar - 日历控件的实例
// onMonthPick: function (time, $el, calendar) {
// console.log('选择时间:', time)
// console.log('选择DOM:', $el)
// console.log('日历实例:', calendar)
// }
onMonthPick: null,
// 选择年份后的自定义事件处理器
// time - 选中的日期时间
// $el - 点击的 DOM 节点
// calendar - 日历控件的实例
// onYearPick: function (time, $el, calendar) {
// console.log('选择时间:', time)
// console.log('选择DOM:', $el)
// console.log('日历实例:', calendar)
// }
onYearPick: null,
// 点击当前日期的自定义事件处理器
// time - 选中的日期时间
// $el - 点击的 DOM 节点
// calendar - 日历控件的实例
// onTodayPick: function (time, $el, calendar) {
// console.log('选择时间:', time)
// console.log('选择的 DOM 节点:', $el)
// console.log('日历实例:', calendar)
// }
onTodayPick: null,
// 月份常量
MONTHS: [],
// 星期常量
DAYS: [],
// 月份天数常量
DATES: [],
// 日历控件的样式常量
STYLES: {}
/**
* Calendar 控件相关的 DOM 节点属性
* ========================================================================
*/
};
this.elements = {
// 显示日历控件的父节点
parent: null,
// 日历控件的根节点
wrap: null,
// 日历控件的头部节点
header: null,
// 日历控件的标题节点
title: null,
// 日历控件的切换器节点
switcher: null,
// 日历控件向上切换按钮节点
prev: null,
// 日历控件向下切换按钮节点
next: null,
// 日历控件的主体内容节点
body: null,
// 日历控件的星期栏节点
week: null,
// 日历控件的日期显示节点
dates: null,
// 日历控件的月份显示节点
months: null,
// 日历控件的年代显示节点
years: null,
// 日历控件的页脚节点
footer: null,
// 日历控件的当前日期显示节点
today: null,
// 日历控件的当前时间显示节点
time: null
/**
* Calendar 控件相关的数据属性
* ========================================================================
*/
};
this.data = {
// 日历可以显示的最小年份
minYear: 0,
// 日历可以显示的最大年份
maxYear: 0,
// 当前选中日期的年份
year: 0,
// 当前选中日期的月份
month: 0,
// 选中的日期信息
date: {
// 年份
year: 0,
// 月份
month: 0,
// 日期
date: 0,
// 星期几
day: 0,
// 日期的英文表示(格式:2019-6-2)
text: '',
// 日期的完整中文表示(格式:2019年6月2日 星期日)
fullText: ''
},
// 多选(multiple/range/week)模式下,选中的日期数据
picked: [] // 执行初始化操作
// 绘制界面
// 绑定事件处理器
};
this.initialize(options).render().addEventListeners();
return this;
}
/**
* 初始化方法
* ========================================================================
* 1. 初始化配置信息;
* 2. 初始化数据信息;
* 3. 初始化 DOM 信息(创建控件相关的 DOM 节点);
* ========================================================================
* @param {Object} options - 配置信息
* @see this.attributes
* @returns {Calendar}
*/
_createClass(Calendar, [{
key: "initialize",
value: function initialize(options) {
var year = Calendar.getYear().value;
var pickMode;
var time;
var month;
var monthText;
var dateRanges;
var startDate;
var endDate; // 初始化配置
this.set(Calendar.defaults).set(options);
time = this.get('time');
pickMode = this.get('pickMode');
month = Calendar.getMonth(time);
monthText = month.text; // 初始化数据
this.setYear(time).setMonth(time).setDate(time)._setYears(time); // 初始化(多选模式)选中的时间
switch (pickMode) {
case 'multiple':
this.data.picked.push(this.getDate().text);
break;
case 'range':
startDate = monthText + '-' + 1;
endDate = monthText + '-' + this.get('DATES')[month.value - 1]; // 默认选中整个月
this.data.picked = [startDate, endDate];
break;
case 'week':
dateRanges = Calendar.getWeekRanges(time);
startDate = dateRanges[0];
endDate = dateRanges[dateRanges.length - 1]; // 默认选中配置日期所在的那个星期
this.data.picked = [startDate, endDate];
break;
} // 设置日历控件可以显示的年份范围
this.data.minYear = year - 100;
this.data.maxYear = year + 100; // 创建控件相关的 DOM 节点
this._createElements();
return this;
}
/**
* 绘制日历控件界面的方法
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "render",
value: function render() {
var elements = this.getEls();
var $wrap = elements.wrap;
var $header = elements.header;
var $switcher = elements.switcher;
var $body = elements.body;
var $footer = elements.footer;
var $fragment = document.createDocumentFragment(); // 绘制头部
this._renderTitle();
$header.appendChild(elements.title); // 配置了显示上下切换按钮
if (this.get('hasSwitcher')) {
$switcher.appendChild(elements.prev);
$switcher.appendChild(elements.next);
$header.appendChild($switcher);
} // 绘制星期栏
this._renderDays();
$body.appendChild(elements.week); // 绘制日期
this._renderDates();
$body.appendChild(elements.dates); // 绘制月份
this._renderMonths();
$body.appendChild(elements.months); // 绘制年代
this._renderYears();
$body.appendChild(elements.years); // 配置了显示页脚
if (this.get('hasFooter')) {
// 绘制页脚
this._renderFooter();
$footer.appendChild(elements.today); // 配置了显示当前时间
if (this.get('hasClock')) {
$footer.appendChild(elements.time);
}
} // 将主体模块绘制出来
$wrap.appendChild($header);
$wrap.appendChild($body); // 配置了显示页脚
if (this.get('hasFooter')) {
$wrap.appendChild($footer);
} // 将控件零时保存在文档碎片中
$fragment.appendChild($wrap); // 一次性绘制出整个日历控件
elements.parent.appendChild($fragment);
return this;
}
/**
* 给日历控件相关的 DOM 节点绑定事件处理器
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "addEventListeners",
value: function addEventListeners() {
var DOT = '.';
var STYLES = this.get('STYLES');
var CLICK = 'click';
var selectorTitle = DOT + STYLES.TITLE;
var selectorPrev = DOT + STYLES.PREV;
var selectorNext = DOT + STYLES.NEXT;
var selectorDate = DOT + STYLES.DATE;
var selectorMonth = DOT + STYLES.MONTH;
var selectorYear = DOT + STYLES.YEAR;
var selectorToday = DOT + STYLES.TODAY;
var Delegate = Calendar.Delegate;
var $wrap = this.getEls().wrap; // 绑定点击标题的事件处理器
Delegate.on($wrap, selectorTitle, CLICK, this._titleClick, this);
if (this.get('hasSwitcher')) {
// 绑定点击向上按钮的事件处理器
Delegate.on($wrap, selectorPrev, CLICK, this._prevClick, this); // 绑定点击向下按钮的事件处理器
Delegate.on($wrap, selectorNext, CLICK, this._nextClick, this);
} // 绑定点击日期的事件处理器
Delegate.on($wrap, selectorDate, CLICK, this._dateClick, this); // 绑定点击月份的事件处理器
Delegate.on($wrap, selectorMonth, CLICK, this._monthClick, this); // 绑定点击年份的事件处理器
Delegate.on($wrap, selectorYear, CLICK, this._yearClick, this);
if (this.get('hasClock')) {
// 绑定点击今天的事件处理器
Delegate.on($wrap, selectorToday, CLICK, this._todayClick, this);
}
return this;
}
/**
* 重启日历控件
* ========================================================================
* 1. 销毁日历控件:
* 1.1 移除所有的绑定的事件处理器
* 1.2 隐藏控件
* 1.3 移除所有 DOM 节点
* 1.4 重置所有属性
* 2. 初始化控件
* 3. 绘制控件
* 4. 绑定事件处理起
* ========================================================================
* @param {Object} options - 配置信息
* @see this.attributes
* @returns {Calendar}
*/
}, {
key: "reload",
value: function reload(options) {
this.destroy().initialize(options).render().addEventListeners();
return this;
}
/**
* 销毁日历控件
* ========================================================================
* 1 移除所有的绑定的事件处理器
* 2 隐藏控件
* 3 移除所有 DOM 节点
* 4 重置所有属性
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "destroy",
value: function destroy() {
this.removeEventListeners().hide().remove().reset();
return this;
}
/**
* 移除所有绑定的事件处理器
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "removeEventListeners",
value: function removeEventListeners() {
var CLICK = 'click';
var Delegate = Calendar.Delegate;
var $wrap = this.getEls().wrap;
Delegate.off($wrap, CLICK, this._titleClick);
if (this.get('hasSwitcher')) {
Delegate.off($wrap, CLICK, this._prevClick);
Delegate.off($wrap, CLICK, this._nextClick);
}
Delegate.off($wrap, CLICK, this._dateClick);
Delegate.off($wrap, CLICK, this._monthClick);
Delegate.off($wrap, CLICK, this._yearClick);
if (this.get('hasClock')) {
Delegate.off($wrap, CLICK, this._todayClick);
}
return this;
}
/**
* 移除所有 DOM 节点
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "remove",
value: function remove() {
var elements = this.getEls();
elements.parent.removeChild(elements.wrap);
return this;
}
/**
* 重置所有属性
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "reset",
value: function reset() {
this.attributes = {
parent: '',
time: '',
viewMode: 0,
pickMode: 'single',
hasSwitcher: true,
hasFooter: true,
hasClock: true,
MONTHS: [],
DAYS: [],
DATES: [],
STYLES: {}
};
this.elements = {
parent: null,
wrap: null,
header: null,
title: null,
switcher: null,
prev: null,
next: null,
body: null,
week: null,
dates: null,
months: null,
years: null,
footer: null,
today: null,
time: null,
year: null,
month: null,
date: null
};
this.data = {
minYear: 0,
maxYear: 0,
years: {
start: 0,
end: 0
},
year: 0,
month: 0,
date: {
year: 0,
month: 0,
date: 0,
day: 0,
text: '',
fullText: ''
},
picked: []
};
return this;
}
/**
* 获取配置信息
* ========================================================================
* @param {String} attr - 配置属性名称
* @returns {*} - 返回对应属性的值
*/
}, {
key: "get",
value: function get(attr) {
return this.attributes[attr];
}
/**
* 设置配置信息
* ========================================================================
* @param {Object} [options] - 配置信息对象
* @returns {Calendar}
*/
}, {
key: "set",
value: function set() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
Object.assign(this.attributes, options);
return this;
}
/**
* 获取日历控件所有相关的 DOM 节点的对象
* ========================================================================
* @see Calendar.elements
* @returns {Object}
*/
}, {
key: "getEls",
value: function getEls() {
return this.elements;
}
/**
* 获取日历控件当前显示的年份信息
* ========================================================================
* @returns {Number} - 返回日历控件当前显示的年份
*/
}, {
key: "getYear",
value: function getYear() {
return this.data.year;
}
/**
* 设置日历控件当前的年份
* ========================================================================
* @param {String|Number} [time] - 表示年份的字符串或数字(默认值:今年)
* 字符串格式:'2019'、'2019-2' 或 '2019-2-2'
* 数字格式: 1546300800000
* @returns {Calendar}
*/
}, {
key: "setYear",
value: function setYear(time) {
this.data.year = Calendar.getYear(time).value;
return this;
}
/**
* 获得日历控件当前显示的月份信息
* ========================================================================
* @returns {Number} - 返回日历控件当前显示的月份
*/
}, {
key: "getMonth",
value: function getMonth() {
return this.data.month;
}
/**
* 设置日历控件当前显示的月份
* ========================================================================
* @param {String|Number} [time] - 表示月份的字符串或数字(默认值:本月)
* @returns {Calendar}
*/
}, {
key: "setMonth",
value: function setMonth(time) {
this.data.month = Calendar.getMonth(time).value;
return this;
}
/**
* 获取日历控件当前选中的日期
* ========================================================================
* @returns {Object} - 返回日历控件当前选中的日期
*/
}, {
key: "getDate",
value: function getDate() {
return this.data.date;
}
/**
* 设置日历控件当前选中的日期
* ========================================================================
* @param {String|Number} [time] - 表示日期的字符串或者数字(默认值:今天)
* @returns {Calendar}
*/
}, {
key: "setDate",
value: function setDate(time) {
this.data.date = Calendar.getDate(time);
return this;
}
/**
* 获取日历控件当前显示的年份所在的年代信息
* ========================================================================
* @returns {Object} - 返回当前所在年代信息
*/
}, {
key: "getYears",
value: function getYears() {
return this.data.years;
}
/**
* 获取日历控件在多选(multiple/range/week)模式下选中的日期信息
* ========================================================================
* @returns {Array} - 返回选中的日期信息
*/
}, {
key: "getPicked",
value: function getPicked() {
return this.data.picked;
}
/**
* 根据试图显示模式
* ========================================================================
* 1. 切换日历控件的显示模式
* 2. 更新显示内容
* ========================================================================
* @param {Number} viewMode - 显示模式的值:
* 0 - 日期显示模式(默认值)
* 1 - 月份显示模式
* 2 - 年代显示模式
* @returns {Calendar}
*/
}, {
key: "update",
value: function update() {
var viewMode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
this.updateViewMode(viewMode).updateView();
return this;
}
/**
* 更新试图显示模式的配置信息
* ========================================================================
* @param {Number} viewMode - 显示模式的值(默认值:0)
* @see this.update
* @returns {Calendar}
*/
}, {
key: "updateViewMode",
value: function updateViewMode() {
var viewMode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
var mode = viewMode;
if (mode > 2) {
mode = 2;
} else {
if (mode < 0) {
mode = 0;
}
}
this.set({
viewMode: mode
});
return this;
}
/**
* 更新日历控件的显示内容
* ========================================================================
* 1. 更新标题内容
* 1.1 日期显示模式:显示年份和月份
* 1.2 月份显示模式:显示年份
* 1.3 年份显示模式:显示年代区间信息
* 2. 更细主体内容
* 2.1 日期显示模式:隐藏年份和月份的 DOM 节点,显示星期栏和日期信息
* 2.2 月份显示模式:隐藏年份、星期栏以及日期信息
* 2.3 年份显示模式:隐藏月份 DOM 节点、星期栏以及日期信息
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "updateView",
value: function updateView() {
var STYLES = this.get('STYLES');
var CLS_HIDDEN = STYLES.HIDDEN;
var DOM = Calendar.DOM;
var addClass = DOM.addClass;
var removeClass = DOM.removeClass;
var elements = this.getEls();
var $week = elements.week;
var $dates = elements.dates;
var $months = elements.months;
var $years = elements.years;
this._renderTitle();
switch (this.get('viewMode')) {
// 日期显示模式
case 0:
addClass($months, CLS_HIDDEN);
addClass($years, CLS_HIDDEN);
removeClass($week, CLS_HIDDEN);
removeClass($dates, CLS_HIDDEN); // 重新绘制日期
this._repaintDates();
break;
// 月份显示模式
case 1:
addClass($week, CLS_HIDDEN);
addClass($dates, CLS_HIDDEN);
addClass($years, CLS_HIDDEN);
removeClass($months, CLS_HIDDEN); // 重新绘制月份
this._repaintMonths();
break;
// 年份显示模式
case 2:
addClass($week, CLS_HIDDEN);
addClass($dates, CLS_HIDDEN);
addClass($months, CLS_HIDDEN);
removeClass($years, CLS_HIDDEN); // 重新绘制年份
this._repaintYears();
break;
}
return this;
}
/**
* 向上翻页
* ========================================================================
* 1. 日期显示模式:向上翻页,显示上一个月份的日期信息
* 2. 月份显示模式:向上翻页,显示上一年的月份信息
* 3. 年份显示模式:向上翻页,显示上一个年代(10前)的年份信息
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "prev",
value: function prev() {
var years = this.getYears();
var startYear = years.start;
var year = this.getYear();
var month = this.getMonth();
var minYear = this.data.minYear;
var time; // 针对显示模式,处理相应的翻页逻辑
switch (this.get('viewMode')) {
// 日期显示模式
case 0:
// 切换月份
month -= 1; // 到了上一年,切换年份
if (month < 1) {
month = 12;
year -= 1; // 确保不小于最小可以显示的年份
if (year < minYear) {
year = minYear;
}
}
time = year + '-' + month + '-1';
this.setYear(time).setMonth(time);
break;
case 1:
// 切换年份
year -= 1;
if (year < minYear) {
year = minYear;
}
this.setYear(year + '-1-1');
break;
case 2:
// 切换年代
startYear -= 10;
if (startYear < minYear) {
startYear = minYear + 9;
}
this._setYears(startYear.toString());
break;
} // 更新显示内容
this.updateView();
return this;
}
/**
* 向下翻页
* ========================================================================
* 1. 日期显示模式:向下翻页,显示下一个月份的日期信息
* 2. 月份显示模式:向下翻页,显示下一年的月份信息
* 3. 年份显示模式:向下翻页,显示下一个年代(10后)的年份信息
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "next",
value: function next() {
var years = this.getYears();
var startYear = years.start;
var year = this.getYear();
var month = this.getMonth();
var maxYear = this.data.maxYear;
var time;
switch (this.get('viewMode')) {
case 0:
month += 1;
if (month > 12) {
month = 1;
year += 1;
if (year > maxYear) {
year = maxYear;
}
}
time = year + '-' + month + '-1';
this.setYear(time).setMonth(time);
break;
case 1:
year += 1;
if (year > maxYear) {
year = maxYear;
}
this.setYear(year + '-1-1');
break;
case 2:
startYear += 10;
if (startYear > maxYear) {
startYear = maxYear - 9;
}
this._setYears(startYear.toString());
break;
}
this.updateView();
return this;
}
/**
* 选择日期
* ========================================================================
* 1. 选择了选中状态的日期:
* 1.1 星期区间和单选模式:不做任何处理
* 1.2 多选模式:取消选中 DOM 节点的选中状态,并且将选中的日期在选中信息移除
* 1.3 日期区间选择模式下:取消之前选中区间的选中样式,将当前选中的日期 DOM 节点
* 设置为选中状态。移除之前选中日期信息,并将选中日期信息保存起来
* 2. 选择了未选中状态的日期:
* 2.1 单选模式:获取选中日期信息,并用这个信息替换之前选中的信息。移除之前选中样
* 式,并设置当前选中日期的选中样式
* 2.2 多选模式:获取选中的日期信息,然后保存到选中信息中,最后设置选中日期的样式
* 2.3 日期区间选择模式下:
* 2.4 星期区间选择模式:获取当前选择日期的星期区间信息,移除之前保存的区间信息将
* 新的区间信息保存起来,移除之前的区间选中样式,并设置当前选中区间的选中样式
* ========================================================================
* @param {HTMLElement} $date - 选中的日期 DOM 节点
* @returns {*}
*/
}, {
key: "pickDate",
value: function pickDate($date) {
var STYLES = this.get('STYLES');
var CLS_PICKED = STYLES.PICKED;
var DOM = Calendar.DOM;
var hasClass = DOM.hasClass;
var addClass = DOM.addClass;
var removeClass = DOM.removeClass;
var isFunction = Calendar.Utils.isFunction;
var pickMode = this.get('pickMode');
var elements = this.getEls();
var time = $date.getAttribute('data-date');
var callback = this.get('onDatePick');
var $picked = null;
var pickedDates; // 选择了选中状态的日期
if (hasClass($date, CLS_PICKED)) {
switch (pickMode) {
// 单选/星期选择模式
case 'single':
case 'week':
return false;
// 多选模式
case 'multiple':
// 取消选中样式
removeClass($date, CLS_PICKED); // 移除选中的日期信息
this._removePicked(time); // 设置最后一个选中的时间为当前选中日期
pickedDates = this.getPicked();
this.setDate(pickedDates[pickedDates.length - 1]);
if (isFunction(callback)) {
callback(pickedDates, $date, this);
}
break;
case 'range':
// 清除之前选中的数据
this.data.picked = []; // 将当前选中的日期数据保存起来
this.data.picked.push(time);
this.setDate(time); // 绘制选中样式
elements.date = $date;
this._updateDateRanges();
if (isFunction(callback)) {
callback(this.getPicked(), $date, this);
}
break;
}
} else {
this.setYear(time).setMonth(time); // 选择了未选中状态的日期
switch (pickMode) {
case 'single':
$picked = elements.date; // 移除之前选中日期的选中样式
if ($picked) {
removeClass($picked, CLS_PICKED);
} // 设置当前选中日期的选中样式
addClass($date, CLS_PICKED);
elements.date = $date;
this.setDate(time);
if (isFunction(callback)) {
callback(time, $date, this);
}
break;
case 'multiple':
// 保存选中的日期,并对选中时间排序
this.data.picked.push(time);
this.data.picked.sort(); // 设置最晚的那个日期为当前选中日期
pickedDates = this.getPicked();
this.setDate(pickedDates[pickedDates.length - 1]);
addClass($date, CLS_PICKED);
if (isFunction(callback)) {
callback(this.getPicked(), $date, this);
}
break;
case 'range':
// 根据已经选中的日期长度,处理数据的保存
switch (this.data.picked.length) {
case 0:
case 1:
// 保存选中的日期
this.data.picked.push(time); // 如果选择两个不同的日期,则完成了范围选择,需要对日期排序
if (this.data.picked.length === 2) {
this.data.picked.sort();
} // 设置选中日期范围的最后一天为当前选中日期
pickedDates = this.getPicked();
this.setDate(pickedDates[pickedDates.length - 1]);
elements.date = $date;
this._updateDateRanges();
if (isFunction(callback)) {
callback(pickedDates, $date, this);
}
break;
case 2:
// 之前已经选中了一个日期范围,现在需要清除之前的数据
this.data.picked = []; // 保存第一个日期点
this.data.picked.push(time);
elements.date = $date;
this._updateDateRanges();
break;
}
break;
case 'week':
// 获得当前选中日期的星期范围
var ranges = Calendar.getWeekRanges(time); // 清除之前的数据,保存现在的星期日期范围
this.data.picked = [ranges[0], ranges[ranges.length - 1]];
this.setDate(ranges[ranges.length - 1]);
elements.date = $date;
this._updateWeekRanges();
if (isFunction(callback)) {
callback(this.getPicked(), $date, this);
}
break;
}
}
return this;
}
/**
* 选择月份
* ========================================================================
* 1. 选择了已选中状态的月份:直接切换试图模式到日期试图模式
* 2. 选择了未选中状态的月份:移除之前选中的月份的选中样式,并当前选中的月份的选中
* 样式。然后更新选中年份和月份的数据,并切换到日期试图模式
* ========================================================================
* @param {HTMLElement} $month - 选中的月份 DOM 节点
* @returns {Calendar}
*/
}, {
key: "pickMonth",
value: function pickMonth($month) {
var CLS_PICKED = this.get('STYLES').PICKED;
var DOM = Calendar.DOM;
var elements = this.getEls();
var $picked = elements.month;
var time = $month.getAttribute('data-month');
var callback = this.get('onMonthPick'); // 点击已经选中的年份
if (DOM.hasClass($month, CLS_PICKED)) {
// 切换到月份试图模式
this.update();
} else {
// 移除之前选中的年份选中样式
if ($picked) {
DOM.removeClass($picked, CLS_PICKED);
} // 设置选中样式
DOM.addClass($month, CLS_PICKED);
elements.month = $month;
this.setYear(time).setMonth(time)._setYears(time).update();
}
if (Calendar.Utils.isFunction(callback)) {
callback(time, $month, this);
}
return this;
}
/**
* 选择年份
* ========================================================================
* 1. 选择了已选中状态的年份:更新选中的年份信息,并切换到月份试图模式
* 2. 选择了未选中状态的年份:移除之前选中的年份的选中样式,将当前选中的年份设为选中
* 样式,并切换到月份试图模式
* ========================================================================
* @param {HTMLElement} $year - 选中的年份 DOM 节点
* @returns {Calendar}
*/
}, {
key: "pickYear",
value: function pickYear($year) {
var CLS_PICKED = this.get('STYLES').PICKED;
var DOM = Calendar.DOM;
var elements = this.getEls();
var $picked = elements.year;
var time = $year.getAttribute('data-year');
var callback = this.get('onYearPick'); // 点击已经选中的月份
if (DOM.hasClass($year, CLS_PICKED)) {
// 切换到日期试图模式
this.setYear(time).update(1);
} else {
// 移除之前选中的年份选中样式
if ($picked) {
DOM.removeClass($picked, CLS_PICKED);
} // 设置选中样式
DOM.addClass($year, CLS_PICKED);
elements.year = $year; // 更新年份并切换到月份试图
this.setYear(time)._setYears(time).update(1);
}
if (Calendar.Utils.isFunction(callback)) {
callback(time, $year, this);
}
return this;
}
/**
* 选择今天
* ========================================================================
* 将今天的年份、月份以及日期信息设置为当前选中日期,并切换到日期试图模式
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "pickToday",
value: function pickToday() {
var time = Calendar.getToday().value;
var callback = this.get('onTodayPick');
this.setYear(time).setMonth(time).setDate(time)._setYears(time).update();
if (Calendar.Utils.isFunction(callback)) {
callback(time, this.getEls().dates.querySelector('[data-date=' + time + ']'), this);
}
return this;
}
/**
* 隐藏日历控件
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "hide",
value: function hide() {
var CLS_HIDDEN = this.get('STYLES').HIDDEN;
var $wrap = this.getEls().wrap;
Calendar.DOM.addClass($wrap, CLS_HIDDEN);
return this;
}
/**
* 显示日历控件
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "show",
value: function show() {
var CLS_HIDDEN = this.get('STYLES').HIDDEN;
var $wrap = this.getEls().wrap;
Calendar.DOM.removeClass($wrap, CLS_HIDDEN);
return this;
}
/**
* 隐藏/显示之间切换
* ========================================================================
* @returns {Calendar}
*/
}, {
key: "toggle",
value: function toggle() {
var CLS_HIDDEN = this.get('STYLES').HIDDEN;
var $wrap = this.getEls().wrap;
if (Calendar.DOM.hasClass($wrap, CLS_HIDDEN)) {
this.show();
} else {
this.hide();
}
return this;
}
/**
* 设置当前的年代信息
* ========================================================================
* @param {String|Number} [time] - 表示年份的字符串或者数字(默认值:今年)
* @returns {Calendar}
* @private
*/
}, {
key: "_setYears",
value: function _setYears(time) {
this.data.years = Calendar.getYears(time);
return this;
}
/**
* (多选模式)移除选中的日期
* ========================================================================
* @param {String|Number} time - 表示日期的字符串或者数字
* @returns {Calendar}
* @private
*/
}, {
key: "_removePicked",
value: function _removePicked(time) {
var pickedDates = this.getPicked();
var index = pickedDates.indexOf(time);
if (index > -1) {
pickedDates.splice(index, 1);
}
return this;
}
/**
* 绘制日历控件的各个主要 DOM 节点
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_createElements",
value: function _createElements() {
var STYLES = this.get('STYLES');
var CLS_WRAP = STYLES.WRAP;
var CLS_WRAP_WITHOUT_FOOTER = STYLES.WRAP_WITHOUT_FOOTER;
var CLS_HEADER = STYLES.HEADER;
var CLS_TITLE = STYLES.TITLE;
var CLS_SWITCHER = STYLES.SWITCHER;
var CLS_PREV = STYLES.PREV;
var CLS_ICON_PREV = STYLES.ICON_PREV;
var CLS_NEXT = STYLES.NEXT;
var CLS_ICON_NEXT = STYLES.ICON_NEXT;
var CLS_BODY = STYLES.BODY;
var CLS_WEEK = STYLES.WEEK;
var CLS_DATES = STYLES.DATES;
var CLS_MONTHS = STYLES.MONTHS;
var CLS_YEARS = STYLES.YEARS;
var CLS_FOOTER = STYLES.FOOTER;
var CLS_FOOTER_DATE = STYLES.FOOTER_DATE;
var CLS_TODAY = STYLES.TODAY;
var CLS_FOOTER_TIME = STYLES.FOOTER_TIME;
var CLS_TIME = STYLES.TIME;
var CLS_TEXT = STYLES.TEXT;
var CLS_HIDDEN = STYLES.HIDDEN;
var SPACE = ' ';
var hasFooter = this.get('hasFooter');
var elements = this.getEls();
var createElement = Calendar.DOM.createElement;
var wrapClassName = CLS_WRAP;
var weekClassName = CLS_WEEK;
var datesClassName = CLS_DATES;
var monthsClassName = CLS_MONTHS;
var yearsClassName = CLS_YEARS;
switch (this.get('viewMode')) {
case 0:
monthsClassName += SPACE + CLS_HIDDEN;
yearsClassName += SPACE + CLS_HIDDEN;
break;
case 1:
weekClassName += SPACE + CLS_HIDDEN;
datesClassName += SPACE + CLS_HIDDEN;
yearsClassName += SPACE + CLS_HIDDEN;
break;
case 2:
weekClassName += SPACE + CLS_HIDDEN;
datesClassName += SPACE + CLS_HIDDEN;
monthsClassName += SPACE + CLS_HIDDEN;
break;
}
if (!hasFooter) {
wrapClassName += SPACE + CLS_WRAP_WITHOUT_FOOTER;
}
elements.parent = document.getElementById(this.get('parent')); // wrap
elements.wrap = createElement('div', {
id: Calendar.Utils.guid('calendar'),
className: wrapClassName
}); // header
elements.header = createElement('div', {
className: CLS_HEADER
});
elements.title = createElement('h4', {
className: CLS_TITLE
}, [createElement('span', {
className: CLS_TEXT
})]); // 配置了显示上下切换按钮
if (this.get('hasSwitcher')) {
elements.switcher = createElement('div', {
className: CLS_SWITCHER
});
elements.prev = createElement('div', {
className: CLS_PREV
}, [createElement('span', {
className: CLS_TEXT
}, [createElement('i', {
className: CLS_ICON_PREV
})])]);
elements.next = createElement('div', {
className: CLS_NEXT
}, [createElement('span', {
className: CLS_TEXT
}, [createElement('i', {
className: CLS_ICON_NEXT
})])]);
} // body
elements.body = createElement('div', {
className: CLS_BODY
});
elements.week = createElement('div', {
className: weekClassName
});
elements.dates = createElement('div', {
className: datesClassName
});
elements.months = createElement('div', {
className: monthsClassName
});
elements.years = createElement('div', {
className: yearsClassName
}); // 配置了显示页脚
if (hasFooter) {
// footer
elements.footer = createElement('div', {
className: CLS_FOOTER
});
elements.today = createElement('div', {
className: CLS_FOOTER_DATE
}, [createElement('p', {
className: CLS_TODAY
}, [createElement('span', {
className: CLS_TEXT
})])]); // 配置了显示当前时间
if (this.get('hasClock')) {
elements.time = createElement('div', {
className: CLS_FOOTER_TIME
}, [createElement('p', {
className: CLS_TIME
}, [createElement('span', {
className: CLS_TEXT
})])]);
}
}
return this;
}
/**
* 绘制日历控件的标题
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_renderTitle",
value: function _renderTitle() {
var $title = this.getEls().title.querySelector('.' + this.get('STYLES').TEXT);
var years = this.getYears();
var year = this.getYear();
var value = '';
switch (this.get('viewMode')) {
case 0:
// 显示完整的年月时间
value = Calendar.getMonth(year + '-' + this.getMonth() + '-1').fullText;
break;
case 1:
// 显示年份时间
value = Calendar.getYear(year + '-1-1').fullText;
break;
case 2:
// 显示年代范围格式时间
value = years.start + ' - ' + years.end;
break;
}
$title.innerHTML = value;
return this;
}
/**
* 绘制日历控件的星期栏
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_renderDays",
value: function _renderDays() {
var STYLES = this.get('STYLES');
var CLS_DAY = STYLES.DAY;
var CLS_WEEKEND = STYLES.WEEKEND;
var CLS_TEXT = STYLES.TEXT;
var DAYS = this.get('DAYS');
var createElement = Calendar.DOM.createElement;
var fragment = document.createDocumentFragment();
DAYS.forEach(function (day, i) {
var className = i === 0 || i === DAYS.length - 1 ? CLS_DAY + ' ' + CLS_WEEKEND : CLS_DAY; // 先将创建的星期几的 DOM 节点保存到文档碎片
fragment.appendChild(createElement('div', {
className: className
}, [createElement('span', {
className: CLS_TEXT
}, [day])]));
}); // 然后一次性添加到页面,性能会更好
this.getEls().week.appendChild(fragment);
return this;
}
/**
* 绘制日历控件的日期信息
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_renderDates",
value: function _renderDates() {
var DATES = this.get('DATES');
var isLeapYear = Calendar.isLeapYear; // fragments
var fragment = document.createDocumentFragment(); // current month
var year = this.getYear();
var month = this.getMonth();
var days = DATES[month - 1];
var firstDateDay = Calendar.getDay(year + '-' + month + '-' + 1).value; // prev month
var prevYear = month - 2 < 0 ? year - 1 : year;
var prevMonth = month - 2 < 0 ? 12 : month - 1;
var prevDays = DATES[prevMonth - 1]; // next month
var nextYear = month === 12 ? year + 1 : year;
var nextMonth = month === 12 ? 1 : month + 1;
var nextDays; // 如果当前是闰年,上个月是二月份,则闰年二月为29天
if (isLeapYear(year) && prevMonth === 2) {
prevDays += 1;
} else {
// 如果当前是闰年,当前月份是二月,则本月有29天
if (isLeapYear(year) && month === 2) {
days += 1;
}
}
nextDays = 42 - (firstDateDay + days); // 绘制上个月月底的最后几天
if (firstDateDay !== 0) {
fragment.appendChild(this._getDatesFragment({
year: prevYear,
month: prevMonth,
start: prevDays - (firstDateDay - 1),
end: prevDays,
isPrev: true,
isNext: false
}));
} // 绘制本月的日期
fragment.appendChild(this._getDatesFragment({
year: year,
month: month,
start: 1,
end: days,
isPrev: false,
isNext: false
})); // 绘制下个月月头的几天
if (nextDays > 0) {
fragment.appendChild(this._getDatesFragment({
year: nextYear,
month: nextMonth,
start: 1,
end: nextDays,
isPrev: false,
isNext: true
}));
}
this.getEls().dates.appendChild(fragment);
return this;
}
/**
* 重绘日历控件的日期信息
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_repaintDates",
value: function _repaintDates() {
var CLS_HIDDEN = this.get('STYLES').HIDDEN;
var DOM = Calendar.DOM;
var $dates = this.getEls().dates;
DOM.addClass($dates, CLS_HIDDEN);
$dates.innerHTML = '';
DOM.removeClass($dates, CLS_HIDDEN);
this._renderDates();
return this;
}
/**
* 获得绘制日期信息时的文档碎片
* ========================================================================
* @param {Object} options - 参数对象
* @param {Number} options.year - 年份
* @param {Number} options.month - 月份
* @param {Number} options.start - 开始的日期
* @param {Number} options.end - 结束的日期
* @param {Boolean} options.isPrev - 是否为上个月的日期
* @param {Boolean} options.isNext - 是否为下个月的日期
* @returns {DocumentFragment}
* @private
*/
}, {
key: "_getDatesFragment",
value: function _getDatesFragment(options) {
var _this = this;
var year = options.year,
month = options.month,
start = options.start,
end = options.end,
isPrev = options.isPrev,
isNext = options.isNext;
var SPACE = ' ';
var STYLES = this.get('STYLES');
var CLS_DATE = STYLES.DATE;
var CLS_DATE_PREV = STYLES.DATE_PREV;
var CLS_DATE_NEXT = STYLES.DATE_NEXT;
var CLS_CURRENT = STYLES.CURRENT;
var CLS_PICKED = STYLES.PICKED;
var CLS_PICKED_RANGE = STYLES.PICKED_RANGE;
var CLS_WEEKEND = STYLES.WEEKEND;
var CLS_TEXT = STYLES.TEXT;
var createElement = Calendar.DOM.createElement;
var isDatesEqual = Calendar.isDatesEqual;
var fragment = document.createDocumentFragment();
var elements = this.getEls();
var date = start;
var pickMode = this.get('pickMode');
var pickedDates = this.getPicked();
var _loop = function _loop() {
var fullDate = year + '-' + month + '-' + date;
var isCurrent = Calendar.isToday(fullDate);
var day = Calendar.getDay(fullDate);
var $children = [createElement('span', {
className: CLS_TEXT
}, [date])];
var className = '';
var $date = void 0;
$date = createElement('div', {
'data-date': fullDate
}, $children);
className += CLS_DATE;
if (isPrev) {
className += SPACE + CLS_DATE_PREV;
} else {
if (isNext) {
className += SPACE + CLS_DATE_NEXT;
}
} // 当前(今天)的日期
if (isCurrent) {
className += SPACE + CLS_CURRENT;
} // 周末
if (day.value === 0 || day.value === 6) {
className += SPACE + CLS_WEEKEND;
}
switch (pickMode) {
// 单选模式
case 'single':
var pickedDate = _this.getDate().text;
var isPickedDate = isDatesEqual(fullDate, pickedDate);
if (isPickedDate) {
className += SPACE + CLS_PICKED;
elements.date = $date;
}
break;
// 多选模式
case 'multiple':
pickedDates.forEach(function (picked) {
var isPicked = isDatesEqual(fullDate, picked);
if (isPicked) {
className += SPACE + CLS_PICKED;
}
});
break;
// 区间模式
case 'range':
case 'week':
var dateRanges = []; // 只有选中了两个节点,才绘制选中日期区间的样式
if (pickedDates.length === 2) {
dateRanges = Calendar.getRanges(pickedDates[0], pickedDates[1]);
dateRanges.forEach(function (picked, i) {
var isPicked = isDatesEqual(fullDate, picked);
if (!isPicked) {
return false;
} // 设置中间日期的样式
if (i !== 0 && i !== dateRanges.length - 1) {
className += SPACE + CLS_PICKED;
className += SPACE + CLS_PICKED_RANGE;
} else {
if (i === 0 || i === dateRanges.length - 1) {
className += SPACE + CLS_PICKED;
}
}
});
} else {
if (pickedDates.length === 1) {
className += SPACE + CLS_PICKED;
}
}
break;
}
$date.className = className;
fragment.appendChild($date);
};
for (; date <= end; date += 1) {
_loop();
}
return fragment;
}
/**
* 绘制选中的日期区间选中样式
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_updateDateRanges",
value: function _updateDateRanges() {
var STYLES = this.get('STYLES');
var CLS_PICKED = STYLES.PICKED;
var CLS_PICKED_RANGE = STYLES.PICKED_RANGE;
var DOM = Calendar.DOM;
var hasClass = DOM.hasClass;
var removeClass = DOM.removeClass;
var addClass = DOM.addClass;
var elements = this.getEls();
var $date = this.elements.date;
var $dates = elements.dates;
var $pickedDates = $dates.querySelectorAll('.' + CLS_PICKED);
switch (this.data.picked.length) {
case 1:
// 移除之前的选中样式
$pickedDates.forEach(function ($picked) {
removeClass($picked, CLS_PICKED);
if (hasClass($picked, CLS_PICKED_RANGE)) {
removeClass($picked, CLS_PICKED_RANGE);
}
}); // 绘制选中的第一个端点的选中样式
addClass($date, CLS_PICKED);
break;
case 2:
var ranges = Calendar.getRanges(this.data.picked[0], this.data.picked[1]);
ranges.forEach(function (picked, i) {
var $picked = $dates.querySelector('[data-date="' + picked + '"]'); // 绘制中间区域的选中样式
if (i > 0 && i < ranges.length - 1) {
addClass($picked, CLS_PICKED);
addClass($picked, CLS_PICKED_RANGE);
}
}); // 绘制选中的第二个端点的选中样式
addClass($date, CLS_PICKED);
}
return this;
}
/**
* 绘制选中的星期区间
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_updateWeekRanges",
value: function _updateWeekRanges() {
var STYLES = this.get('STYLES');
var CLS_PICKED = STYLES.PICKED;
var CLS_PICKED_RANGE = STYLES.PICKED_RANGE;
var DOM = Calendar.DOM;
var removeClass = DOM.removeClass;
var addClass = DOM.addClass;
var elements = this.getEls();
var $dates = elements.dates;
var $pickedDates = $dates.querySelectorAll('.' + CLS_PICKED);
var picked = this.getPicked();
var ranges = Calendar.getWeekRanges(picked[0]); // 移除之前选中区域的样式
$pickedDates.forEach(function ($picked) {
removeClass($picked, CLS_PICKED_RANGE);
removeClass($picked, CLS_PICKED);
}); // 设置新的选中区域的样式
ranges.forEach(function (picked, i) {
var $picked = $dates.querySelector('[data-date="' + picked + '"]'); // 绘制中间区域
if (i > 0 && i < ranges.length - 1) {
addClass($picked, CLS_PICKED);
addClass($picked, CLS_PICKED_RANGE);
} else {
// 绘制两头的节点
if (i === 0 || i === ranges.length - 1) {
addClass($picked, CLS_PICKED);
}
}
});
return this;
}
/**
* 绘制日历控件的月份信息
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_renderMonths",
value: function _renderMonths() {
var _this2 = this;
var SPACE = ' ';
var STYLES = this.get('STYLES');
var CLS_CURRENT = STYLES.CURRENT;
var CLS_PICKED = STYLES.PICKED;
var CLS_MONTH = STYLES.MONTH;
var CLS_MONTH_PREV = STYLES.MONTH_PREV;
var CLS_MONTH_NEXT = STYLES.MONTH_NEXT;
var CLS_TEXT = STYLES.TEXT;
var MONTHS = this.get('MONTHS');
var DOM = Calendar.DOM;
var createElement = DOM.createElement;
var fragment = document.createDocumentFragment();
var elements = this.getEls();
var year = this.getYear();
var today = Calendar.getToday();
MONTHS.forEach(function (MONTH, i) {
var pickedDate = _this2.getDate();
var className = CLS_MONTH;
var $month; // 去年的月份
if (i < 2) {
className += SPACE + CLS_MONTH_PREV; // 判断是否被选中了
if (year - 1 === pickedDate.year && MONTH === pickedDate.month) {
className += SPACE + CLS_PICKED;
} // 创建月份的 DOM 节点
$month = createElement('div', {
className: className,
'data-month': year - 1 + '-' + MONTH + '-1'
}, [createElement('span', {
className: CLS_TEXT
}, [MONTH])]);
} else {
// 今年的月份
if (i >= 2 && i <= 13) {
// 判断是否为今天
if (year === today.year && MONTH === today.month) {
className += ' ' + CLS_CURRENT;
} // 判断是否被选中了
if (year === pickedDate.year && MONTH === pickedDate.month) {
className += SPACE + CLS_PICKED;
} // 创建月份的 DOM 节点
$month = createElement('div', {
className: className,
'data-month': year + '-' + MONTH + '-1'
}, [createElement('span', {
className: CLS_TEXT
}, [year + '-' + MONTH])]);
} else {
// 明年的月份
if (i > 13 && i <= 15) {
className += SPACE + CLS_MONTH_NEXT; // 判断是否被选中了
if (year + 1 === pickedDate.year && MONTH === pickedDate.month) {
className += SPACE + CLS_PICKED;
} // 创建月份的 DOM 节点
$month = createElement('div', {
className: className,
'data-month': year + 1 + '-' + MONTH + '-1'
}, [createElement('span', {
className: CLS_TEXT
}, [MONTH])]);
}
}
} // 将所有月份 DOM 节点缓存到文档碎片中
fragment.appendChild($month);
});
elements.months.appendChild(fragment);
return this;
}
/**
* 重绘日历控件的月份信息
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_repaintMonths",
value: function _repaintMonths() {
var CLS_HIDDEN = this.get('STYLES').HIDDEN;
var DOM = Calendar.DOM;
var $months = this.getEls().months;
DOM.addClass($months, CLS_HIDDEN);
$months.innerHTML = '';
DOM.removeClass($months, CLS_HIDDEN);
this._renderMonths();
return this;
}
/**
* 绘制日历控件的年份信息
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_renderYears",
value: function _renderYears() {
var years = this.getYears();
var yearsStart = years.start;
var yearsEnd = years.end;
var prevStartYear = yearsStart - 3;
var prevEndYear = yearsStart - 1;
var nextStartYear = yearsEnd + 1;
var nextEndYear = yearsEnd + 3;
var fragment = document.createDocumentFragment();
fragment.appendChild(this._getYearsFragment({
start: prevStartYear,
end: prevEndYear,
isPrev: true,
isNext: false
}));
fragment.appendChild(this._getYearsFragment({
start: yearsStart,
end: yearsEnd,
isPrev: false,
isNext: false
}));
fragment.appendChild(this._getYearsFragment({
start: nextStartYear,
end: nextEndYear,
isPrev: false,
isNext: true
}));
this.getEls().years.appendChild(fragment);
return this;
}
/**
* 重绘日历控件的年份信息
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_repaintYears",
value: function _repaintYears() {
var CLS_HIDDEN = this.get('STYLES').HIDDEN;
var DOM = Calendar.DOM;
var $years = this.getEls().years;
DOM.addClass($years, CLS_HIDDEN);
$years.innerHTML = '';
DOM.removeClass($years, CLS_HIDDEN);
this._renderYears();
return this;
}
/**
* 获取绘制年份信息的文档碎片
* ========================================================================
* @param {Object} options - 参数对象
* @param {Number} options.start - 开始年份
* @param {Number} options.end - 结束年份
* @param {Boolean} options.isPrev - 是否为上个年代的年份
* @param {Boolean} options.isNext - 是否为下个年带的年份
* @returns {DocumentFragment}
* @private
*/
}, {
key: "_getYearsFragment",
value: function _getYearsFragment(options) {
var start = options.start,
end = options.end,
isPrev = options.isPrev,
isNext = options.isNext;
var STYLES = this.get('STYLES');
var CLS_YEAR = STYLES.YEAR;
var CLS_YEAR_PREV = STYLES.YEAR_PREV;
var CLS_YEAR_NEXT = STYLES.YEAR_NEXT;
var CLS_CURRENT = STYLES.CURRENT;
var CLS_PICKED = STYLES.PICKED;
var CLS_DISABLED = STYLES.DISABLED;
var CLS_TEXT = STYLES.TEXT;
var DOM = Calendar.DOM;
var createElement = DOM.createElement;
var fragment = document.createDocumentFragment();
var elements = this.getEls();
var minYear = this.data.minYear;
var maxYear = this.data.maxYear;
var year = start;
for (; year <= end; year += 1) {
var pickedDate = this.getDate();
var isCurrent = year === Calendar.getToday().year;
var isPicked = year === pickedDate.year;
var className = CLS_YEAR;
var $year = createElement('div', {
'data-year': year + '-1-1'
}, [createElement('span', {
className: CLS_TEXT
}, [year])]);
if (isPrev) {
className += ' ' + CLS_YEAR_PREV;
} else {
if (isNext) {
className += ' ' + CLS_YEAR_NEXT;
}
}
if (isCurrent) {
className += ' ' + CLS_CURRENT;
}
if (isPicked) {
className += ' ' + CLS_PICKED;
elements.year = $year;
}
if (year < minYear || year > maxYear) {
className += ' ' + CLS_DISABLED;
}
$year.className = className;
fragment.appendChild($year);
}
return fragment;
}
/**
* 绘制日历控件的页脚
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_renderFooter",
value: function _renderFooter() {
var STYLES = this.get('STYLES');
var CLS_TEXT = STYLES.TEXT;
var elements = this.getEls();
var $today = elements.today.querySelector('.' + CLS_TEXT);
var today = Calendar.getToday();
var timer = null;
var renderTime = function renderTime() {
var $time = elements.time.querySelector('.' + CLS_TEXT);
var time = new Date();
var hours = time.getHours();
var minutes = time.getMinutes();
var seconds = time.getSeconds();
if (timer) {
clearTimeout(timer);
}
if (hours < 10) {
hours = '0' + hours;
}
if (minutes < 10) {
minutes = '0' + minutes;
}
if (seconds < 10) {
seconds = '0' + seconds;
}
$time.innerHTML = hours + ':' + minutes + ':' + seconds;
timer = setTimeout(renderTime, 1000);
};
$today.innerHTML = '今天:' + today.text;
Calendar.DOM.setAttribute($today, 'data-date', today.value);
if (this.get('hasClock')) {
renderTime();
}
return this;
}
/**
* 点击标题的事件处理器
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_titleClick",
value: function _titleClick() {
var viewMode = this.get('viewMode');
viewMode += 1;
if (viewMode > 2) {
viewMode = 2;
}
this.update(viewMode);
return this;
}
/**
* 点击向上翻页的事件处理器
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_prevClick",
value: function _prevClick() {
this.prev();
// return this;
}
/**
* 点击向下翻页的事件处理起
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_nextClick",
value: function _nextClick() {
this.next();
// return this;
}
/**
* 点击日期的事件处理器
* ========================================================================
* @param {Event} evt - 事件对象
* @returns {Calendar}
* @private
*/
}, {
key: "_dateClick",
value: function _dateClick(evt) {
var $el = evt.delegateTarget;
var time = $el.getAttribute('data-date');
var picked;
this.pickDate($el);
picked = this.getPicked();
console.log('------------- _dateClick -------------');
timeclick(time);
if (this.get('pickMode') === 'single') {
console.log(time);
} else {
console.log(picked);
}
return this;
}
/**
* 点击月份的事件处理器
* ========================================================================
* @param {Event} evt - 事件对象
* @returns {Calendar}
* @private
*/
}, {
key: "_monthClick",
value: function _monthClick(evt) {
var $month = evt.delegateTarget;
var time = $month.getAttribute('data-month');
this.pickMonth($month);
console.log('------------- _monthClick -------------');
console.log(time);
return this;
}
/**
* 点击年份的事件处理器
* ========================================================================
* @param {Event} evt - 事件对象
* @returns {Calendar}
* @private
*/
}, {
key: "_yearClick",
value: function _yearClick(evt) {
var $el = evt.delegateTarget;
var time = $el.getAttribute('data-year');
this.pickYear($el);
console.log('------------- _yearClick -------------');
console.log(time);
return this;
}
/**
* 点击今天的事件处理器
* ========================================================================
* @returns {Calendar}
* @private
*/
}, {
key: "_todayClick",
value: function _todayClick() {
var elements = this.getEls();
var time = Calendar.getToday().text;
this.pickToday(); // 触发日期选择逻辑
this.pickDate(elements.dates.querySelector('[data-date="' + time + '"]'));
console.log('------------- _todayClick -------------');
console.log(time);
return this;
}
/**
* 获得年份信息
* ========================================================================
* @param {String|Number} [val] - 表示年份的字符串或者数字(默认值:今年)
* @returns {{value: (Number|{value, text, fullText}), text: string, fullText: string}}
*/
}], [{
key: "getYear",
value: function getYear(val) {
var time = !val ? new Date() : new Date(Calendar.toAllSupported(val));
var year = time.getFullYear();
return {
value: year,
text: year.toString(),
fullText: year + '年'
};
}
/**
* 获取月份信息
* ========================================================================
* @param {String|Number} [val] - 表示月份的字符串或者数字(默认值:本月)
* @returns {{value: number, text: string, fullText: string}}
*/
}, {
key: "getMonth",
value: function getMonth(val) {
var time = !val ? new Date() : new Date(Calendar.toAllSupported(val));
var year = Calendar.getYear(val);
var month = time.getMonth();
month += 1;
return {
value: month,
text: year.text + '-' + month,
fullText: year.fullText + month + '月'
};
}
/**
* 获取日期信息
* ========================================================================
* @param {String|Number} [val] - 表示日期的字符串或者数字(默认值:今天)
* @returns {{year: (Number|{value, text}), month: number, date: number, day: number, text: string, fullText: string}}
*/
}, {
key: "getDate",
value: function getDate(val) {
var time = !val ? new Date() : new Date(Calendar.toAllSupported(val));
var year = Calendar.getYear(val);
var month = Calendar.getMonth(val);
var date = time.getDate();
var day = Calendar.getDay(val);
var fullDate = year.value + '-' + month.value + '-' + date;
var text = month.fullText + date + '日';
return {
year: year.value,
month: month.value,
date: date,
day: day.value,
text: fullDate,
fullText: text + ' ' + day.fullText
};
}
/**
* 获取星期信息
* ========================================================================
* @param {String|Number} [val] - 表示日期的字符串或者数字(默认值:今天)
* @returns {{value: number, text: string, fullText: string}}
*/
}, {
key: "getDay",
value: function getDay(val) {
var time = !val ? new Date() : new Date(Calendar.toAllSupported(val));
var day = time.getDay();
var text = Calendar.defaults.DAYS[day];
return {
value: day,
text: text,
fullText: '星期' + text
};
}
/**
* 获取今天的日期信息
* ========================================================================
* @returns {{year: (Number|{value, text}), month: number, date: number, day: number, text: string, fullText: string}}
*/
}, {
key: "getToday",
value: function getToday() {
return Calendar.getDate();
}
/**
* 获取年代信息
* ========================================================================
* @param {String|Number} [val] - 表示年份的字符串或者数字(默认值:今年)
* @returns {{start: (number|Number|{value, text}), end: (*|number)}}
*/
}, {
key: "getYears",
value: function getYears(val) {
var year = Calendar.getYear(val).value;
var numbers = year.toString().split('');
var lastNumber = parseInt(numbers[numbers.length - 1], 10);
var yearsStart = 0;
var yearsEnd = 0;
if (lastNumber === 0) {
yearsStart = year;
yearsEnd = year + 9;
} else {
if (lastNumber === 9) {
yearsStart = year - 9;
yearsEnd = year;
} else {
yearsStart = year - lastNumber;
yearsEnd = year + (9 - lastNumber);
}
}
return {
start: yearsStart,
end: yearsEnd
};
}
/**
* 获取日期所属的整个星期的日期区间信息
* ========================================================================
* @param {String} time - 表示日期的字符串
* @returns {Array}
*/
}, {
key: "getWeekRanges",
value: function getWeekRanges(time) {
var DATES = Calendar.defaults.DATES;
var isLeapYear = Calendar.isLeapYear;
var day = Calendar.getDay(time).value;
var begins = time.split('-');
var year = parseInt(begins[0], 10);
var month = parseInt(begins[1], 10);
var date = parseInt(begins[2], 10);
var days = DATES[month - 1];
var startYear = year;
var startMonth = month;
var startDate = date - day;
var endYear = year;
var endMonth = month;
var endDate = date + (6 - day);
var prevMonth = 0; // 闰年2月为29天,默认值为28天,所以需要+1天
if (isLeapYear(year) && month === 2) {
days += 1;
}
if (startDate < 1) {
// 上一个月
prevMonth = month - 2;
startMonth -= 1;
if (prevMonth < 0) {
startYear -= 1;
startMonth = 12;
startDate = DATES[11] + startDate;
} else {
// 开始日期
startDate = DATES[prevMonth] + startDate;
}
}
if (endDate > days) {
endMonth += 1; // 结束日期
endDate = endDate - days;
if (prevMonth > 11) {
endYear += 1;
endMonth = 1;
}
}
return Calendar.getRanges(startYear + '-' + startMonth + '-' + startDate, endYear + '-' + endMonth + '-' + endDate);
}
/**
* 获取两个日期之间的所有日期信息
* ========================================================================
* @param {String} begin - 表示日期的字符串
* @param {String} end - 表示日期的字符串
* @returns {Array}
*/
}, {
key: "getRanges",
value: function getRanges(begin, end) {
var ONE_DAY_TO_SECONDS = 24 * 60 * 60 * 1000;
var ranges = [];
var begins = begin.split('-');
var ends = end.split('-');
var beginTime = new Date();
var endTime = new Date();
var beginNumber;
var endNumber;
var timeNumber;
beginTime.setUTCFullYear(parseInt(begins[0], 10), parseInt(begins[1], 10) - 1, parseInt(begins[2], 10));
endTime.setUTCFullYear(parseInt(ends[0], 10), parseInt(ends[1], 10) - 1, parseInt(ends[2], 10));
beginNumber = beginTime.getTime();
endNumber = endTime.getTime();
timeNumber = beginNumber;
for (; timeNumber <= endNumber; timeNumber += ONE_DAY_TO_SECONDS) {
ranges.push(Calendar.getDate(timeNumber).text);
}
return ranges;
}
/**
* 判断是否为闰年
* ========================================================================
* @param {Number} year - 年份数值
* @returns {boolean}
*/
}, {
key: "isLeapYear",
value: function isLeapYear(year) {
return (year % 4 === 0 || year % 400 === 0) && year % 100 !== 0;
}
/**
* 判断是否为今天
* ========================================================================
* @param {String|Number} time - 表示日期的字符串或者数字
* @returns {*}
*/
}, {
key: "isToday",
value: function isToday(time) {
return Calendar.isDatesEqual(time);
}
/**
* 判断两个日期是否相等
* ========================================================================
* @param {String|Number} dateOne - 表示日期的字符串或者数字
* @param {String|Number} [dateTwo] - 表示日期的字符串或者数字(默认值:今天)
* @returns {boolean}
*/
}, {
key: "isDatesEqual",
value: function isDatesEqual(dateOne, dateTwo) {
var getDate = Calendar.getDate;
return Calendar.isEqual(getDate(dateOne).text, getDate(dateTwo).text);
}
/**
* 判断两个时间是否相等
* ========================================================================
* @param {String|Number} timeOne - 表示日期的字符串或者数字
* @param {String|Number} timeTwo - 表示日期的字符串或者数字
* @returns {boolean}
*/
}, {
key: "isEqual",
value: function isEqual(timeOne, timeTwo) {
var toAllSupported = Calendar.toAllSupported;
return new Date(toAllSupported(timeOne)).getTime() === new Date(toAllSupported(timeTwo)).getTime();
}
}, {
key: "toAllSupported",
value: function toAllSupported(time) {
var Utils = Calendar.Utils;
var date = [];
if (Utils.isNumber(time)) {
return time;
} else {
if (Utils.isString(time)) {
if (time.indexOf('-')) {
date = time.split('-');
} else {
if (time.indexOf('/')) {
date = time.split('/');
}
}
if (date.length === 1) {
date.push('1');
date.push('1');
} else {
if (date.length === 2) {
// 例如:'2019-1'
if (date[0].length === 4) {
date.push('1');
} else {
// 例如:'1-2019'
if (data[1].length === 4) {
date.unshift('1');
}
}
}
}
return date.join('/');
}
}
}
}]);
return Calendar;
}();
/**
* 日历控件默认的配置信息
* ========================================================================
*/
Calendar.defaults = {
parent: 'calendar',
time: '',
// 0 - 日期显示模式(默认值)
// 1 - 月份显示模式
// 2 - 年代显示模式
viewMode: 0,
// single - 单选(默认值)
// multiple - 多选
// range - 范围多选
// week - 整个星期选择
pickMode: 'single',
hasSwitcher: true,
hasFooter: true,
hasClock: true,
onDatePick: null,
onMonthPick: null,
onYearPick: null,
onTodayPick: null,
MONTHS: [11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2],
DAYS: ['日', '一', '二', '三', '四', '五', '六'],
DATES: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
STYLES: {
WRAP: 'cal-md',
WRAP_WITHOUT_FOOTER: 'cal-md-without-footer',
HEADER: 'cal-hd',
TITLE: 'cal-title',
SWITCHER: 'cal-switcher',
PREV: 'cal-prev',
ICON_PREV: 'icon-angle-up',
NEXT: 'cal-next',
ICON_NEXT: 'icon-angle-down',
BODY: 'cal-bd',
WEEK: 'cal-week',
WEEKEND: 'cal-weekend',
DAY: 'cal-day',
DATES: 'cal-dates',
DATE: 'cal-date',
DATE_PREV: 'cal-date-prev',
DATE_NEXT: 'cal-date-next',
MONTHS: 'cal-months',
MONTH: 'cal-month',
MONTH_PREV: 'cal-month-prev',
MONTH_NEXT: 'cal-month-next',
YEARS: 'cal-years',
YEAR: 'cal-year',
YEAR_PREV: 'cal-year-prev',
YEAR_NEXT: 'cal-year-next',
FOOTER: 'cal-ft',
FOOTER_DATE: 'cal-ft-date',
TODAY: 'cal-today',
FOOTER_TIME: 'cal-ft-time',
TIME: 'cal-time',
TEXT: 'cal-text',
CURRENT: 'cal-current',
PICKED: 'cal-picked',
PICKED_RANGE: 'cal-picked-range',
PICKED_POINT: 'cal-picked-point',
DISABLED: 'cal-disabled',
HIDDEN: 'cal-hidden'
}
/**
* 常用的工具方法
* ========================================================================
*/
};
Calendar.Utils = {
uuid: 0,
isString: function isString(o) {
return typeof o === 'string';
},
isNumber: function isNumber(o) {
return typeof o === 'number';
},
isArray: function isArray(o) {
if (Array.isArray) {
return Array.isArray(o);
} else {
return Object.prototype.toString.apply(o) === '[object Array]';
}
},
isFunction: function isFunction(o) {
return typeof o === 'function' || Object.prototype.toString.apply(o) === '[object Function]';
},
isElement: function isElement(o) {
return o && o.nodeName && o.tagName && o.nodeType === 1;
},
guid: function guid(prefix) {
var Utils = Calendar.Utils;
Utils.uuid += 1;
return prefix ? prefix + '-' + Utils.uuid : 'guid-' + Utils.uuid;
},
trim: function trim(str) {
return str.replace(/^\s+/g, '').replace(/\s+$/g, '');
},
stripTags: function stripTags(str) {
return str.replace(/<\/?[^>]+(>|$)/g, '');
}
/**
* DOM 操作相关的工具方法
* ========================================================================
*/
};
Calendar.DOM = {
/**
* 创建 DOM 节点,并添加属性和子节点
* ========================================================================
* @param {String} tagName - 标签名称
* @param {Object} attributes - 属性对象
* @param {Array} [children] - 子节点数组
* @returns {HTMLElement}
*/
createElement: function createElement(tagName, attributes, children) {
var Utils = Calendar.Utils;
var element = document.createElement(tagName);
for (var attr in attributes) {
if (attributes.hasOwnProperty(attr)) {
Calendar.DOM.setAttribute(element, attr, attributes[attr]);
}
}
if (Utils.isArray(children)) {
children.forEach(function (child) {
var childNode;
if (Utils.isElement(child)) {
childNode = child;
} else {
if (Utils.isString(child) || Utils.isNumber(child)) {
var text = Utils.isString(child) ? Utils.trim(Utils.stripTags(child)) : child.toString();
childNode = document.createTextNode(text);
}
}
element.appendChild(childNode);
});
}
return element;
},
/**
* 给 DOM 节点设置属性/值
* ========================================================================
* @param {HTMLElement} el - DOM 节点
* @param {String} attr - 属性名称
* @param {String|Number|Boolean} value - 属性值
*/
setAttribute: function setAttribute(el, attr, value) {
var tagName = el.tagName.toLowerCase();
switch (attr) {
case 'style':
el.style.cssText = value;
break;
case 'value':
if (tagName === 'input' || tagName === 'textarea') {
el.value = value;
} else {
el.setAttribute(attr, value);
}
break;
case 'className':
el.className = value;
break;
default:
el.setAttribute(attr, value);
break;
}
},
/**
* 检测 DOM 节点是否包含名为 className 的样式
* ========================================================================
* @param {HTMLElement} el - DOM 节点
* @param {String} className - 样式名称
* @returns {*}
*/
hasClass: function hasClass(el, className) {
var allClass = el.className;
if (!allClass) {
return false;
}
return allClass.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
},
/**
* 给 DOM 节点添加名为 className 的样式
* ========================================================================
* @param {HTMLElement} el - DOM 节点
* @param {String} className - 样式名称
* @returns {Boolean}
*/
addClass: function addClass(el, className) {
var allClass = el.className;
if (Calendar.DOM.hasClass(el, className)) {
return false;
}
allClass += allClass.length > 0 ? ' ' + className : className;
el.className = allClass;
},
/**
* 移除 DOM 节点的 className 样式
* ========================================================================
* @param {HTMLElement} el - DOM 节点
* @param {String} className - 样式名称
* @returns {Boolean}
*/
removeClass: function removeClass(el, className) {
var allClass = el.className;
if (!allClass || !Calendar.DOM.hasClass(el, className)) {
return false;
}
allClass = Calendar.Utils.trim(allClass.replace(className, ''));
el.className = allClass;
}
};
/**
* 代理事件
* ========================================================
* 说明:代码修改至 Nicolas Gallagher 的 delegate.js
* 项目 GitHub 地址:https://github.com/necolas/delegate.js
* ========================================================
*/
Calendar.Delegate = {
/**
* 绑定代理事件
* ========================================================================
* @param {HTMLElement} el - 绑定代理事件的 DOM 节点
* @param {String} selector - 触发 el 代理事件的 DOM 节点的选择器
* @param {String} type - 事件类型
* @param {Function} callback - 绑定事件的回调函数
* @param {Object} [context] - callback 回调函数的 this 上下文(默认值:el)
* @param {Boolean} [capture] - 是否采用事件捕获(默认值:false - 事件冒泡)
* @param {Boolean} [once] - 是否只触发一次(默认值:false - 事件冒泡)
*/
on: function on(el, selector, type, callback, context, capture,
/* private */
once) {
var Delegate = Calendar.Delegate;
var wrapper = function wrapper(e) {
var delegateTarget = Delegate.getDelegateTarget(el, e.target, selector);
e.delegateTarget = delegateTarget;
if (delegateTarget) {
if (once === true) {
Delegate.off(el, type, wrapper);
}
callback.call(context || el, e);
}
};
if (type === 'mouseenter' || type === 'mouseleave') {
capture = true;
}
callback._delegateWrapper = callback;
el.addEventListener(type, wrapper, capture || false);
return callback;
},
/**
* 绑定只触发一次的事件
* ========================================================================
* @param {HTMLElement} el - 绑定代理事件的 DOM 节点
* @param {String} selector - 触发 el 代理事件的 DOM 节点的选择器
* @param {String} type - 事件类型
* @param {Function} callback - 绑定事件的回调函数
* @param {Object} [context] - callback 回调函数的 this 上下文(默认值:el)
* @param {Boolean} [capture] - 是否采用事件捕获(默认值:false - 事件冒泡)
*/
once: function once(el, type, selector, callback, context, capture) {
Calendar.Delegate.on(el, type, selector, callback, context, capture, true);
},
/**
* 取消事件绑定
* ========================================================================
* @param {HTMLElement} el - 取消绑定(代理)事件的 DOM 节点
* @param {String} type - 事件类型
* @param {Function} callback - 绑定事件的回调函数
* @param {Boolean} [capture] - 是否采用事件捕获(默认值:false - 事件冒泡)
*/
off: function off(el, type, callback, capture) {
if (callback._delegateWrapper) {
callback = callback._delegateWrapper;
delete callback._delegateWrapper;
}
if (type === 'mouseenter' || type === 'mouseleave') {
capture = true;
}
el.removeEventListener(type, callback, capture || false);
},
/**
* 停止事件(阻止默认行为和阻止事件的捕获或冒泡)
* ========================================================================
* @param {Event} evt - 事件对象
*/
stop: function stop(evt) {
var Delegate = Calendar.Delegate;
Delegate.stopPropagation(evt);
Delegate.preventDefault(evt);
},
/**
* 终止事件在传播过程的捕获或冒泡
* ========================================================================
* @param {Event} evt - 事件对象
*/
stopPropagation: function stopPropagation(evt) {
var event = window.event;
if (evt.stopPropagation) {
evt.stopPropagation();
} else {
event.cancelBubble = true;
}
},
/**
* 阻止事件的默认行为
* ========================================================================
* @param {Event} evt - 事件对象
*/
preventDefault: function preventDefault(evt) {
var event = window.event;
if (evt.preventDefault) {
evt.preventDefault();
} else {
event.returnValue = false;
}
},
/**
* 通过 className 获得事件代理节点的事件代理目标节点
* ========================================================================
* @param {HTMLElement} el - 绑定事件代理的节点
* @param target - (触发事件后)事件的目标对象
* @param selector - 目标节点的类选择器
* @returns {HTMLElement|Null}
*/
getDelegateTarget: function getDelegateTarget(el, target, selector) {
while (target && target !== el) {
if (Calendar.DOM.hasClass(target, selector.replace('.', ''))) {
return target;
}
target = target.parentElement;
}
return null;
}
}; // 为了处理不兼容 Object.assign
if (!Calendar.Utils.isFunction(Object.assign)) {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) {
// .length of function is 2
'use strict';
if (target == null) {
// TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) {
// Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
return Calendar;
}));