# JQuery日期选择插件
----index.html----------------------------------------------------------------------------
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
<meta http-equiv="x-ua-compatible" content="IE=edge, chrome=1">
<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8;">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery事件日历插件Calendar</title>
<link rel="stylesheet" href="calendar.css">
<style type="text/css">
html {
font: 500 14px 'roboto';
color: #333;
background-color: #fafafa;
}
a {
text-decoration: none;
}
ul, ol, li {
list-style: none;
padding: 0;
margin: 0;
}
#demo {
width: 300px;
margin: 150px auto;
}
p {
margin: 0;
}
#dt {
margin: 30px auto;
height: 28px;
width: 200px;
padding: 0 6px;
border: 1px solid #ccc;
outline: none;
}
</style>
</head>
<body>
<div id="demo">
<input type="text" id="dt" placeholder="trigger calendar">
<div id="dd"></div>
</div>
<script src="js/jquery.js"></script>
<script src="js/calendar.js"></script>
<script>
$('#dd').calendar({
trigger: '#dt',
zIndex: 999,
format: 'yyyy-mm-dd',
onSelected: function (view, date, data) {
console.log('event: onSelected')
},
onClose: function (view, date, data) {
console.log('event: onClose')
console.log('view:' + view)
console.log('date:' + date)
console.log('data:' + (data || 'None'));
}
});
</script>
</body>
</html>
---calendar.css---------------------------------------------------------------------
.calendar {
width: 280px;
height: 330px;
}
.calendar-modal {
display: none;
position: absolute;
background: #fdfdfd;
border: 1px solid #e8e8e8;
box-shadow: 1px 2px 3px #ddd
}
.calendar-inner {
position: relative;
z-index: 1;
-webkit-perspective: 1000;
-moz-perspective: 1000;
-ms-perspective: 1000;
perspective: 1000;
-ms-transform: perspective(1000px);
-moz-transform: perspective(1000px);
-moz-transform-style: preserve-3d;
-ms-transform-style: preserve-3d;
}
.calendar-views {
transform-style: preserve-3d;
}
.calendar .view {
backface-visibility: hidden;
position: absolute;
top: 0;
left: 0;
*overflow: hidden;
-webkit-transition: .6s;
transition: .6s;
}
.calendar-d .view-month,
.calendar-m .view-date {
transform: rotateY(180deg);
visibility: hidden;
z-index: 1;
}
.calendar-d .view-date,
.calendar-m .view-month {
transform: rotateY(0deg);
visibility: visible;
z-index: 2;
}
.calendar-ct,
.calendar-hd,
.calendar-views .week,
.calendar-views .days {
overflow: hidden;
}
.calendar-views {
width: 100%;
}
.calendar .view,
.calendar-display,
.calendar-arrow .prev,
.calendar .date-items li {
float: left;
}
.calendar-arrow,
.calendar-arrow .next {
float: right;
}
.calendar-hd {
padding: 10px 0;
height: 30px;
line-height: 30px;
}
.calendar-display {
font-size: 28px;
text-indent: 10px;
}
.view-month .calendar-hd {
padding: 10px;
}
.calendar-arrow,
.calendar-display {
color: #ddd;
}
.calendar li[disabled] {
color: #bbb;
}
.calendar li.old[disabled],
.calendar li.new[disabled] {
color: #eee;
}
.calendar-display .m,
.calendar-views .week,
.calendar-views .days .old,
.calendar-views .days .new,
.calendar-display:hover,
.calendar-arrow span:hover {
color: #888;
}
.calendar-arrow span,
.calendar-views .days li[data-calendar-day],
.calendar-views .view-month li[data-calendar-month] {
cursor: pointer;
}
.calendar li[disabled] {
cursor: not-allowed;
}
.calendar-arrow {
width: 50px;
margin-right: 10px;
}
.calendar-arrow span {
font: 500 26px sans-serif;
}
.calendar ol li {
position: relative;
float: left;
text-align: center;
border-radius: 50%;
}
.calendar .week li,
.calendar .days li {
width: 40px;
height: 40px;
line-height: 40px;
}
.calendar .month-items li {
width: 70px;
height: 70px;
line-height: 70px;
}
.calendar .days li[data-calendar-day]:hover,
.calendar .view-month li[data-calendar-month]:hover {
background: #eee;
}
.calendar .calendar-views .now {
color: #fff;
background: #FF808E!important;
}
.calendar .calendar-views .selected {
color: #FF808E;
background: #CDE9D9!important;
}
.calendar .calendar-views .dot {
position: absolute;
left: 50%;
bottom: 4px;
margin-left: -2px;
width: 4px;
height: 4px;
background: #FF808E;
border-radius: 50%;
}
.calendar-views .now .dot {
background: #fff;
}
.calendar .date-items {
width: 300%;
margin-left: -100%;
}
.calendar-label {
display: none;
position: absolute;
top: 50%;
left: 50%;
z-index: 2;
padding: 5px 10px;
line-height: 22px;
color: #fff;
background: #000;
border-radius: 3px;
opacity: .7;
filter: alpha(opacity=70);
}
.calendar-label i {
display: none;
position: absolute;
left: 50%;
bottom: -12px;
width: 0;
height: 0;
margin-left: -3px;
border: 6px solid transparent;
border-top-color: #000;
}
---calendar.js------------------------------------------------------------------------
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define('calendar', ['jquery'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('jquery'));
} else {
factory(root.jQuery);
}
}(this, function($) {
// default config
var defaults = {
// 宽度
width: 280,
// 高度, 不包含头部,头部固定高度
height: 280,
zIndex: 1,
// selector or element
// 设置触发显示的元素,为null时默认显示
trigger: null,
// 偏移位置,可设正负值
// trigger 设置时生效
offset: [0, 1],
// 自定义类,用于重写样式
customClass: '',
// 显示视图
// 可选:date, month
view: 'date',
// 默认日期为当前日期
date: new Date(),
format: 'yyyy/mm/dd',
// 一周的第一天
// 0表示周日,依次类推
startWeek: 0,
// 星期格式
weekArray: ['日', '一', '二', '三', '四', '五', '六'],
// 设置选择范围
// 格式:[开始日期, 结束日期]
// 开始日期为空,则无上限;结束日期为空,则无下限
// 如设置2015年11月23日以前不可选:[new Date(), null] or ['2015/11/23']
selectedRang: null,
// 日期关联数据 [{ date: string, value: object }, ... ]
// 日期格式与 format 一致
// 如 [ {date: '2015/11/23', value: '面试'} ]
data: null,
// 展示关联数据
// 格式化参数:{m}视图,{d}日期,{v}value
// 设置 false 表示不显示
label: '{d}\n{v}',
// 切换字符
prev: '<',
next: '>',
// 切换视图
// 参数:view, y, m
viewChange: $.noop,
// view: 视图
// date: 不同视图返回不同的值
// value: 日期关联数据
onSelected: function(view, date, value) {
// body...
},
// 参数同上
onMouseenter: $.noop,
onClose: $.noop
},
// static variable
ACTION_NAMESPACE = 'data-calendar-',
DISPLAY_VD = '[' + ACTION_NAMESPACE + 'display-date]',
DISPLAY_VM = '[' + ACTION_NAMESPACE + 'display-month]',
ARROW_DATE = '[' + ACTION_NAMESPACE + 'arrow-date]',
ARROW_MONTH = '[' + ACTION_NAMESPACE + 'arrow-month]',
ITEM_DAY = ACTION_NAMESPACE + 'day',
ITEM_MONTH = ACTION_NAMESPACE + 'month',
DISABLED = 'disabled',
MARK_DATA = 'markData',
VIEW_CLASS = {
date: 'calendar-d',
month: 'calendar-m'
},
OLD_DAY_CLASS = 'old',
NEW_DAY_CLASS = 'new',
TODAY_CLASS = 'now',
SELECT_CLASS = 'selected',
MARK_DAY_HTML = '<i class="dot"></i>',
DATE_DIS_TPL = '{year}/<span class="m">{month}</span>',
ITEM_STYLE = 'style="width:{w}px;height:{h}px;line-height:{h}px"',
WEEK_ITEM_TPL = '<li ' + ITEM_STYLE + '>{wk}</li>',
DAY_ITEM_TPL = '<li ' + ITEM_STYLE + ' class="{class}" {action}>{value}</li>',
MONTH_ITEM_TPL = '<li ' + ITEM_STYLE + ' ' + ITEM_MONTH + '>{m}月</li>',
TEMPLATE = [
'<div class="calendar-inner">',
'<div class="calendar-views">',
'<div class="view view-date">',
'<div class="calendar-hd">',
'<a href="javascript:;" data-calendar-display-date class="calendar-display">',
'{yyyy}/<span class="m">{mm}</span>',
'</a>',
'<div class="calendar-arrow">',
'<span class="prev" title="上一月" data-calendar-arrow-date>{prev}</span>',
'<span class="next" title="下一月" data-calendar-arrow-date>{next}</span>',
'</div>',
'</div>',
'<div class="calendar-ct">',
'<ol class="week">{week}</ol>',
'<ul class="date-items"></ul>',
'</div>',
'</div>',
'<div class="view view-month">',
'<div class="calendar-hd">',
'<a href="javascript:;" data-calendar-display-month class="calendar-display">{yyyy}</a>',
'<div class="calendar-arrow">',
'<span class="prev" title="上一年" data-calendar-arrow-month>{prev}</span>',
'<span class="next" title="下一年" data-calendar-arrow-month>{next}</span>',
'</div>',
'</div>',
'<ol class="calendar-ct month-items">{month}</ol>',
'</div>',
'</div>',
'</div>',
'<div class="calendar-label"><p>HelloWorld</p><i></i></div>'
],
OS = Object.prototype.toString;
// utils
function isDate(obj) {
return OS.call(obj) === '[object Date]';
}
function isString(obj) {
return OS.call(obj) === '[object String]';
}
function getClass(el) {
return el.getAttribute('class') || el.getAttribute('className');
}
// extension methods
String.prototype.repeat = function(data) {
return this.replace(/\{\w+\}/g, function(str) {
var prop = str.replace(/\{|\}/g, '');
return data[prop] || '';
});
}
String.prototype.toDate = function() {
var dt = new Date(),
dot = this.replace(/\d/g, '').charAt(0),
arr = this.split(dot);
dt.setFullYear(arr[0]);
dt.setMonth(arr[1] - 1);
dt.setDate(arr[2]);
return dt;
}
Date.prototype.format = function(exp) {
var y = this.getFullYear(),
m = this.getMonth() + 1,
d = this.getDate();
return exp.replace('yyyy', y).replace('mm', m).replace('dd', d);
}
Date.prototype.isSame = function(y, m, d) {
if (isDate(y)) {
var dt = y;
y = dt.getFullYear();
m = dt.getMonth() + 1;
d = dt.getDate();
}
return this.getFullYear() === y && this.getMonth() + 1 === m && this.getDate() === d;
}
Date.prototype.add = function(n) {
this.setDate(this.getDate() + n);
}
Date.prototype.minus = function(n) {
this.setDate(this.getDate() - n);
}
Date.prototype.clearTime = function(n) {
this.setHours(0);
this.setSeconds(0);
this.setMinutes(0);
this.setMilliseconds(0);
return this;
}
Date.isLeap = function(y) {
return (y % 100 !== 0 && y % 4 === 0) || (y % 400 === 0);
}
Date.getDaysNum = function(y, m) {
var num = 31;
switch (m) {
case 2:
num = this.isLeap(y) ? 29 : 28;
break;
case 4:
case 6:
case 9:
case 11:
num = 30;
break;
}
return num;
}
Date.getSiblingsMonth = function(y, m, n) {
var d = new Date(y, m - 1);
d.setMonth(m - 1 + n);
return {
y: d.getFullYear(),
m: d.getMonth() + 1
};
}
Date.getPrevMonth = function(y, m, n) {
return this.getSiblingsMonth(y, m, 0 - (n || 1));
}
Date.getNextMonth = function(y, m, n) {
return this.getSiblingsMonth(y, m, n || 1);
}
Date.tryParse = function(obj) {
if (!obj) {
return obj;
}
return isDate(obj) ? obj : obj.toDate();
}
// Calendar class
function Calendar(element, options) {
this.$element = $(element);
this.options = $.extend({}, $.fn.calendar.defaults, options);
this.$element.addClass('calendar ' + this.options.customClass);
this.width = this.options.width;
this.height = this.options.height;
this.date = this.options.date;
this.selectedRang = this.options.selectedRang;
this.data = this.options.data;
this.init();
}
Calendar.prototype = {
constructor: Calendar,
getDayAction: function(day) {
var action = ITEM_DAY;
if (this.selectedRang) {
var start = Date.tryParse(this.selectedRang[0]),
end = Date.tryParse(this.selectedRang[1]);
if ((start && day < start.clearTime()) || (end && day > end.clearTime())) {
action = DISABLED;
}
}
return action;
},
getDayData: function(day) {
var ret, data = this.data;
if (data) {
for (var i = 0, len = data.length; i < len; i++) {
var item = data[i];
if (day.isSame(item.date.toDate())) {
ret = item.value;
}
}
}
return ret;
},
getDayItem: function(y, m, d, f) {
var dt = this.date,
idt = new Date(y, m - 1, d),
data = {
w: this.width / 7,
h: this.height / 7,
value: d
},
markData,
$item;
var selected = dt.isSame(y, m, d) ? SELECT_CLASS : '';
if (f === 1) {
data['class'] = OLD_DAY_CLASS;
} else if (f === 3) {
data['class'] = NEW_DAY_CLASS;
} else {
data['class'] = '';
}
if (dt.isSame(y, m, d)) {
data['class'] += ' ' + TODAY_CLASS;
}
data.action = this.getDayAction(idt);
markData = this.getDayData(idt);
$item = $(DAY_ITEM_TPL.repeat(data));
if (markData) {
$item.data(MARK_DATA, markData);
$item.html(d + MARK_DAY_HTML);
}
return $item;
},
getDaysHtml: function(y, m) {
var year, month, firstWeek, daysNum, prevM, prevDiff,
dt = this.date,
$days = $('<ol class="days"></ol>');
if (isDate(y)) {
year = y.getFullYear();
month = y.getMonth() + 1;
} else {
year = Number(y);
month = Number(m);
}
firstWeek = new Date(year, month - 1, 1).getDay() || 7;
prevDiff = firstWeek - this.options.startWeek;
daysNum = Date.getDaysNum(year, month);
prevM = Date.getPrevMonth(year, month);
prevDaysNum = Date.getDaysNum(year, prevM.m);
nextM = Date.getNextMonth(year, month);
// month flag
var PREV_FLAG = 1,
CURR_FLAG = 2,
NEXT_FLAG = 3,
count = 0;
for (var p = prevDaysNum - prevDiff + 1; p <= prevDaysNum; p++, count++) {
$days.append(this.getDayItem(prevM.y, prevM.m, p, PREV_FLAG));
}
for (var c = 1; c <= daysNum; c++, count++) {
$days.append(this.getDayItem(year, month, c, CURR_FLAG));
}
for (var n = 1, nl = 42 - count; n <= nl; n++) {
$days.append(this.getDayItem(nextM.y, nextM.m, n, NEXT_FLAG));
}
return $('<li></li>').width(this.options.width).append($days);
},
getWeekHtml: function() {
var week = [],
weekArray = this.options.weekArray,
start = this.options.startWeek,
len = weekArray.length,
w = this.width / 7,
h = this.height / 7;
for (var i = start; i < len; i++) {
week.push(WEEK_ITEM_TPL.repeat({
w: w,
h: h,
wk: weekArray[i]
}));
}
for (var j = 0; j < start; j++) {
week.push(WEEK_ITEM_TPL.repeat({
w: w,
h: h,
wk: weekArray[j]
}));
}
return week.join('');
},
getMonthHtml: function() {
var month = [],
w = this.width / 4,
h = this.height / 4,
i = 1;
for (; i < 13; i++) {
month.push(MONTH_ITEM_TPL.repeat({
w: w,
h: h,
m: i
}));
}
return month.join('');
},
setMonthAction: function(y) {
var m = this.date.getMonth() + 1;
this.$monthItems.children().removeClass(TODAY_CLASS);
if (y === this.date.getFullYear()) {
this.$monthItems.children().eq(m - 1).addClass(TODAY_CLASS);
}
},
fillStatic: function() {
var staticData = {
prev: this.options.prev,
next: this.options.next,
week: this.getWeekHtml(),
month: this.getMonthHtml()
};
this.$element.html(TEMPLATE.join('').repeat(staticData));
},
updateDisDate: function(y, m) {
this.$disDate.html(DATE_DIS_TPL.repeat({
year: y,
month: m
}));
},
updateDisMonth: function(y) {
this.$disMonth.html(y);
},
fillDateItems: function(y, m) {
var ma = [
Date.getPrevMonth(y, m), {
y: y,
m: m
},
Date.getNextMonth(y, m)
];
this.$dateItems.html('');
for (var i = 0; i < 3; i++) {
var $item = this.getDaysHtml(ma[i].y, ma[i].m);
this.$dateItems.append($item);
}
},
hide: function(view, date, data) {
this.$trigger.val(date.format(this.options.format));
this.options.onClose.call(this, view, date, data);
this.$element.hide();
},
trigger: function() {
this.$trigger = this.options.trigger instanceof $ ? this.options.trigger : $(this.options.trigger);
var _this = this,
$this = _this.$element,
post = _this.$trigger.offset(),
offs = _this.options.offset;
$this.addClass('calendar-modal').css({
left: (post.left + offs[0]) + 'px',
top: (post.top + _this.$trigger.outerHeight() + offs[1]) + 'px',
zIndex: _this.options.zIndex
});
_this.$trigger.click(function() {
$this.show();
});
$(document).click(function(e) {
if (_this.$trigger[0] != e.target && !$.contains($this[0], e.target)) {
$this.hide();
}
});
},
render: function() {
this.$week = this.$element.find('.week');
this.$dateItems = this.$element.find('.date-items');
this.$monthItems = this.$element.find('.month-items');
this.$label = this.$element.find('.calendar-label');
this.$disDate = this.$element.find(DISPLAY_VD);
this.$disMonth = this.$element.find(DISPLAY_VM);
var y = this.date.getFullYear(),
m = this.date.getMonth() + 1;
this.updateDisDate(y, m);
this.updateMonthView(y);
this.fillDateItems(y, m);
this.options.trigger && this.trigger();
},
setView: function(view) {
this.$element.removeClass(VIEW_CLASS.date + ' ' + VIEW_CLASS.month)
.addClass(VIEW_CLASS[view]);
this.view = view;
},
updateDateView: function(y, m, dirc, cb) {
m = m || this.date.getMonth() + 1;
var _this = this,
$dis = this.$dateItems,
exec = {
prev: function() {
var pm = Date.getPrevMonth(y, m),
ppm = Date.getPrevMonth(y, m, 2),
$prevItem = _this.getDaysHtml(ppm.y, ppm.m);
m = pm.m;
y = pm.y;
$dis.animate({
marginLeft: 0
}, 300, 'swing', function() {
$dis.children(':last').remove();
$dis.prepend($prevItem).css('margin-left', '-100%');
$.isFunction(cb) && cb.call(_this);
});
},
next: function() {
var nm = Date.getNextMonth(y, m),
nnm = Date.getNextMonth(y, m, 2),
$nextItem = _this.getDaysHtml(nnm.y, nnm.m);
m = nm.m;
y = nm.y;
$dis.animate({
marginLeft: '-200%'
}, 300, 'swing', function() {
$dis.children(':first').remove();
$dis.append($nextItem).css('margin-left', '-100%');
$.isFunction(cb) && cb.call(_this);
});
}
};
if (dirc) {
exec[dirc]();
} else {
this.fillDateItems(y, m);
}
this.updateDisDate(y, m);
this.setView('date');
return {
y: y,
m: m
};
},
updateMonthView: function(y) {
this.updateDisMonth(y);
this.setMonthAction(y);
this.setView('month');
},
getDisDateValue: function() {
var arr = this.$disDate.html().split('/'),
y = Number(arr[0]),
m = Number(arr[1].match(/\d{1,2}/)[0]);
return [y, m];
},
selectedDay: function(d, type) {
var arr = this.getDisDateValue(),
y = arr[0],
m = arr[1],
toggleClass = function() {
this.$dateItems.children(':eq(1)')
.find('[' + ITEM_DAY + ']:not(.' + NEW_DAY_CLASS + ', .' + OLD_DAY_CLASS + ')')
.removeClass(SELECT_CLASS)
.filter(function(index) {
return parseInt(this.innerHTML) === d;
}).addClass(SELECT_CLASS);
};
if (type) {
var ret = this.updateDateView(y, m, {
'old': 'prev',
'new': 'next'
}[type], toggleClass);
y = ret.y;
m = ret.m;
this.options.viewChange('date', y, m);
} else {
toggleClass.call(this);
}
return new Date(y, m - 1, d);
},
showLabel: function(event, view, date, data) {
var $lbl = this.$label;
$lbl.find('p').html(this.options.label.repeat({
m: view,
d: date.format(this.options.format),
v: data
}).replace(/\n/g, '<br>'));
var w = $lbl.outerWidth(),
h = $lbl.outerHeight();
$lbl.css({
left: (event.pageX - w / 2) + 'px',
top: (event.pageY - h - 20) + 'px'
}).show();
},
hasLabel: function() {
if (this.options.label) {
$('body').append(this.$label);
return true;
}
return false;
},
event: function() {
var _this = this,
vc = _this.options.viewChange;
// view change
_this.$element.on('click', DISPLAY_VD, function() {
var arr = _this.getDisDateValue();
_this.updateMonthView(arr[0], arr[1]);
vc('month', arr[0], arr[1]);
}).on('click', DISPLAY_VM, function() {
var y = this.innerHTML;
_this.updateDateView(y);
vc('date', y);
});
// arrow
_this.$element.on('click', ARROW_DATE, function() {
var arr = _this.getDisDateValue(),
type = getClass(this),
y = arr[0],
m = arr[1];
var d = _this.updateDateView(y, m, type, function() {
vc('date', d.y, d.m);
});
}).on('click', ARROW_MONTH, function() {
var y = Number(_this.$disMonth.html()),
type = getClass(this);
y = type === 'prev' ? y - 1 : y + 1;
_this.updateMonthView(y);
vc('month', y);
});
// selected
_this.$element.on('click', '[' + ITEM_DAY + ']', function() {
var d = parseInt(this.innerHTML),
cls = getClass(this),
type = /new|old/.test(cls) ? cls.match(/new|old/)[0] : '';
var day = _this.selectedDay(d, type);
_this.options.onSelected.call(this, 'date', day, $(this).data(MARK_DATA));
_this.$trigger && _this.hide('date', day, $(this).data(MARK_DATA));
}).on('click', '[' + ITEM_MONTH + ']', function() {
var y = Number(_this.$disMonth.html()),
m = parseInt(this.innerHTML);
_this.updateDateView(y, m);
vc('date', y, m);
_this.options.onSelected.call(this, 'month', new Date(y, m - 1));
});
// hover
_this.$element.on('mouseenter', '[' + ITEM_DAY + ']', function(e) {
var arr = _this.getDisDateValue(),
day = new Date(arr[0], arr[1] - 1, parseInt(this.innerHTML));
if (_this.hasLabel && $(this).data(MARK_DATA)) {
$('body').append(_this.$label);
_this.showLabel(e, 'date', day, $(this).data(MARK_DATA));
}
_this.options.onMouseenter.call(this, 'date', day, $(this).data(MARK_DATA));
}).on('mouseleave', '[' + ITEM_DAY + ']', function() {
_this.$label.hide();
});
},
resize: function() {
var w = this.width,
h = this.height,
hdH = this.$element.find('.calendar-hd').outerHeight();
this.$element.width(w).height(h + hdH)
.find('.calendar-inner, .view')
.css('width', w + 'px');
this.$element.find('.calendar-ct').width(w).height(h);
},
init: function() {
this.fillStatic();
this.resize();
this.render();
this.view = this.options.view;
this.setView(this.view);
this.event();
},
setData: function(data) {
this.data = data;
if (this.view === 'date') {
var d = this.getDisDateValue();
this.fillDateItems(d[0], d[1]);
} else if (this.view === 'month') {
this.updateMonthView(this.$disMonth.html());
}
},
methods: function(name, args) {
if (OS.call(this[name]) === '[object Function]') {
return this[name].apply(this, args);
}
}
};
$.fn.calendar = function(options) {
var calendar = this.data('calendar'),
fn,
args = [].slice.call(arguments);
if (!calendar) {
return this.each(function() {
return $(this).data('calendar', new Calendar(this, options));
});
}
if (isString(options)) {
fn = options;
args.shift();
return calendar.methods(fn, args);
}
return this;
}
$.fn.calendar.defaults = defaults;
}));