PageRenderTime 29ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/js/jquery.cal.js

http://yourls.googlecode.com/
JavaScript | 319 lines | 200 code | 59 blank | 60 comment | 96 complexity | 80045fc6415a1e9c7bf01581099426cc MD5 | raw file
  1. /**
  2. the script only works on "input [type=text]"
  3. http://teddevito.com/demos/calendar.php
  4. **/
  5. // don't declare anything out here in the global namespace
  6. (function($) { // create private scope (inside you can use $ instead of jQuery)
  7. // functions and vars declared here are effectively 'singletons'. there will be only a single
  8. // instance of them. so this is a good place to declare any immutable items or stateless
  9. // functions. for example:
  10. var today = new Date(); // used in defaults
  11. var months = 'January,February,March,April,May,June,July,August,September,October,November,December'.split(',');
  12. var months = l10n_cal_month;
  13. var monthlengths = '31,28,31,30,31,30,31,31,30,31,30,31'.split(',');
  14. var dateRegEx = /^\d{1,2}\/\d{1,2}\/\d{2}|\d{4}$/;
  15. var yearRegEx = /^\d{4,4}$/;
  16. // next, declare the plugin function
  17. $.fn.simpleDatepicker = function(options) {
  18. // functions and vars declared here are created each time your plugn function is invoked
  19. // you could probably refactor your 'build', 'load_month', etc, functions to be passed
  20. // the DOM element from below
  21. var opts = jQuery.extend({}, jQuery.fn.simpleDatepicker.defaults, options);
  22. // replaces a date string with a date object in opts.startdate and opts.enddate, if one exists
  23. // populates two new properties with a ready-to-use year: opts.startyear and opts.endyear
  24. setupYearRange();
  25. /** extracts and setup a valid year range from the opts object **/
  26. function setupYearRange () {
  27. var startyear, endyear;
  28. if (opts.startdate.constructor == Date) {
  29. startyear = opts.startdate.getFullYear();
  30. } else if (opts.startdate) {
  31. if (yearRegEx.test(opts.startdate)) {
  32. startyear = opts.startdate;
  33. } else if (dateRegEx.test(opts.startdate)) {
  34. opts.startdate = new Date(opts.startdate);
  35. startyear = opts.startdate.getFullYear();
  36. } else {
  37. startyear = today.getFullYear();
  38. }
  39. } else {
  40. startyear = today.getFullYear();
  41. }
  42. opts.startyear = startyear;
  43. if (opts.enddate.constructor == Date) {
  44. endyear = opts.enddate.getFullYear();
  45. } else if (opts.enddate) {
  46. if (yearRegEx.test(opts.enddate)) {
  47. endyear = opts.enddate;
  48. } else if (dateRegEx.test(opts.enddate)) {
  49. opts.enddate = new Date(opts.enddate);
  50. endyear = opts.enddate.getFullYear();
  51. } else {
  52. endyear = today.getFullYear();
  53. }
  54. } else {
  55. endyear = today.getFullYear();
  56. }
  57. opts.endyear = endyear;
  58. }
  59. /** HTML factory for the actual datepicker table element **/
  60. // has to read the year range so it can setup the correct years in our HTML <select>
  61. function newDatepickerHTML () {
  62. var years = [];
  63. // process year range into an array
  64. for (var i = 0; i <= opts.endyear - opts.startyear; i ++) years[i] = opts.startyear + i;
  65. // build the table structure
  66. var table = jQuery('<table class="datepicker" cellpadding="0" cellspacing="0"></table>');
  67. table.append('<thead></thead>');
  68. table.append('<tfoot></tfoot>');
  69. table.append('<tbody></tbody>');
  70. // month select field
  71. var monthselect = '<select name="month">';
  72. for (var i in l10n_cal_month) monthselect += '<option value="'+i+'">'+l10n_cal_month[i]+'</option>';
  73. monthselect += '</select>';
  74. // year select field
  75. var yearselect = '<select name="year">';
  76. for (var i in years) yearselect += '<option>'+years[i]+'</option>';
  77. yearselect += '</select>';
  78. jQuery("thead",table).append('<tr class="controls"><th colspan="7"><span class="prevMonth">&laquo;</span>&nbsp;'+monthselect+yearselect+'&nbsp;<span class="nextMonth">&raquo;</span></th></tr>');
  79. jQuery("thead",table).append('<tr class="days"><th>'+l10n_cal_days[0]+'</th><th>'+l10n_cal_days[1]+'</th><th>'+l10n_cal_days[2]+'</th><th>'+l10n_cal_days[3]+'</th><th>'+l10n_cal_days[4]+'</th><th>'+l10n_cal_days[5]+'</th><th>'+l10n_cal_days[6]+'</th></tr>');
  80. jQuery("tfoot",table).append('<tr><td colspan="2"><span class="today">'+l10n_cal_today+'</span></td><td colspan="3">&nbsp;</td><td colspan="2"><span class="close">'+l10n_cal_close+'</span></td></tr>');
  81. for (var i = 0; i < 6; i++) jQuery("tbody",table).append('<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>');
  82. return table;
  83. }
  84. /** get the real position of the input (well, anything really) **/
  85. //http://www.quirksmode.org/js/findpos.html
  86. function findPosition (obj) {
  87. var curleft = curtop = 0;
  88. if (obj.offsetParent) {
  89. do {
  90. curleft += obj.offsetLeft;
  91. curtop += obj.offsetTop;
  92. } while (obj = obj.offsetParent);
  93. return [curleft,curtop];
  94. } else {
  95. return false;
  96. }
  97. }
  98. /** load the initial date and handle all date-navigation **/
  99. // initial calendar load (e is null)
  100. // prevMonth & nextMonth buttons
  101. // onchange for the select fields
  102. function loadMonth (e, el, datepicker, chosendate) {
  103. // reference our years for the nextMonth and prevMonth buttons
  104. var mo = jQuery("select[name=month]", datepicker).get(0).selectedIndex;
  105. var yr = jQuery("select[name=year]", datepicker).get(0).selectedIndex;
  106. var yrs = jQuery("select[name=year] option", datepicker).get().length;
  107. // first try to process buttons that may change the month we're on
  108. if (e && jQuery(e.target).hasClass('prevMonth')) {
  109. if (0 == mo && yr) {
  110. yr -= 1; mo = 11;
  111. jQuery("select[name=month]", datepicker).get(0).selectedIndex = 11;
  112. jQuery("select[name=year]", datepicker).get(0).selectedIndex = yr;
  113. } else {
  114. mo -= 1;
  115. jQuery("select[name=month]", datepicker).get(0).selectedIndex = mo;
  116. }
  117. } else if (e && jQuery(e.target).hasClass('nextMonth')) {
  118. if (11 == mo && yr + 1 < yrs) {
  119. yr += 1; mo = 0;
  120. jQuery("select[name=month]", datepicker).get(0).selectedIndex = 0;
  121. jQuery("select[name=year]", datepicker).get(0).selectedIndex = yr;
  122. } else {
  123. mo += 1;
  124. jQuery("select[name=month]", datepicker).get(0).selectedIndex = mo;
  125. }
  126. }
  127. // maybe hide buttons
  128. if (0 == mo && !yr) jQuery("span.prevMonth", datepicker).hide();
  129. else jQuery("span.prevMonth", datepicker).show();
  130. if (yr + 1 == yrs && 11 == mo) jQuery("span.nextMonth", datepicker).hide();
  131. else jQuery("span.nextMonth", datepicker).show();
  132. // clear the old cells
  133. var cells = jQuery("tbody td", datepicker).unbind().empty().removeClass('date');
  134. // figure out what month and year to load
  135. var m = jQuery("select[name=month]", datepicker).val();
  136. var y = jQuery("select[name=year]", datepicker).val();
  137. var d = new Date(y, m, 1);
  138. var startindex = d.getDay();
  139. var numdays = monthlengths[m];
  140. // http://en.wikipedia.org/wiki/Leap_year
  141. if (1 == m && ((y%4 == 0 && y%100 != 0) || y%400 == 0)) numdays = 29;
  142. // test for end dates (instead of just a year range)
  143. if (opts.startdate.constructor == Date) {
  144. var startMonth = opts.startdate.getMonth();
  145. var startDate = opts.startdate.getDate();
  146. }
  147. if (opts.enddate.constructor == Date) {
  148. var endMonth = opts.enddate.getMonth();
  149. var endDate = opts.enddate.getDate();
  150. }
  151. // walk through the index and populate each cell, binding events too
  152. for (var i = 0; i < numdays; i++) {
  153. var cell = jQuery(cells.get(i+startindex)).removeClass('chosen');
  154. // test that the date falls within a range, if we have a range
  155. if (
  156. (yr || ((!startDate && !startMonth) || ((i+1 >= startDate && mo == startMonth) || mo > startMonth))) &&
  157. (yr + 1 < yrs || ((!endDate && !endMonth) || ((i+1 <= endDate && mo == endMonth) || mo < endMonth)))) {
  158. cell
  159. .text(i+1)
  160. .addClass('date')
  161. .hover(
  162. function () { jQuery(this).addClass('over'); },
  163. function () { jQuery(this).removeClass('over'); })
  164. .click(function () {
  165. var chosenDateObj = new Date(jQuery("select[name=year]", datepicker).val(), jQuery("select[name=month]", datepicker).val(), jQuery(this).text());
  166. closeIt(el, datepicker, chosenDateObj);
  167. });
  168. // highlight the previous chosen date
  169. if (i+1 == chosendate.getDate() && m == chosendate.getMonth() && y == chosendate.getFullYear()) cell.addClass('chosen');
  170. }
  171. }
  172. }
  173. /** closes the datepicker **/
  174. // sets the currently matched input element's value to the date, if one is available
  175. // remove the table element from the DOM
  176. // indicate that there is no datepicker for the currently matched input element
  177. function closeIt (el, datepicker, dateObj) {
  178. if (dateObj && dateObj.constructor == Date)
  179. el.val(jQuery.fn.simpleDatepicker.formatOutput(dateObj));
  180. datepicker.remove();
  181. datepicker = null;
  182. jQuery.data(el.get(0), "simpleDatepicker", { hasDatepicker : false });
  183. }
  184. // iterate the matched nodeset
  185. return this.each(function() {
  186. // functions and vars declared here are created for each matched element. so if
  187. // your functions need to manage or access per-node state you can defined them
  188. // here and use $this to get at the DOM element
  189. if ( jQuery(this).is('input') && 'text' == jQuery(this).attr('type')) {
  190. var datepicker;
  191. jQuery.data(jQuery(this).get(0), "simpleDatepicker", { hasDatepicker : false });
  192. // open a datepicker on the click event
  193. jQuery(this).click(function (ev) {
  194. var $this = jQuery(ev.target);
  195. if (false == jQuery.data($this.get(0), "simpleDatepicker").hasDatepicker) {
  196. // store data telling us there is already a datepicker
  197. jQuery.data($this.get(0), "simpleDatepicker", { hasDatepicker : true });
  198. // validate the form's initial content for a date
  199. var initialDate = $this.val();
  200. if (initialDate && dateRegEx.test(initialDate)) {
  201. var chosendate = new Date(initialDate);
  202. } else if (opts.chosendate.constructor == Date) {
  203. var chosendate = opts.chosendate;
  204. } else if (opts.chosendate) {
  205. var chosendate = new Date(opts.chosendate);
  206. } else {
  207. var chosendate = today;
  208. }
  209. // insert the datepicker in the DOM
  210. datepicker = newDatepickerHTML();
  211. jQuery("body").prepend(datepicker);
  212. // position the datepicker
  213. var elPos = findPosition($this.get(0));
  214. var x = (parseInt(opts.x) ? parseInt(opts.x) : 0) + elPos[0];
  215. var y = (parseInt(opts.y) ? parseInt(opts.y) : 0) + elPos[1];
  216. jQuery(datepicker).css({ position: 'absolute', left: x, top: y });
  217. // bind events to the table controls
  218. jQuery("span", datepicker).css("cursor","pointer");
  219. jQuery("select", datepicker).bind('change', function () { loadMonth (null, $this, datepicker, chosendate); });
  220. jQuery("span.prevMonth", datepicker).click(function (e) { loadMonth (e, $this, datepicker, chosendate); });
  221. jQuery("span.nextMonth", datepicker).click(function (e) { loadMonth (e, $this, datepicker, chosendate); });
  222. jQuery("span.today", datepicker).click(function () { closeIt($this, datepicker, new Date()); });
  223. jQuery("span.close", datepicker).click(function () { closeIt($this, datepicker); });
  224. // set the initial values for the month and year select fields
  225. // and load the first month
  226. jQuery("select[name=month]", datepicker).get(0).selectedIndex = chosendate.getMonth();
  227. jQuery("select[name=year]", datepicker).get(0).selectedIndex = Math.max(0, chosendate.getFullYear() - opts.startyear);
  228. loadMonth(null, $this, datepicker, chosendate);
  229. }
  230. });
  231. }
  232. });
  233. };
  234. // finally, I like to expose default plugin options as public so they can be manipulated. one
  235. // way to do this is to add a property to the already-public plugin fn
  236. jQuery.fn.simpleDatepicker.formatOutput = function (dateObj) {
  237. return (dateObj.getMonth() + 1) + "/" + dateObj.getDate() + "/" + dateObj.getFullYear();
  238. };
  239. jQuery.fn.simpleDatepicker.defaults = {
  240. // date string matching /^\d{1,2}\/\d{1,2}\/\d{2}|\d{4}$/
  241. chosendate : today,
  242. // date string matching /^\d{1,2}\/\d{1,2}\/\d{2}|\d{4}$/
  243. // or four digit year
  244. startdate : today.getFullYear(),
  245. enddate : today.getFullYear() + 1,
  246. // offset from the top left corner of the input element
  247. x : 1, // must be in px
  248. y : 18 // must be in px
  249. };
  250. })(jQuery);
  251. // Init the form
  252. $(document).ready(function(){
  253. $('#date_first').simpleDatepicker({startdate: 2005, enddate: 2100});
  254. $('#date_second').simpleDatepicker({startdate: 2005, enddate: 2100});
  255. $('#date_filter').change(function(){
  256. var show = $(this).val() == 'between' ? 'inline' : 'none';
  257. $('#date_second').css('display', show);
  258. $('#date_and').css('display', show);
  259. });
  260. });