| | 1 | /** |
| | 2 | * jCalendar 0.5 |
| | 3 | * |
| | 4 | * Some code based on jQuery Date Picker (http://kelvinluck.com/assets/jquery/datePicker/) |
| | 5 | * |
| | 6 | * Copyright (c) 2007 Theodore Serbinski (http://tedserbinski.com) |
| | 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) |
| | 8 | * and GPL (GPL-LICENSE.txt) licenses. |
| | 9 | */ |
| | 10 | jQuery.jcalendar = function() { |
| | 11 | var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; |
| | 12 | var days = ['S', 'M', 'Tu', 'W', 'Th', 'F', 'S']; |
| | 13 | var navLinks = {p:'Prev', n:'Next', t:'Today'}; |
| | 14 | var _firstDayOfWeek; |
| | 15 | var _firstDate; |
| | 16 | var _lastDate; |
| | 17 | var _selectedDate; |
| | 18 | |
| | 19 | var _drawCalendar = function(dateIn, a, day, month, year) { |
| | 20 | var today = new Date(); |
| | 21 | var d; |
| | 22 | |
| | 23 | if (dateIn == undefined) { |
| | 24 | // start from this month. |
| | 25 | d = new Date(today.getFullYear(), today.getMonth(), 1); |
| | 26 | year.val(today.getFullYear()); |
| | 27 | month.val(today.getMonth()+1); |
| | 28 | day.val(today.getDate()); |
| | 29 | } |
| | 30 | else { |
| | 31 | // start from the passed in date |
| | 32 | d = dateIn; |
| | 33 | d.setDate(1); |
| | 34 | } |
| | 35 | |
| | 36 | // check that date is within allowed limits |
| | 37 | if ((d.getMonth() < _firstDate.getMonth() && d.getFullYear() == _firstDate.getFullYear()) || d.getFullYear() < _firstDate.getFullYear()) { |
| | 38 | d = new Date(_firstDate.getFullYear(), _firstDate.getMonth(), 1); |
| | 39 | } |
| | 40 | else if ((d.getMonth() > _lastDate.getMonth() && d.getFullYear() == _lastDate.getFullYear()) || d.getFullYear() > _lastDate.getFullYear()) { |
| | 41 | d = new Date(_lastDate.getFullYear(), _lastDate.getMonth(), 1); |
| | 42 | } |
| | 43 | |
| | 44 | var firstMonth = true; |
| | 45 | var firstDate = _firstDate.getDate(); |
| | 46 | |
| | 47 | // create prev and next links |
| | 48 | if (!(d.getMonth() == _firstDate.getMonth() && d.getFullYear() == _firstDate.getFullYear())) { |
| | 49 | // not in first display month so show a previous link |
| | 50 | firstMonth = false; |
| | 51 | var lastMonth = d.getMonth() == 0 ? new Date(d.getFullYear()-1, 11, 1) : new Date(d.getFullYear(), d.getMonth()-1, 1); |
| | 52 | var prevLink = jQuery('<a href="" class="link-prev">‹ '+ navLinks.p +'</a>').click(function() { |
| | 53 | jQuery.jcalendar.changeMonth(lastMonth, this, day, month, year); |
| | 54 | return false; |
| | 55 | }); |
| | 56 | } |
| | 57 | |
| | 58 | var finalMonth = true; |
| | 59 | var lastDate = _lastDate.getDate(); |
| | 60 | |
| | 61 | if (!(d.getMonth() == _lastDate.getMonth() && d.getFullYear() == _lastDate.getFullYear())) { |
| | 62 | // in the last month - no next link |
| | 63 | finalMonth = false; |
| | 64 | var nextMonth = new Date(d.getFullYear(), d.getMonth()+1, 1); |
| | 65 | var nextLink = jQuery('<a href="" class="link-next">'+ navLinks.n +' ›</a>').click(function() { |
| | 66 | jQuery.jcalendar.changeMonth(nextMonth, this, day, month, year); |
| | 67 | return false; |
| | 68 | }); |
| | 69 | } |
| | 70 | |
| | 71 | var todayLink = jQuery('<a href="" class="link-today">'+ navLinks.t +'</a>').click(function() { |
| | 72 | day.val(today.getDate()); |
| | 73 | jQuery.jcalendar.changeMonth(today, this, day, month, year); |
| | 74 | return false; |
| | 75 | }); |
| | 76 | |
| | 77 | // update the year and month select boxes |
| | 78 | year.val(d.getFullYear()); |
| | 79 | month.val(d.getMonth()+1); |
| | 80 | |
| | 81 | var headRow = jQuery("<tr></tr>"); |
| | 82 | for (var i=_firstDayOfWeek; i<_firstDayOfWeek+7; i++) { |
| | 83 | var weekday = i%7; |
| | 84 | var wordday = days[weekday]; |
| | 85 | headRow.append('<th scope="col" abbr="'+ wordday +'" title="'+ wordday +'" class="'+ (weekday == 0 || weekday == 6 ? 'weekend' : 'weekday') +'">'+ wordday +'</th>'); |
| | 86 | } |
| | 87 | headRow = jQuery("<thead></thead>").append(headRow); |
| | 88 | |
| | 89 | var tBody = jQuery("<tbody></tbody>"); |
| | 90 | var lastDay = (new Date(d.getFullYear(), d.getMonth()+1, 0)).getDate(); |
| | 91 | var curDay = _firstDayOfWeek - d.getDay(); |
| | 92 | if (curDay > 0) curDay -= 7; |
| | 93 | |
| | 94 | var todayDate = today.getDate(); |
| | 95 | var thisMonth = d.getMonth() == today.getMonth() && d.getFullYear() == today.getFullYear(); |
| | 96 | |
| | 97 | // render calendar |
| | 98 | do { |
| | 99 | var thisRow = jQuery("<tr></tr>"); |
| | 100 | for (var i=0; i<7; i++) { |
| | 101 | var weekday = (_firstDayOfWeek + i) % 7; |
| | 102 | var atts = {'class':(weekday == 0 || weekday == 6 ? 'weekend ' : 'weekday ')}; |
| | 103 | |
| | 104 | if (curDay < 0 || curDay >= lastDay) { |
| | 105 | dayStr = ' '; |
| | 106 | } |
| | 107 | else if (firstMonth && curDay < firstDate-1) { |
| | 108 | dayStr = curDay+1; |
| | 109 | atts['class'] += 'inactive'; |
| | 110 | } |
| | 111 | else if (finalMonth && curDay > lastDate-1) { |
| | 112 | dayStr = curDay+1; |
| | 113 | atts['class'] += 'inactive'; |
| | 114 | } |
| | 115 | else { |
| | 116 | d.setDate(curDay+1); |
| | 117 | |
| | 118 | // attach a click handler to every day to select it if clicked |
| | 119 | // we use the rel attribute to keep track of the day that is being clicked |
| | 120 | dayStr = jQuery('<a href="" rel="'+ d +'">'+ (curDay+1) +'</a>').click(function(e) { |
| | 121 | if (_selectedDate) { |
| | 122 | _selectedDate.removeClass('selected'); |
| | 123 | } |
| | 124 | _selectedDate = jQuery(this); |
| | 125 | _selectedDate.addClass('selected'); |
| | 126 | day.val(new Date(_selectedDate.attr('rel')).getDate()); |
| | 127 | return false; |
| | 128 | }); |
| | 129 | |
| | 130 | // highlight the current selected day |
| | 131 | if (day.val() == d.getDate()) { |
| | 132 | _selectedDate = dayStr; |
| | 133 | _selectedDate.addClass('selected'); |
| | 134 | } |
| | 135 | } |
| | 136 | |
| | 137 | if (thisMonth && curDay+1 == todayDate) { |
| | 138 | atts['class'] += 'today'; |
| | 139 | } |
| | 140 | thisRow.append(jQuery("<td></td>").attr(atts).append(dayStr)); |
| | 141 | curDay++; |
| | 142 | } |
| | 143 | |
| | 144 | tBody.append(thisRow); |
| | 145 | } while (curDay < lastDay); |
| | 146 | |
| | 147 | jQuery('div.jcalendar').html('<table cellspacing="1"></table><div class="jcalendar-links"></div>'); |
| | 148 | jQuery('div.jcalendar table').append(headRow, tBody); |
| | 149 | jQuery('div.jcalendar > div.jcalendar-links').append(prevLink, todayLink, nextLink); |
| | 150 | }; |
| | 151 | |
| | 152 | return { |
| | 153 | show: function(a, day, month, year) { |
| | 154 | _firstDate = a._startDate; |
| | 155 | _lastDate = a._endDate; |
| | 156 | _firstDayOfWeek = a._firstDayOfWeek; |
| | 157 | |
| | 158 | // pass in the selected form date if one was set |
| | 159 | var selected; |
| | 160 | if (year.val() > 0 && month.val() > 0 && day.val() > 0) { |
| | 161 | selected = new Date(year.val(), month.val()-1, day.val()); |
| | 162 | } |
| | 163 | else { |
| | 164 | selected = null; |
| | 165 | } |
| | 166 | _drawCalendar(selected, a, day, month, year); |
| | 167 | }, |
| | 168 | changeMonth: function(d, e, day, month, year) { |
| | 169 | _drawCalendar(d, e, day, month, year); |
| | 170 | }, |
| | 171 | /** |
| | 172 | * Function: setLanguageStrings |
| | 173 | * |
| | 174 | * Allows you to localise the calendar by passing in relevant text for the english strings in the plugin. |
| | 175 | * |
| | 176 | * Arguments: |
| | 177 | * days - Array, e.g. ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] |
| | 178 | * months - Array, e.g. ['January', 'Febuary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; |
| | 179 | * navLinks - Object, e.g. {p:'Prev', n:'Next', c:'Close', b:'Choose date'} |
| | 180 | **/ |
| | 181 | setLanguageStrings: function(aDays, aMonths, aNavLinks) { |
| | 182 | days = aDays; |
| | 183 | months = aMonths; |
| | 184 | navLinks = aNavLinks; |
| | 185 | }, |
| | 186 | /** |
| | 187 | * Function: setDateWindow |
| | 188 | * |
| | 189 | * Used internally to set the start and end dates for a given date select |
| | 190 | * |
| | 191 | * Arguments: |
| | 192 | * i - The id of the INPUT element this date window is for |
| | 193 | * w - The date window - an object containing startDate and endDate properties |
| | 194 | * e.g. {startDate:'24-11-1981', endDate:'25-12-2012} |
| | 195 | **/ |
| | 196 | setDateWindow: function(i, w, year) { |
| | 197 | if (w == undefined) w = {}; |
| | 198 | if (w.startDate == undefined) { |
| | 199 | // set the minimum browseable date equal to January of the min year in the select box |
| | 200 | // don't get the first option because that is an empty year |
| | 201 | |
| | 202 | // note we can't do this: year.find('option:eq(1)').val() |
| | 203 | // it doesn't work in 1.0 since find() is destructive |
| | 204 | // so we copy the object to a new var |
| | 205 | i._startDate = new Date(jQuery(year).find('option:eq(1)').val(), 0, 1); |
| | 206 | } |
| | 207 | else { |
| | 208 | dateParts = w.startDate.split('-'); |
| | 209 | i._startDate = new Date(dateParts[2], Number(dateParts[1])-1, Number(dateParts[0])); |
| | 210 | } |
| | 211 | if (w.endDate == undefined) { |
| | 212 | // set the maximum browseable date equal to December of the max year in the select box |
| | 213 | |
| | 214 | // note we can't do this: year.find('option:last').val() |
| | 215 | // it doesn't work in 1.0 since find() is destructive |
| | 216 | // so we copy the object to a new var |
| | 217 | i._endDate = new Date(jQuery(year).find('option:last').val(), 11, 1); |
| | 218 | } |
| | 219 | else { |
| | 220 | dateParts = w.endDate.split('-'); |
| | 221 | i._endDate = new Date(dateParts[2], Number(dateParts[1])-1, Number(dateParts[0])); |
| | 222 | } |
| | 223 | i._firstDayOfWeek = w.firstDayOfWeek == undefined ? 0 : w.firstDayOfWeek; |
| | 224 | } |
| | 225 | }; |
| | 226 | }(); |
| | 227 | |
| | 228 | jQuery.fn.jcalendar = function(a) { |
| | 229 | this.each(function() { |
| | 230 | var day = jQuery(this).find('select.jcalendar-select-day'); |
| | 231 | var month = jQuery(this).find('select.jcalendar-select-month'); |
| | 232 | var year = jQuery(this).find('select.jcalendar-select-year'); |
| | 233 | jQuery('div.jcalendar-selects').after('<div class="jcalendar"></div>'); |
| | 234 | jQuery.jcalendar.setDateWindow(this, a, year); |
| | 235 | jQuery.jcalendar.show(this, day, month, year); |
| | 236 | |
| | 237 | day.change(function() { |
| | 238 | // only if a valid day is selected |
| | 239 | if (this.value > 0) { |
| | 240 | d = new Date(year.val(), month.val()-1, this.value); |
| | 241 | jQuery.jcalendar.changeMonth(d, a, day, month, year); |
| | 242 | } |
| | 243 | }); |
| | 244 | |
| | 245 | month.change(function() { |
| | 246 | // only if a valid month is selected |
| | 247 | if (this.value > 0) { |
| | 248 | d = new Date(year.val(), this.value-1, 1); |
| | 249 | jQuery.jcalendar.changeMonth(d, a, day, month, year); |
| | 250 | } |
| | 251 | }); |
| | 252 | |
| | 253 | year.change(function() { |
| | 254 | // only if a valid year is selected |
| | 255 | if (this.value > 0) { |
| | 256 | d = new Date(this.value, month.val()-1, 1); |
| | 257 | jQuery.jcalendar.changeMonth(d, a, day, month, year); |
| | 258 | } |
| | 259 | }); |
| | 260 | |
| | 261 | }); |
| | 262 | return this; |
| | 263 | }; |