Created
October 10, 2013 08:39
-
-
Save coma/6915057 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function($, _, undefined) { | |
var resetTime = function(m) { | |
return m.hour(0).minute(0).second(0); | |
}; | |
$.fn.CalendarWidget = function(options) { | |
var pluginName = 'CalendarWidget'; | |
var plugin = $(this).data(pluginName); | |
if(plugin) { | |
return plugin; | |
} | |
return this.each(function() { | |
var defaults = { | |
format: { | |
main: 'YYYY-MM-DD', | |
month: 'MMMM YYYY' | |
}, | |
min: _(), | |
max: _().add('y', 1), | |
container: 'body', | |
style: { | |
main: 'calendar' | |
}, | |
tolerance: 100, | |
label: { | |
cancel: 'Cancel', | |
set : 'Set', | |
title : '' | |
} | |
}; | |
var input = $(this); | |
var data = input.data('widget-calendar'); | |
var settings = $.extend(defaults, data, options); | |
var widget = $('<div class="' + settings.style.main + '"></div>').appendTo(settings.container); | |
var win = $(window); | |
var hash = 'calendar' + (new Date).getTime(); | |
var prevHash; | |
var showing = false; | |
input | |
.attr('readonly', true) | |
.on('focus click', function(event) { | |
event.preventDefault(); | |
event.stopImmediatePropagation(); | |
show(); | |
}); | |
if(_.isMoment(settings.min)) { | |
resetTime(settings.min); | |
} | |
if(_.isMoment(settings.max)) { | |
resetTime(settings.max); | |
} | |
widget.html([ | |
'<div>', | |
'<div class="actions">', | |
'<a href="#" class="cancel">' + settings.label.cancel + '</a>', | |
'<a href="#" class="set">' + settings.label.set + '</a>', | |
settings.label.title, | |
'</div>', | |
'<div class="month">', | |
'<a href="#" class="prev"></a>', | |
'<div></div>', | |
'<a href="#" class="next"></a>', | |
'</div>', | |
'<div class="weekdays"></div>', | |
'<div class="days"></div>', | |
'</div>' | |
].join('')); | |
var actionSet = widget.find('div.actions > a.set'); | |
var actionCancel = widget.find('div.actions > a.cancel'); | |
var prevMonth = widget.find('div.month > a.prev'); | |
var nextMonth = widget.find('div.month > a.next'); | |
var labelMonth = widget.find('div.month > div'); | |
var weekDays = widget.find('div.weekdays'); | |
var days = widget.find('div.days'); | |
var date = resetTime(_()); | |
var selected; | |
var show = function() { | |
select(val()); | |
if(!_.isMoment(selected)) { | |
date = resetTime(_()); | |
render(); | |
} | |
widget.show(); | |
prevHash = location.hash.substring(1); | |
if(prevHash === hash) { | |
prevHash = ''; | |
} | |
showing = true; | |
location.hash = hash; | |
emit('show'); | |
}; | |
var hide = function() { | |
showing = false; | |
location.hash = prevHash; | |
widget.hide(); | |
emit('hide'); | |
}; | |
var renderMonth = function() { | |
labelMonth.text(date.format(settings.format.month)); | |
emit('renderMonth'); | |
}; | |
var renderWeekdays = function() { | |
var html = ''; | |
var a = date.clone().startOf('week'); | |
var b = date.clone().endOf('week'); | |
while(a <= b) { | |
html += a.format('[<div>]ddd[</div>]'); | |
a.add('d', 1); | |
} | |
weekDays.html(html); | |
emit('renderWeekDays'); | |
}; | |
var renderDays = function() { | |
var html = ''; | |
var a = date.clone().startOf('month').startOf('week'); | |
var n = 7 * 6; | |
while(n > 0) { | |
html += a >= settings.min && a <= settings.max | |
? '<a href="#" rel="' + a.valueOf() + '">' + a.date() + '</a>' | |
: '<span>' + a.date() + '</span>'; | |
a.add('d', 1); | |
n--; | |
} | |
days.html(html); | |
if(_.isMoment(selected)) { | |
days.find('[rel="' + selected.valueOf() + '"]').addClass('selected'); | |
} | |
emit('renderDays'); | |
}; | |
var render = function(direction) { | |
renderMonth(); | |
renderDays(direction); | |
emit('render'); | |
}; | |
var emit = function(name) { | |
var event = $.Event('calendar.' + name); | |
event.api = api; | |
input.trigger(event); | |
}; | |
var val = function () { | |
return _(input.val(), settings.format.main); | |
}; | |
var set = function(v) { | |
v = _(v); | |
if(_.isMoment(v)) { | |
resetTime(v); | |
select(v); | |
input.val(selected.format(settings.format.main)); | |
emit('set'); | |
input.change(); | |
} | |
}; | |
var select = function(v) { | |
v = _(v); | |
if(_.isMoment(v)) { | |
resetTime(v); | |
date = v; | |
selected = v.clone(); | |
emit('select'); | |
render(); | |
} | |
}; | |
var addMonth = function() { | |
date.add('M', 1); | |
render(); | |
}; | |
var subtractMonth = function() { | |
date.subtract('M', 1); | |
render(); | |
}; | |
var x; | |
var getTouchX = function(event) { | |
if(event.hasOwnProperty('originalEvent')) { | |
var touch = event.originalEvent.touches[0] || event.originalEvent.changedTouches[0] || null; | |
if(touch !== null) { | |
return touch.pageX; | |
} else { | |
widget.off('touchend'); | |
} | |
} | |
return null; | |
}; | |
prevMonth.on('click', function(event) { | |
event.preventDefault(); | |
subtractMonth(); | |
}); | |
nextMonth.on('click', function(event) { | |
event.preventDefault(); | |
addMonth(); | |
}); | |
actionSet.on('click', function(event) { | |
event.preventDefault(); | |
set(selected); | |
hide(); | |
}); | |
actionCancel.on('click', function(event) { | |
event.preventDefault(); | |
hide(); | |
}); | |
days.on('click', 'a', function(event) { | |
event.preventDefault(); | |
select(_(parseInt(this.rel))); | |
}); | |
widget.on('mousewheel', function(event) { | |
event.preventDefault(); | |
var delta = parseInt(event.wheelDelta || event.detail || event.originalEvent.wheelDelta || event.originalEvent.deltaY); | |
if(delta > 0) { | |
addMonth(); | |
} else { | |
subtractMonth(); | |
} | |
}); | |
widget.on('touchstart', function(event) { | |
x = getTouchX(event); | |
}); | |
widget.on('touchend', function(event) { | |
var a = getTouchX(event); | |
var delta = a - x; | |
x = a; | |
if(!isNaN(delta) && Math.abs(delta) > settings.tolerance) { | |
event.preventDefault(); | |
if(delta < -settings.tolerance) { | |
addMonth(); | |
} else if(delta > settings.tolerance) { | |
subtractMonth(); | |
} | |
} | |
}); | |
win.on('hashchange', function() { | |
if(!showing && location.hash.substring(1) === hash) { | |
show(); | |
} else if(showing && location.hash.substring(1) !== hash) { | |
hide(); | |
} | |
}); | |
var api = { | |
settedValue: function(v) { | |
if(v !== undefined) { | |
set(v); | |
return api; | |
} | |
return val(); | |
}, | |
selectedValue: function(v) { | |
if(v !== undefined) { | |
select(v); | |
return api; | |
} | |
return selected; | |
}, | |
min: function(v) { | |
if(v !== undefined) { | |
settings.min = v; | |
render(); | |
return api; | |
} | |
return settings.min; | |
}, | |
max: function(v) { | |
if(v !== undefined) { | |
settings.max = v; | |
render(); | |
return api; | |
} | |
return settings.max; | |
}, | |
hash: function() { | |
return hash; | |
}, | |
addMonth: addMonth, | |
subtractMonth: subtractMonth, | |
show: show, | |
hide: hide | |
}; | |
input.data(pluginName, api); | |
set(input.val()); | |
renderWeekdays(); | |
render(); | |
}); | |
}; | |
})(jQuery, moment); | |
$(function() { | |
$('[data-widget-calendar]').CalendarWidget(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment