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