jquery.calendario.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /**
  2. * jquery.calendario.js v1.0.0
  3. * http://www.codrops.com
  4. *
  5. * Licensed under the MIT license.
  6. * http://www.opensource.org/licenses/mit-license.php
  7. *
  8. * Copyright 2012, Codrops
  9. * http://www.codrops.com
  10. */
  11. ;( function( $, window, undefined ) {
  12. 'use strict';
  13. $.Calendario = function( options, element ) {
  14. this.$el = $( element );
  15. this._init( options );
  16. };
  17. // the options
  18. $.Calendario.defaults = {
  19. /*
  20. you can also pass:
  21. month : initialize calendar with this month (1-12). Default is today.
  22. year : initialize calendar with this year. Default is today.
  23. caldata : initial data/content for the calendar.
  24. caldata format:
  25. {
  26. 'MM-DD-YYYY' : 'HTML Content',
  27. 'MM-DD-YYYY' : 'HTML Content',
  28. 'MM-DD-YYYY' : 'HTML Content'
  29. ...
  30. }
  31. */
  32. weeks : [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ],
  33. weekabbrs : [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ],
  34. months : [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
  35. monthabbrs : [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ],
  36. // choose between values in options.weeks or options.weekabbrs
  37. displayWeekAbbr : false,
  38. // choose between values in options.months or options.monthabbrs
  39. displayMonthAbbr : false,
  40. // left most day in the calendar
  41. // 0 - Sunday, 1 - Monday, ... , 6 - Saturday
  42. startIn : 1,
  43. onDayClick : function( $el, $content, dateProperties ) { return false; }
  44. };
  45. $.Calendario.prototype = {
  46. _init : function( options ) {
  47. // options
  48. this.options = $.extend( true, {}, $.Calendario.defaults, options );
  49. this.today = new Date();
  50. this.month = ( isNaN( this.options.month ) || this.options.month == null) ? this.today.getMonth() : this.options.month - 1;
  51. this.year = ( isNaN( this.options.year ) || this.options.year == null) ? this.today.getFullYear() : this.options.year;
  52. this.caldata = this.options.caldata || {};
  53. this._generateTemplate();
  54. this._initEvents();
  55. },
  56. _initEvents : function() {
  57. var self = this;
  58. this.$el.on( 'click.calendario', 'div.fc-row > div', function() {
  59. var $cell = $( this ),
  60. idx = $cell.index(),
  61. $content = $cell.children( 'div' ),
  62. dateProp = {
  63. day : $cell.children( 'span.fc-date' ).text(),
  64. month : self.month + 1,
  65. monthname : self.options.displayMonthAbbr ? self.options.monthabbrs[ self.month ] : self.options.months[ self.month ],
  66. year : self.year,
  67. weekday : idx + self.options.startIn,
  68. weekdayname : self.options.weeks[ idx + self.options.startIn ]
  69. };
  70. if( dateProp.day ) {
  71. self.options.onDayClick( $cell, $content, dateProp );
  72. }
  73. } );
  74. },
  75. // Calendar logic based on http://jszen.blogspot.pt/2007/03/how-to-build-simple-calendar-with.html
  76. _generateTemplate : function( callback ) {
  77. var head = this._getHead(),
  78. body = this._getBody(),
  79. rowClass;
  80. switch( this.rowTotal ) {
  81. case 4 : rowClass = 'fc-four-rows'; break;
  82. case 5 : rowClass = 'fc-five-rows'; break;
  83. case 6 : rowClass = 'fc-six-rows'; break;
  84. }
  85. this.$cal = $( '<div class="fc-calendar ' + rowClass + '">' ).append( head, body );
  86. this.$el.find( 'div.fc-calendar' ).remove().end().append( this.$cal );
  87. if( callback ) { callback.call(); }
  88. },
  89. _getHead : function() {
  90. var html = '<div class="fc-head">';
  91. for ( var i = 0; i <= 6; i++ ) {
  92. var pos = i + this.options.startIn,
  93. j = pos > 6 ? pos - 6 - 1 : pos;
  94. html += '<div>';
  95. html += this.options.displayWeekAbbr ? this.options.weekabbrs[ j ] : this.options.weeks[ j ];
  96. html += '</div>';
  97. }
  98. html += '</div>';
  99. return html;
  100. },
  101. _getBody : function() {
  102. var d = new Date( this.year, this.month + 1, 0 ),
  103. // number of days in the month
  104. monthLength = d.getDate(),
  105. firstDay = new Date( this.year, this.month, 1 );
  106. // day of the week
  107. this.startingDay = firstDay.getDay();
  108. var html = '<div class="fc-body"><div class="fc-row">',
  109. // fill in the days
  110. day = 1;
  111. // this loop is for weeks (rows)
  112. for ( var i = 0; i < 7; i++ ) {
  113. // this loop is for weekdays (cells)
  114. for ( var j = 0; j <= 6; j++ ) {
  115. var pos = this.startingDay - this.options.startIn,
  116. p = pos < 0 ? 6 + pos + 1 : pos,
  117. inner = '',
  118. today = this.month === this.today.getMonth() && this.year === this.today.getFullYear() && day === this.today.getDate(),
  119. content = '';
  120. if ( day <= monthLength && ( i > 0 || j >= p ) ) {
  121. inner += '<span class="fc-date">' + day + '</span><span class="fc-weekday">' + this.options.weekabbrs[ j + this.options.startIn > 6 ? j + this.options.startIn - 6 - 1 : j + this.options.startIn ] + '</span>';
  122. // this day is:
  123. var strdate = ( this.month + 1 < 10 ? '0' + ( this.month + 1 ) : this.month + 1 ) + '-' + ( day < 10 ? '0' + day : day ) + '-' + this.year,
  124. dayData = this.caldata[ strdate ];
  125. if( dayData ) {
  126. content = dayData;
  127. }
  128. if( content !== '' ) {
  129. inner += '<div>' + content + '</div>';
  130. }
  131. ++day;
  132. }
  133. else {
  134. today = false;
  135. }
  136. var cellClasses = today ? 'fc-today ' : '';
  137. if( content !== '' ) {
  138. cellClasses += 'fc-content';
  139. }
  140. html += cellClasses !== '' ? '<div class="' + cellClasses + '">' : '<div>';
  141. html += inner;
  142. html += '</div>';
  143. }
  144. // stop making rows if we've run out of days
  145. if (day > monthLength) {
  146. this.rowTotal = i + 1;
  147. break;
  148. }
  149. else {
  150. html += '</div><div class="fc-row">';
  151. }
  152. }
  153. html += '</div></div>';
  154. return html;
  155. },
  156. // based on http://stackoverflow.com/a/8390325/989439
  157. _isValidDate : function( date ) {
  158. date = date.replace(/-/gi,'');
  159. var month = parseInt( date.substring( 0, 2 ), 10 ),
  160. day = parseInt( date.substring( 2, 4 ), 10 ),
  161. year = parseInt( date.substring( 4, 8 ), 10 );
  162. if( ( month < 1 ) || ( month > 12 ) ) {
  163. return false;
  164. }
  165. else if( ( day < 1 ) || ( day > 31 ) ) {
  166. return false;
  167. }
  168. else if( ( ( month == 4 ) || ( month == 6 ) || ( month == 9 ) || ( month == 11 ) ) && ( day > 30 ) ) {
  169. return false;
  170. }
  171. else if( ( month == 2 ) && ( ( ( year % 400 ) == 0) || ( ( year % 4 ) == 0 ) ) && ( ( year % 100 ) != 0 ) && ( day > 29 ) ) {
  172. return false;
  173. }
  174. else if( ( month == 2 ) && ( ( year % 100 ) == 0 ) && ( day > 29 ) ) {
  175. return false;
  176. }
  177. return {
  178. day : day,
  179. month : month,
  180. year : year
  181. };
  182. },
  183. _move : function( period, dir, callback ) {
  184. if( dir === 'previous' ) {
  185. if( period === 'month' ) {
  186. this.year = this.month > 0 ? this.year : --this.year;
  187. this.month = this.month > 0 ? --this.month : 11;
  188. }
  189. else if( period === 'year' ) {
  190. this.year = --this.year;
  191. }
  192. }
  193. else if( dir === 'next' ) {
  194. if( period === 'month' ) {
  195. this.year = this.month < 11 ? this.year : ++this.year;
  196. this.month = this.month < 11 ? ++this.month : 0;
  197. }
  198. else if( period === 'year' ) {
  199. this.year = ++this.year;
  200. }
  201. }
  202. this._generateTemplate( callback );
  203. },
  204. /*************************
  205. ******PUBLIC METHODS *****
  206. **************************/
  207. getYear : function() {
  208. return this.year;
  209. },
  210. getMonth : function() {
  211. return this.month + 1;
  212. },
  213. getMonthName : function() {
  214. return this.options.displayMonthAbbr ? this.options.monthabbrs[ this.month ] : this.options.months[ this.month ];
  215. },
  216. // gets the cell's content div associated to a day of the current displayed month
  217. // day : 1 - [28||29||30||31]
  218. getCell : function( day ) {
  219. var row = Math.floor( ( day + this.startingDay - this.options.startIn ) / 7 ),
  220. pos = day + this.startingDay - this.options.startIn - ( row * 7 ) - 1;
  221. return this.$cal.find( 'div.fc-body' ).children( 'div.fc-row' ).eq( row ).children( 'div' ).eq( pos ).children( 'div' );
  222. },
  223. setData : function( caldata ) {
  224. caldata = caldata || {};
  225. $.extend( this.caldata, caldata );
  226. this._generateTemplate();
  227. },
  228. // goes to today's month/year
  229. gotoNow : function( callback ) {
  230. this.month = this.today.getMonth();
  231. this.year = this.today.getFullYear();
  232. this._generateTemplate( callback );
  233. },
  234. // goes to month/year
  235. goto : function( month, year, callback ) {
  236. this.month = month;
  237. this.year = year;
  238. this._generateTemplate( callback );
  239. },
  240. gotoPreviousMonth : function( callback ) {
  241. this._move( 'month', 'previous', callback );
  242. },
  243. gotoPreviousYear : function( callback ) {
  244. this._move( 'year', 'previous', callback );
  245. },
  246. gotoNextMonth : function( callback ) {
  247. this._move( 'month', 'next', callback );
  248. },
  249. gotoNextYear : function( callback ) {
  250. this._move( 'year', 'next', callback );
  251. }
  252. };
  253. var logError = function( message ) {
  254. if ( window.console ) {
  255. window.console.error( message );
  256. }
  257. };
  258. $.fn.calendario = function( options ) {
  259. var instance = $.data( this, 'calendario' );
  260. if ( typeof options === 'string' ) {
  261. var args = Array.prototype.slice.call( arguments, 1 );
  262. this.each(function() {
  263. if ( !instance ) {
  264. logError( "cannot call methods on calendario prior to initialization; " +
  265. "attempted to call method '" + options + "'" );
  266. return;
  267. }
  268. if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
  269. logError( "no such method '" + options + "' for calendario instance" );
  270. return;
  271. }
  272. instance[ options ].apply( instance, args );
  273. });
  274. }
  275. else {
  276. this.each(function() {
  277. if ( instance ) {
  278. instance._init();
  279. }
  280. else {
  281. instance = $.data( this, 'calendario', new $.Calendario( options, this ) );
  282. }
  283. });
  284. }
  285. return instance;
  286. };
  287. } )( jQuery, window );