Created
March 29, 2010 06:13
-
-
Save jimjeffers/347496 to your computer and use it in GitHub Desktop.
A simple calendar input that only has essential functionality.
This file contains hidden or 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
| jQuery.fn.calendarInput: (options) -> | |
| defaults: { | |
| active_class: "active" | |
| calendar_id: "calendar_table" | |
| calendar_class: "calendar_object" | |
| calendar_container_id: "calendar_container" | |
| controls_class: "calendar_controls" | |
| custom_class: false | |
| default_class: "calendar_input" | |
| dont_allow_dates_from_the_past: true | |
| inactive_class: "inactive" | |
| indicator_class: "calendar_indicator" | |
| prior_class: "prior_month" | |
| prior_button_class: "prior_button" | |
| month_name_class: "month_name" | |
| next_class: "next_month" | |
| next_button_class: "next_button" | |
| reset_class: "calendar_reset" | |
| wrapper: "<span>" | |
| } | |
| settings: jQuery.extend(defaults,options) | |
| class CalendarController | |
| constructor: -> | |
| @date_pattern = /(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/ | |
| @current_date = new Date() | |
| @today = new Date() | |
| @present_day: @today.getDate() | |
| @present_month: @today.getMonth() | |
| @weekdays = [ | |
| "sun" | |
| "mon" | |
| "tue" | |
| "wed" | |
| "thr" | |
| "fri" | |
| "sat" | |
| ] | |
| @months = [ | |
| "January" | |
| "February" | |
| "March" | |
| "April" | |
| "May" | |
| "June" | |
| "July" | |
| "August" | |
| "September" | |
| "October" | |
| "Novemeber" | |
| "December" | |
| ] | |
| # Generate the table if it doesn't exist yet. Since we rely on an ID this is | |
| # technically a singleton pattern imposed via the DOM. | |
| @calendar_table = $("#"+settings.calendar_id) | |
| if @calendar_table.length < 1 | |
| $("body").append("<div id=\""+settings.calendar_container_id+"\"><table id=\""+settings.calendar_id+"\" class=\""+settings.calendar_class+"\"></table></div>") | |
| $("#"+settings.calendar_container_id).prepend("<ul class=\""+settings.controls_class+"\"><li class=\""+settings.next_button_class+"\"><a href=\"#\">></a></li><li class=\""+settings.prior_button_class+"\"><a href=\"#\"><</a></li><li class=\""+settings.month_name_class+"\"></li></ul>") | |
| @container = $("#"+settings.calendar_container_id).addClass("inactive") | |
| @calendar_table = $("#"+settings.calendar_id) | |
| @calendar_controls = $("."+settings.controls_class) | |
| @calendar_controls.delegate("a", "click", (e) => | |
| link: $(e.target) | |
| if link.parent().hasClass(settings.prior_button_class) | |
| this.backward() | |
| else if link.parent().hasClass(settings.next_button_class) | |
| this.forward() | |
| false | |
| ) | |
| @month_name = @calendar_controls.find("."+settings.month_name_class) | |
| @next_button = @calendar_controls.find("."+settings.next_button_class) | |
| @prior_button = @calendar_controls.find("."+settings.prior_button_class) | |
| # Add event delegation to listen for clicks. | |
| @calendar_table.delegate("a", "click", (e) => | |
| @current_date = new Date(@current_date.getFullYear(), @current_date.getMonth(),$(e.target).html()) | |
| this.update_input() | |
| this.deactivate() | |
| false | |
| ) | |
| # Build calendar object html. | |
| for week in [0..5] | |
| if week > 0 | |
| @calendar_table.append("<tr class=\"week\"></tr>") | |
| row: @calendar_table.find("tr:last-child") | |
| else | |
| @calendar_table.append("<th class=\"week\"></th>") | |
| row: @calendar_table.find("th:first-child") | |
| for day in [0..6] | |
| if week > 0 | |
| row.append("<td class=\"day "+@weekdays[day]+"\"></td>") | |
| else | |
| row.append("<td class=\"day "+@weekdays[day]+"\">"+@weekdays[day]+"</td>") | |
| # Set the initial date to the current day. | |
| this.set(@current_date.getFullYear(), @current_date.getMonth(), @current_date.getDate()) | |
| # Bind event listener to close the calendar input if the user clicks off the element. | |
| $("body").click( (e) => | |
| this.deactivate() if @container.hasClass(settings.active_class) | |
| ) | |
| set: (year,month,day) -> | |
| @current_date = new Date(year,month-1,day) | |
| @month_name.html(@months[@current_date.getMonth()]+" "+@current_date.getFullYear()) | |
| month_start: new Date(@current_date.getFullYear(), @current_date.getMonth(),1) | |
| month_end: new Date(@current_date.getFullYear(), @current_date.getMonth()+1,0) | |
| month_days: [1..month_end.getDate()] | |
| if month_start.getDay() > 0 | |
| prior_month_end: new Date(@current_date.getFullYear(), @current_date.getMonth(),0) | |
| prior_month_start: new Date(@current_date.getFullYear(), @current_date.getMonth(),(-month_start.getDay()+1)) | |
| prior_month_days: [prior_month_start.getDate()..prior_month_end.getDate()] | |
| else | |
| prior_month_days: [] | |
| next_month_end: new Date(@current_date.getFullYear(), @current_date.getMonth()+3,0) | |
| next_month_start: new Date(@current_date.getFullYear(), @current_date.getMonth()+2,1) | |
| next_month_days: [next_month_start.getDate()..next_month_end.getDate()] | |
| @current_month: @current_date.getMonth() | |
| cells: $("tr td.day") | |
| cells.removeClass(settings.next_class).removeClass(settings.prior_class).each( (index) => | |
| cell: $(cells.get(index)) | |
| if index < prior_month_days.length | |
| cell.html(prior_month_days[index]).addClass(settings.prior_class) | |
| else if index < month_days.length + prior_month_days.length | |
| date_active: true | |
| day_number: month_days[index-prior_month_days.length] | |
| if settings.dont_allow_dates_from_the_past and day_number < @present_day and @current_month == @present_month | |
| date_active = false | |
| else if settings.dont_allow_dates_from_the_past and @current_month < @present_month | |
| date_active = false | |
| if date_active | |
| cell.html("<a href=\"#\">"+month_days[index-prior_month_days.length]+"</a>") | |
| else | |
| cell.html(month_days[index-prior_month_days.length]).addClass(settings.inactive_class) | |
| else | |
| cell.html(next_month_days[index-prior_month_days.length-month_days.length]).addClass(settings.next_class) | |
| ) | |
| set_from_input: (value) -> | |
| if @date_pattern.test(value) | |
| values: value.split("/") | |
| this.set(parseInt(values[2]), parseInt(values[0]), parseInt(values[1])) | |
| forward: -> | |
| this.set(@current_date.getFullYear(), @current_date.getMonth()+2, 1) | |
| backward: -> | |
| prior_month: @current_date.getMonth()-1 | |
| if settings.dont_allow_dates_from_the_past | |
| if current_month >= @present_month | |
| this.set(@current_date.getFullYear(), @current_date.getMonth(), 1) | |
| if current_month == @present_month | |
| @prior_button.addClass(settings.inactive_class) | |
| else | |
| this.set(@current_date.getFullYear(), @current_date.getMonth(), 1) | |
| activate: (input) -> | |
| @input = input | |
| this.snap_to_input() | |
| this.set_from_input(input.val()) if input.val() | |
| @container.addClass(settings.active_class).removeClass(settings.inactive_class) | |
| deactivate: () -> | |
| @container.removeClass(settings.active_class).addClass(settings.inactive_class) | |
| snap_to_input: () -> | |
| coordinates: @input.offset() | |
| display_height: parseInt(@input.css("padding-bottom")) + | |
| parseInt(@input.css("padding-top")) + | |
| @input.height() | |
| @container.css("top",coordinates.top+display_height+10+"px") | |
| @container.css("left",coordinates.left+"px") | |
| update_input: () -> | |
| day: @current_date.getDate() | |
| month: @current_date.getMonth()+1 | |
| year: @current_date.getFullYear() | |
| if day < 10 | |
| day = "0"+day | |
| if month < 10 | |
| month = "0"+month | |
| @input.val(month+"/"+day+"/"+year) | |
| calendar_controller: new CalendarController() | |
| this.each( -> | |
| input: $(this) | |
| input.wrap(settings.wrapper) | |
| input.click( (e) -> | |
| input: $(e.target) | |
| calendar_controller.activate(input) | |
| false | |
| ) | |
| container: input.parent().addClass(settings.default_class) | |
| container.addClass(settings.custom_class) if settings.custom_class | |
| container.append("<a href=\"#\"></a>") | |
| input.next().addClass(settings.indicator_class).click( (e) -> | |
| input: $(e.target).parent().find("input") | |
| calendar_controller.activate(input) | |
| false | |
| ) | |
| ) |
This file contains hidden or 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(){ | |
| jQuery.fn.calendarInput = function calendarInput(options) { | |
| var CalendarController, calendar_controller, defaults, settings; | |
| defaults = { | |
| active_class: "active", | |
| calendar_id: "calendar_table", | |
| calendar_class: "calendar_object", | |
| calendar_container_id: "calendar_container", | |
| controls_class: "calendar_controls", | |
| custom_class: false, | |
| default_class: "calendar_input", | |
| dont_allow_dates_from_the_past: true, | |
| inactive_class: "inactive", | |
| indicator_class: "calendar_indicator", | |
| prior_class: "prior_month", | |
| prior_button_class: "prior_button", | |
| month_name_class: "month_name", | |
| next_class: "next_month", | |
| next_button_class: "next_button", | |
| reset_class: "calendar_reset", | |
| wrapper: "<span>" | |
| }; | |
| settings = jQuery.extend(defaults, options); | |
| CalendarController = function CalendarController() { | |
| var _a, _b, _c, _d, _e, _f, _g, _h, day, row, week; | |
| this.current_date = new Date(); | |
| this.today = new Date(); | |
| this.present_day = this.today.getDate(); | |
| this.present_month = this.today.getMonth(); | |
| this.weekdays = ["sun", "mon", "tue", "wed", "thr", "fri", "sat"]; | |
| this.months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "Novemeber", "December"]; | |
| this.date_pattern = /(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/; | |
| // Generate the table if it doesn't exist yet. Since we rely on an ID this is | |
| // technically a singleton pattern imposed via the DOM. | |
| this.calendar_table = $("#" + settings.calendar_id); | |
| if (this.calendar_table.length < 1) { | |
| $("body").append("<div id=\"" + settings.calendar_container_id + "\"><table id=\"" + settings.calendar_id + "\" class=\"" + settings.calendar_class + "\"></table></div>"); | |
| $("#" + settings.calendar_container_id).prepend("<ul class=\"" + settings.controls_class + "\"><li class=\"" + settings.next_button_class + "\"><a href=\"#\">></a></li><li class=\"" + settings.prior_button_class + "\"><a href=\"#\"><</a></li><li class=\"" + settings.month_name_class + "\"></li></ul>"); | |
| this.container = $("#" + settings.calendar_container_id).addClass("inactive"); | |
| this.calendar_table = $("#" + settings.calendar_id); | |
| this.calendar_controls = $("." + settings.controls_class); | |
| this.calendar_controls.delegate("a", "click", (function(__this) { | |
| var __func = function(e) { | |
| var link; | |
| link = $(e.target); | |
| if (link.parent().hasClass(settings.prior_button_class)) { | |
| this.backward(); | |
| } else if (link.parent().hasClass(settings.next_button_class)) { | |
| this.forward(); | |
| } | |
| return false; | |
| }; | |
| return (function() { | |
| return __func.apply(__this, arguments); | |
| }); | |
| })(this)); | |
| this.month_name = this.calendar_controls.find("." + settings.month_name_class); | |
| this.next_button = this.calendar_controls.find("." + settings.next_button_class); | |
| this.prior_button = this.calendar_controls.find("." + settings.prior_button_class); | |
| // Add event delegation to listen for clicks. | |
| this.calendar_table.delegate("a", "click", (function(__this) { | |
| var __func = function(e) { | |
| this.current_date = new Date(this.current_date.getFullYear(), this.current_date.getMonth(), $(e.target).html()); | |
| this.update_input(); | |
| this.deactivate(); | |
| return false; | |
| }; | |
| return (function() { | |
| return __func.apply(__this, arguments); | |
| }); | |
| })(this)); | |
| // Build calendar object html. | |
| _c = 0; _d = 5; | |
| for (_b = 0, week = _c; (_c <= _d ? week <= _d : week >= _d); (_c <= _d ? week += 1 : week -= 1), _b++) { | |
| if (week > 0) { | |
| this.calendar_table.append("<tr class=\"week\"></tr>"); | |
| row = this.calendar_table.find("tr:last-child"); | |
| } else { | |
| this.calendar_table.append("<th class=\"week\"></th>"); | |
| row = this.calendar_table.find("th:first-child"); | |
| } | |
| _g = 0; _h = 6; | |
| for (_f = 0, day = _g; (_g <= _h ? day <= _h : day >= _h); (_g <= _h ? day += 1 : day -= 1), _f++) { | |
| week > 0 ? row.append("<td class=\"day " + this.weekdays[day] + "\"></td>") : row.append("<td class=\"day " + this.weekdays[day] + "\">" + this.weekdays[day] + "</td>"); | |
| } | |
| } | |
| } | |
| // Set the initial date to the current day. | |
| this.set(this.current_date.getFullYear(), this.current_date.getMonth(), this.current_date.getDate()); | |
| // Bind event listener to close the calendar input if the user clicks off the element. | |
| $("body").click((function(__this) { | |
| var __func = function(e) { | |
| if (this.container.hasClass(settings.active_class)) { | |
| return this.deactivate(); | |
| } | |
| }; | |
| return (function() { | |
| return __func.apply(__this, arguments); | |
| }); | |
| })(this)); | |
| return this; | |
| }; | |
| CalendarController.prototype.set = function set(year, month, day) { | |
| var _a, _b, _c, cells, month_days, month_end, month_start, next_month_days, next_month_end, next_month_start, prior_month_days, prior_month_end, prior_month_start; | |
| this.current_date = new Date(year, month - 1, day); | |
| this.month_name.html(this.months[this.current_date.getMonth()] + " " + this.current_date.getFullYear()); | |
| month_start = new Date(this.current_date.getFullYear(), this.current_date.getMonth(), 1); | |
| month_end = new Date(this.current_date.getFullYear(), this.current_date.getMonth() + 1, 0); | |
| month_days = (function() { | |
| var _b, _c, _d, _e, _f; | |
| _b = []; _e = 1; _f = month_end.getDate(); | |
| for (_d = 0, _a = _e; (_e <= _f ? _a <= _f : _a >= _f); (_e <= _f ? _a += 1 : _a -= 1), _d++) { | |
| _b.push(_a); | |
| } | |
| return _b; | |
| }()); | |
| if (month_start.getDay() > 0) { | |
| prior_month_end = new Date(this.current_date.getFullYear(), this.current_date.getMonth(), 0); | |
| prior_month_start = new Date(this.current_date.getFullYear(), this.current_date.getMonth(), (-month_start.getDay() + 1)); | |
| prior_month_days = (function() { | |
| var _c, _d, _e, _f, _g; | |
| _c = []; _f = prior_month_start.getDate(); _g = prior_month_end.getDate(); | |
| for (_e = 0, _b = _f; (_f <= _g ? _b <= _g : _b >= _g); (_f <= _g ? _b += 1 : _b -= 1), _e++) { | |
| _c.push(_b); | |
| } | |
| return _c; | |
| }()); | |
| } else { | |
| prior_month_days = []; | |
| } | |
| next_month_end = new Date(this.current_date.getFullYear(), this.current_date.getMonth() + 3, 0); | |
| next_month_start = new Date(this.current_date.getFullYear(), this.current_date.getMonth() + 2, 1); | |
| next_month_days = (function() { | |
| var _d, _e, _f, _g, _h; | |
| _d = []; _g = next_month_start.getDate(); _h = next_month_end.getDate(); | |
| for (_f = 0, _c = _g; (_g <= _h ? _c <= _h : _c >= _h); (_g <= _h ? _c += 1 : _c -= 1), _f++) { | |
| _d.push(_c); | |
| } | |
| return _d; | |
| }()); | |
| this.current_month = this.current_date.getMonth(); | |
| cells = $("tr td.day"); | |
| return cells.removeClass(settings.next_class).removeClass(settings.prior_class).each((function(__this) { | |
| var __func = function(index) { | |
| var cell, date_active, day_number; | |
| cell = $(cells.get(index)); | |
| if (index < prior_month_days.length) { | |
| return cell.html(prior_month_days[index]).addClass(settings.prior_class); | |
| } else if (index < month_days.length + prior_month_days.length) { | |
| date_active = true; | |
| day_number = month_days[index - prior_month_days.length]; | |
| if (settings.dont_allow_dates_from_the_past && day_number < this.present_day && this.current_month === this.present_month) { | |
| date_active = false; | |
| } else if (settings.dont_allow_dates_from_the_past && this.current_month < this.present_month) { | |
| date_active = false; | |
| } | |
| return date_active ? cell.html("<a href=\"#\">" + month_days[index - prior_month_days.length] + "</a>") : cell.html(month_days[index - prior_month_days.length]).addClass(settings.inactive_class); | |
| } else { | |
| return cell.html(next_month_days[index - prior_month_days.length - month_days.length]).addClass(settings.next_class); | |
| } | |
| }; | |
| return (function() { | |
| return __func.apply(__this, arguments); | |
| }); | |
| })(this)); | |
| }; | |
| CalendarController.prototype.set_from_input = function set_from_input(value) { | |
| var values; | |
| if (this.date_pattern.test(value)) { | |
| values = value.split("/"); | |
| return this.set(parseInt(values[2]), parseInt(values[0]), parseInt(values[1])); | |
| } | |
| }; | |
| CalendarController.prototype.forward = function forward() { | |
| return this.set(this.current_date.getFullYear(), this.current_date.getMonth() + 2, 1); | |
| }; | |
| CalendarController.prototype.backward = function backward() { | |
| var prior_month; | |
| prior_month = this.current_date.getMonth() - 1; | |
| if (settings.dont_allow_dates_from_the_past) { | |
| current_month >= this.present_month ? this.set(this.current_date.getFullYear(), this.current_date.getMonth(), 1) : null; | |
| return current_month === this.present_month ? this.prior_button.addClass(settings.inactive_class) : null; | |
| } else { | |
| return this.set(this.current_date.getFullYear(), this.current_date.getMonth(), 1); | |
| } | |
| }; | |
| CalendarController.prototype.activate = function activate(input) { | |
| this.input = input; | |
| this.snap_to_input(); | |
| if (input.val()) { | |
| this.set_from_input(input.val()); | |
| } | |
| return this.container.addClass(settings.active_class).removeClass(settings.inactive_class); | |
| }; | |
| CalendarController.prototype.deactivate = function deactivate() { | |
| return this.container.removeClass(settings.active_class).addClass(settings.inactive_class); | |
| }; | |
| CalendarController.prototype.snap_to_input = function snap_to_input() { | |
| var coordinates, display_height; | |
| coordinates = this.input.offset(); | |
| display_height = parseInt(this.input.css("padding-bottom")) + parseInt(this.input.css("padding-top")) + this.input.height(); | |
| this.container.css("top", coordinates.top + display_height + 10 + "px"); | |
| return this.container.css("left", coordinates.left + "px"); | |
| }; | |
| CalendarController.prototype.update_input = function update_input() { | |
| var day, month, year; | |
| day = this.current_date.getDate(); | |
| month = this.current_date.getMonth() + 1; | |
| year = this.current_date.getFullYear(); | |
| day < 10 ? (day = "0" + day) : null; | |
| month < 10 ? (month = "0" + month) : null; | |
| return this.input.val(month + "/" + day + "/" + year); | |
| }; | |
| calendar_controller = new CalendarController(); | |
| return this.each(function() { | |
| var container, input; | |
| input = $(this); | |
| input.wrap(settings.wrapper); | |
| input.click(function(e) { | |
| input = $(e.target); | |
| calendar_controller.activate(input); | |
| return false; | |
| }); | |
| container = input.parent().addClass(settings.default_class); | |
| if (settings.custom_class) { | |
| container.addClass(settings.custom_class); | |
| } | |
| container.append("<a href=\"#\"></a>"); | |
| return input.next().addClass(settings.indicator_class).click(function(e) { | |
| input = $(e.target).parent().find("input"); | |
| calendar_controller.activate(input); | |
| return false; | |
| }); | |
| }); | |
| }; | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment