Project

General

Profile

Statistics
| Branch: | Revision:

colonymech / docs / www / colonyscout / internal / jeditable / js / jquery.datePicker.js @ f59acf11

History | View | Annotate | Download (33.4 KB)

1
/**
2
 * Copyright (c) 2007 Kelvin Luck (http://www.kelvinluck.com/)
3
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
4
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
5
 *
6
 * $Id: jquery.datePicker.js 2036 2007-06-05 22:55:15Z kelvin.luck $
7
 **/
8

    
9
(function($){
10
    
11
        $.fn.extend({
12
/**
13
 * Render a calendar table into any matched elements.
14
 * 
15
 * @param Object s (optional) Customize your calendars.
16
 * @option Number month The month to render (NOTE that months are zero based). Default is today's month.
17
 * @option Number year The year to render. Default is today's year.
18
 * @option Function renderCallback A reference to a function that is called as each cell is rendered and which can add classes and event listeners to the created nodes. Default is no callback.
19
 * @option Number showHeader Whether or not to show the header row, possible values are: $.dpConst.SHOW_HEADER_NONE (no header), $.dpConst.SHOW_HEADER_SHORT (first letter of each day) and $.dpConst.SHOW_HEADER_LONG (full name of each day). Default is $.dpConst.SHOW_HEADER_SHORT.
20
 * @option String hoverClass The class to attach to each cell when you hover over it (to allow you to use hover effects in IE6 which doesn't support the :hover pseudo-class on elements other than links). Default is dp-hover. Pass false if you don't want a hover class.
21
 * @type jQuery
22
 * @name renderCalendar
23
 * @cat plugins/datePicker
24
 * @author Kelvin Luck (http://www.kelvinluck.com/)
25
 *
26
 * @example $('#calendar-me').renderCalendar({month:0, year:2007});
27
 * @desc Renders a calendar displaying January 2007 into the element with an id of calendar-me.
28
 *
29
 * @example
30
 * var testCallback = function($td, thisDate, month, year)
31
 * {
32
 * if ($td.is('.current-month') && thisDate.getDay() == 4) {
33
 *                var d = thisDate.getDate();
34
 *                $td.bind(
35
 *                        'click',
36
 *                        function()
37
 *                        {
38
 *                                alert('You clicked on ' + d + '/' + (Number(month)+1) + '/' + year);
39
 *                        }
40
 *                ).addClass('thursday');
41
 *        } else if (thisDate.getDay() == 5) {
42
 *                $td.html('Friday the ' + $td.html() + 'th');
43
 *        }
44
 * }
45
 * $('#calendar-me').renderCalendar({month:0, year:2007, renderCallback:testCallback});
46
 * 
47
 * @desc Renders a calendar displaying January 2007 into the element with an id of calendar-me. Every Thursday in the current month has a class of "thursday" applied to it, is clickable and shows an alert when clicked. Every Friday on the calendar has the number inside replaced with text.
48
 **/
49
                renderCalendar  :   function(s)
50
                {
51
                        var dc = function(a)
52
                        {
53
                                return document.createElement(a);
54
                        };
55
                        
56
                        s = $.extend(
57
                                {
58
                                        month                        : null,
59
                                        year                        : null,
60
                                        renderCallback        : null,
61
                                        showHeader                : $.dpConst.SHOW_HEADER_SHORT,
62
                                        dpController        : null,
63
                                        hoverClass                : 'dp-hover'
64
                                }
65
                                , s
66
                        );
67
                        
68
                        if (s.showHeader != $.dpConst.SHOW_HEADER_NONE) {
69
                                var headRow = $(dc('tr'));
70
                                for (var i=Date.firstDayOfWeek; i<Date.firstDayOfWeek+7; i++) {
71
                                        var weekday = i%7;
72
                                        var day = Date.dayNames[weekday];
73
                                        headRow.append(
74
                                                jQuery(dc('th')).attr({'scope':'col', 'abbr':day, 'title':day, 'class':(weekday == 0 || weekday == 6 ? 'weekend' : 'weekday')}).html(s.showHeader == $.dpConst.SHOW_HEADER_SHORT ? day.substr(0, 1) : day)
75
                                        );
76
                                }
77
                        };
78
                        
79
                        var calendarTable = $(dc('table'))
80
                                                                        .attr(
81
                                                                                {
82
                                                                                        'cellspacing':2,
83
                                                                                        'className':'jCalendar'
84
                                                                                }
85
                                                                        )
86
                                                                        .append(
87
                                                                                (s.showHeader != $.dpConst.SHOW_HEADER_NONE ? 
88
                                                                                        $(dc('thead'))
89
                                                                                                .append(headRow)
90
                                                                                        :
91
                                                                                        dc('thead')
92
                                                                                )
93
                                                                        );
94
                        var tbody = $(dc('tbody'));
95
                        
96
                        var today = (new Date()).zeroTime();
97
                        
98
                        var month = s.month == undefined ? today.getMonth() : s.month;
99
                        var year = s.year || today.getFullYear();
100
                        
101
                        var currentDate = new Date(year, month, 1);
102
                        
103
                        
104
                        var firstDayOffset = Date.firstDayOfWeek - currentDate.getDay() + 1;
105
                        if (firstDayOffset > 1) firstDayOffset -= 7;
106
                        currentDate.addDays(firstDayOffset-1);
107
                        
108
                        var doHover = function()
109
                        {
110
                                if (s.hoverClass) {
111
                                        $(this).addClass(s.hoverClass);
112
                                }
113
                        };
114
                        var unHover = function()
115
                        {
116
                                if (s.hoverClass) {
117
                                        $(this).removeClass(s.hoverClass);
118
                                }
119
                        };
120
                        
121
                        var w = 0;
122
                        while (w++<6) {
123
                                var r = jQuery(dc('tr'));
124
                                for (var i=0; i<7; i++) {
125
                                        var thisMonth = currentDate.getMonth() == month;
126
                                        var d = $(dc('td'))
127
                                                                .text(currentDate.getDate() + '')
128
                                                                .attr('className', (thisMonth ? 'current-month ' : 'other-month ') +
129
                                                                                                        (currentDate.isWeekend() ? 'weekend ' : 'weekday ') +
130
                                                                                                        (thisMonth && currentDate.getTime() == today.getTime() ? 'today ' : '')
131
                                                                )
132
                                                                .hover(doHover, unHover)
133
                                                        ;
134
                                        if (s.renderCallback) {
135
                                                s.renderCallback(d, currentDate, month, year);
136
                                        }
137
                                        r.append(d);
138
                                        currentDate.addDays(1);
139
                                }
140
                                tbody.append(r);
141
                        }
142
                        calendarTable.append(tbody);
143
                        
144
                        return this.each(
145
                                function()
146
                                {
147
                                        $(this).empty().append(calendarTable);
148
                                }
149
                        );
150
                },
151
/**
152
 * Create a datePicker associated with each of the matched elements.
153
 *
154
 * The matched element will receive a few custom events with the following signatures:
155
 *
156
 * dateSelected(event, date, $td, status)
157
 * Triggered when a date is selected. event is a reference to the event, date is the Date selected, $td is a jquery object wrapped around the TD that was clicked on and status is whether the date was selected (true) or deselected (false)
158
 * 
159
 * dpClosed(event, selected)
160
 * Triggered when the date picker is closed. event is a reference to the event and selected is an Array containing Date objects.
161
 *
162
 * dpMonthChanged(event, displayedMonth, displayedYear)
163
 * Triggered when the month of the popped up calendar is changed. event is a reference to the event, displayedMonth is the number of the month now displayed (zero based) and displayedYear is the year of the month.
164
 *
165
 * dpDisplayed(event, $datePickerDiv)
166
 * Triggered when the date picker is created. $datePickerDiv is the div containing the date picker. Use this event to add custom content/ listeners to the popped up date picker.
167
 *
168
 * @param Object s (optional) Customize your date pickers.
169
 * @option Number month The month to render when the date picker is opened (NOTE that months are zero based). Default is today's month.
170
 * @option Number year The year to render when the date picker is opened. Default is today's year.
171
 * @option Date startDate The first date date can be selected.
172
 * @option Date endDate The last date that can be selected.
173
 * @option Boolean createButton Whether to create a .dp-choose-date anchor directly after the matched element which when clicked will trigger the showing of the date picker. Default is true.
174
 * @option Boolean showYearNavigation Whether to display buttons which allow the user to navigate through the months a year at a time. Default is true.
175
 * @option Boolean closeOnSelect Whether to close the date picker when a date is selected. Default is true.
176
 * @option Boolean displayClose Whether to create a "Close" button within the date picker popup. Default is false.
177
 * @option Boolean selectMultiple Whether a user should be able to select multiple dates with this date picker. Default is false.
178
 * @option Boolean clickInput If the matched element is an input type="text" and this option is true then clicking on the input will cause the date picker to appear.
179
 * @option Number verticalPosition The vertical alignment of the popped up date picker to the matched element. One of $.dpConst.POS_TOP and $.dpConst.POS_BOTTOM. Default is $.dpConst.POS_TOP.
180
 * @option Number horizontalPosition The horizontal alignment of the popped up date picker to the matched element. One of $.dpConst.POS_LEFT and $.dpConst.POS_RIGHT.
181
 * @option Number verticalOffset The number of pixels offset from the defined verticalPosition of this date picker that it should pop up in. Default in 0.
182
 * @option Number horizontalOffset The number of pixels offset from the defined horizontalPosition of this date picker that it should pop up in. Default in 0.
183
 * @option (Function|Array) renderCallback A reference to a function (or an array of seperate functions) that is called as each cell is rendered and which can add classes and event listeners to the created nodes. Each callback function will receive four arguments; a jquery object wrapping the created TD, a Date object containing the date this TD represents, a number giving the currently rendered month and a number giving the currently rendered year. Default is no callback.
184
 * @option String hoverClass The class to attach to each cell when you hover over it (to allow you to use hover effects in IE6 which doesn't support the :hover pseudo-class on elements other than links). Default is dp-hover. Pass false if you don't want a hover class.
185
 * @type jQuery
186
 * @name datePicker
187
 * @cat plugins/datePicker
188
 * @author Kelvin Luck (http://www.kelvinluck.com/)
189
 *
190
 * @example $('input.date-picker').datePicker();
191
 * @desc Creates a date picker button next to all matched input elements. When the button is clicked on the value of the selected date will be placed in the corresponding input (formatted according to Date.format).
192
 *
193
 * @example demo/index.html
194
 * @desc See the projects homepage for many more complex examples...
195
 **/
196
                datePicker : function(s)
197
                {                        
198
                        if (!$.event._dpCache) $.event._dpCache = [];
199
                        
200
                        // initialise the date picker controller with the relevant settings...
201
                        s = $.extend(
202
                                {
203
                                        month                                : undefined,
204
                                        year                                : undefined,
205
                                        startDate                        : undefined,
206
                                        endDate                                : undefined,
207
                                        renderCallback                : [],
208
                                        createButton                : true,
209
                                        showYearNavigation        : true,
210
                                        closeOnSelect                : true,
211
                                        displayClose                : false,
212
                                        selectMultiple                : false,
213
                                        clickInput                        : false,
214
                                        verticalPosition        : $.dpConst.POS_TOP,
215
                                        horizontalPosition        : $.dpConst.POS_LEFT,
216
                                        verticalOffset                : 0,
217
                                        horizontalOffset        : 0,
218
                                        hoverClass                        : 'dp-hover'
219
                                }
220
                                , s
221
                        );
222
                        
223
                        return this.each(
224
                                function()
225
                                {
226
                                        var $this = $(this);
227
                                        
228
                                        if (!this._dpId) {
229
                                                this._dpId = $.event.guid++;
230
                                                $.event._dpCache[this._dpId] = new DatePicker(this);
231
                                        }
232
                                        
233
                                        var controller = $.event._dpCache[this._dpId];
234
                                        
235
                                        controller.init(s);
236
                                        
237
                                        if (s.createButton) {
238
                                                // create it!
239
                                                controller.button = $('<a href="#" class="dp-choose-date" title="' + $.dpText.TEXT_CHOOSE_DATE + '">' + $.dpText.TEXT_CHOOSE_DATE + '</a>')
240
                                                                .bind(
241
                                                                        'click',
242
                                                                        function()
243
                                                                        {
244
                                                                                $this.dpDisplay(this);
245
                                                                                this.blur();
246
                                                                                return false;
247
                                                                        }
248
                                                                );
249
                                                $this.after(controller.button);
250
                                        }
251
                                        
252
                                        if ($this.is(':text')) {
253
                                                $this
254
                                                        .bind(
255
                                                                'dateSelected',
256
                                                                function(e, selectedDate, $td)
257
                                                                {
258
                                                                        this.value = selectedDate.asString();
259
                                                                }
260
                                                        ).bind(
261
                                                                'change',
262
                                                                function()
263
                                                                {
264
                                                                        var d = Date.fromString(this.value);
265
                                                                        if (d) {
266
                                                                                controller.setSelected(d, true, true);
267
                                                                        }
268
                                                                }
269
                                                        );
270
                                                if (s.clickInput) {
271
                                                        $this.bind(
272
                                                                'click',
273
                                                                function()
274
                                                                {
275
                                                                        $this.dpDisplay();
276
                                                                }
277
                                                        );
278
                                                }
279
                                        }
280
                                        
281
                                        $this.addClass('dp-applied');
282
                                        
283
                                }
284
                        )
285
                },
286
/**
287
 * Disables or enables this date picker
288
 *
289
 * @param Boolean s Whether to disable (true) or enable (false) this datePicker
290
 * @type jQuery
291
 * @name dpSetDisabled
292
 * @cat plugins/datePicker
293
 * @author Kelvin Luck (http://www.kelvinluck.com/)
294
 *
295
 * @example $('.date-picker').datePicker();
296
 * $('.date-picker').dpSetDisabled(true);
297
 * @desc Prevents this date picker from displaying and adds a class of dp-disabled to it (and it's associated button if it has one) for styling purposes. If the matched element is an input field then it will also set the disabled attribute to stop people directly editing the field.
298
 **/
299
                dpSetDisabled : function(s)
300
                {
301
                        return _w.call(this, 'setDisabled', s);
302
                },
303
/**
304
 * Updates the first selectable date for any date pickers on any matched elements.
305
 *
306
 * @param String d A string representing the first selectable date (formatted according to Date.format).
307
 * @type jQuery
308
 * @name dpSetStartDate
309
 * @cat plugins/datePicker
310
 * @author Kelvin Luck (http://www.kelvinluck.com/)
311
 *
312
 * @example $('.date-picker').datePicker();
313
 * $('.date-picker').dpSetStartDate('01/01/2000');
314
 * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the first selectable date for each of these to the first day of the millenium.
315
 **/
316
                dpSetStartDate : function(d)
317
                {
318
                        return _w.call(this, 'setStartDate', d);
319
                },
320
/**
321
 * Updates the last selectable date for any date pickers on any matched elements.
322
 *
323
 * @param String d A string representing the last selectable date (formatted according to Date.format).
324
 * @type jQuery
325
 * @name dpSetEndDate
326
 * @cat plugins/datePicker
327
 * @author Kelvin Luck (http://www.kelvinluck.com/)
328
 *
329
 * @example $('.date-picker').datePicker();
330
 * $('.date-picker').dpSetEndDate('01/01/2010');
331
 * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the last selectable date for each of these to the first Janurary 2010.
332
 **/
333
                dpSetEndDate : function(d)
334
                {
335
                        return _w.call(this, 'setEndDate', d);
336
                },
337
/**
338
 * Gets a list of Dates currently selected by this datePicker. This will be an empty array if no dates are currently selected or NULL if there is no datePicker associated with the matched element.
339
 *
340
 * @type Array
341
 * @name dpGetSelected
342
 * @cat plugins/datePicker
343
 * @author Kelvin Luck (http://www.kelvinluck.com/)
344
 *
345
 * @example $('.date-picker').datePicker();
346
 * alert($('.date-picker').dpGetSelected());
347
 * @desc Will alert an empty array (as nothing is selected yet)
348
 **/
349
                dpGetSelected : function()
350
                {
351
                        var c = _getController(this[0]);
352
                        if (c) {
353
                                return c.getSelected();
354
                        }
355
                        return null;
356
                },
357
/**
358
 * Selects or deselects a date on any matched element's date pickers. Deselcting is only useful on date pickers where selectMultiple==true. Selecting will only work if the passed date is within the startDate and endDate boundries for a given date picker.
359
 *
360
 * @param String d A string representing the date you want to select (formatted according to Date.format).
361
 * @param Boolean v Whether you want to select (true) or deselect (false) this date. Optional - default = true.
362
 * @param Boolean m Whether you want the date picker to open up on the month of this date when it is next opened. Optional - default = true.
363
 * @type jQuery
364
 * @name dpSetSelected
365
 * @cat plugins/datePicker
366
 * @author Kelvin Luck (http://www.kelvinluck.com/)
367
 *
368
 * @example $('.date-picker').datePicker();
369
 * $('.date-picker').dpSetSelected('01/01/2010');
370
 * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the selected date on these date pickers to the first Janurary 2010. When the date picker is next opened it will display Janurary 2010.
371
 **/
372
                dpSetSelected : function(d, v, m)
373
                {
374
                        if (v == undefined) v=true;
375
                        if (m == undefined) m=true;
376
                        return _w.call(this, 'setSelected', Date.fromString(d), v, m);
377
                },
378
/**
379
 * Sets the month that will be displayed when the date picker is next opened. If the passed month is before startDate then the month containing startDate will be displayed instead. If the passed month is after endDate then the month containing the endDate will be displayed instead.
380
 *
381
 * @param Number m The month you want the date picker to display. Optional - defaults to the currently displayed month.
382
 * @param Number y The year you want the date picker to display. Optional - defaults to the currently displayed year.
383
 * @type jQuery
384
 * @name dpSetDisplayedMonth
385
 * @cat plugins/datePicker
386
 * @author Kelvin Luck (http://www.kelvinluck.com/)
387
 *
388
 * @example $('.date-picker').datePicker();
389
 * $('.date-picker').dpSetDisplayedMonth(10, 2008);
390
 * @desc Creates a date picker associated with all elements with a class of "date-picker" then sets the selected date on these date pickers to the first Janurary 2010. When the date picker is next opened it will display Janurary 2010.
391
 **/
392
                dpSetDisplayedMonth : function(m, y)
393
                {
394
                        return _w.call(this, 'setDisplayedMonth', Number(m), Number(y));
395
                },
396
/**
397
 * Displays the date picker associated with the matched elements. Since only one date picker can be displayed at once then the date picker associated with the last matched element will be the one that is displayed.
398
 *
399
 * @param HTMLElement e An element that you want the date picker to pop up relative in position to. Optional - default behaviour is to pop up next to the element associated with this date picker.
400
 * @type jQuery
401
 * @name dpDisplay
402
 * @cat plugins/datePicker
403
 * @author Kelvin Luck (http://www.kelvinluck.com/)
404
 *
405
 * @example $('#date-picker').datePicker();
406
 * $('#date-picker').dpDisplay();
407
 * @desc Creates a date picker associated with the element with an id of date-picker and then causes it to pop up.
408
 **/
409
                dpDisplay : function(e)
410
                {
411
                        return _w.call(this, 'display', e);
412
                },
413
/**
414
 * Sets a function or array of functions that is called when each TD of the date picker popup is rendered to the page
415
 *
416
 * @param (Function|Array) a A function or an array of functions that are called when each td is rendered. Each function will receive four arguments; a jquery object wrapping the created TD, a Date object containing the date this TD represents, a number giving the currently rendered month and a number giving the currently rendered year.
417
 * @type jQuery
418
 * @name dpSetRenderCallback
419
 * @cat plugins/datePicker
420
 * @author Kelvin Luck (http://www.kelvinluck.com/)
421
 *
422
 * @example $('#date-picker').datePicker();
423
 * $('#date-picker').dpSetRenderCallback(function($td, thisDate, month, year)
424
 * {
425
 *         // do stuff as each td is rendered dependant on the date in the td and the displayed month and year
426
 * });
427
 * @desc Creates a date picker associated with the element with an id of date-picker and then creates a function which is called as each td is rendered when this date picker is displayed.
428
 **/
429
                dpSetRenderCallback : function(a)
430
                {
431
                        return _w.call(this, 'setRenderCallback', a);
432
                },
433
/**
434
 * Sets the position that the datePicker will pop up (relative to it's associated element)
435
 *
436
 * @param Number v The vertical alignment of the created date picker to it's associated element. Possible values are $.dpConst.POS_TOP and $.dpConst.POS_BOTTOM
437
 * @param Number h The horizontal alignment of the created date picker to it's associated element. Possible values are $.dpConst.POS_LEFT and $.dpConst.POS_RIGHT
438
 * @type jQuery
439
 * @name dpSetPosition
440
 * @cat plugins/datePicker
441
 * @author Kelvin Luck (http://www.kelvinluck.com/)
442
 *
443
 * @example $('#date-picker').datePicker();
444
 * $('#date-picker').dpSetPosition($.dpConst.POS_BOTTOM, $.dpConst.POS_RIGHT);
445
 * @desc Creates a date picker associated with the element with an id of date-picker and makes it so that when this date picker pops up it will be bottom and right aligned to the #date-picker element.
446
 **/
447
                dpSetPosition : function(v, h)
448
                {
449
                        return _w.call(this, 'setPosition', v, h);
450
                },
451
/**
452
 * Sets the offset that the popped up date picker will have from it's default position relative to it's associated element (as set by dpSetPosition)
453
 *
454
 * @param Number v The vertical offset of the created date picker.
455
 * @param Number h The horizontal offset of the created date picker.
456
 * @type jQuery
457
 * @name dpSetOffset
458
 * @cat plugins/datePicker
459
 * @author Kelvin Luck (http://www.kelvinluck.com/)
460
 *
461
 * @example $('#date-picker').datePicker();
462
 * $('#date-picker').dpSetOffset(-20, 200);
463
 * @desc Creates a date picker associated with the element with an id of date-picker and makes it so that when this date picker pops up it will be 20 pixels above and 200 pixels to the right of it's default position.
464
 **/
465
                dpSetOffset : function(v, h)
466
                {
467
                        return _w.call(this, 'setOffset', v, h);
468
                },
469
                // private function called on unload to clean up any expandos etc and prevent memory links...
470
                _dpDestroy : function()
471
                {
472
                        // TODO - implement this?
473
                }
474
        });
475
        
476
        // private internal function to cut down on the amount of code needed where we forward
477
        // dp* methods on the jQuery object on to the relevant DatePicker controllers...
478
        var _w = function(f, a1, a2, a3)
479
        {
480
                return this.each(
481
                        function()
482
                        {
483
                                var c = _getController(this);
484
                                if (c) {
485
                                        c[f](a1, a2, a3);
486
                                }
487
                        }
488
                );
489
        };
490
        
491
        function DatePicker(ele)
492
        {
493
                this.ele = ele;
494
                
495
                // initial values...
496
                this.displayedMonth                =        null;
497
                this.displayedYear                =        null;
498
                this.startDate                        =        null;
499
                this.endDate                        =        null;
500
                this.showYearNavigation        =        null;
501
                this.closeOnSelect                =        null;
502
                this.displayClose                =        null;
503
                this.selectMultiple                =        null;
504
                this.verticalPosition        =        null;
505
                this.horizontalPosition        =        null;
506
                this.verticalOffset                =        null;
507
                this.horizontalOffset        =        null;
508
                this.button                                =        null;
509
                this.renderCallback                =        [];
510
                this.selectedDates                =        {};
511
        };
512
        $.extend(
513
                DatePicker.prototype,
514
                {        
515
                        init : function(s)
516
                        {
517
                                this.setStartDate(s.startDate);
518
                                this.setEndDate(s.endDate);
519
                                this.setDisplayedMonth(Number(s.month), Number(s.year));
520
                                this.setRenderCallback(s.renderCallback);
521
                                this.showYearNavigation = s.showYearNavigation;
522
                                this.closeOnSelect = s.closeOnSelect;
523
                                this.displayClose = s.displayClose;
524
                                this.selectMultiple = s.selectMultiple;
525
                                this.verticalPosition = s.verticalPosition;
526
                                this.horizontalPosition = s.horizontalPosition;
527
                                this.hoverClass = s.hoverClass;
528
                                this.setOffset(s.verticalOffset, s.horizontalOffset);
529
                        },
530
                        setStartDate : function(d)
531
                        {
532
                                if (d) {
533
                                        this.startDate = Date.fromString(d);
534
                                }
535
                                if (!this.startDate) {
536
                                        this.startDate = (new Date()).zeroTime();
537
                                }
538
                                this.setDisplayedMonth(this.displayedMonth, this.displayedYear);
539
                        },
540
                        setEndDate : function(d)
541
                        {
542
                                if (d) {
543
                                        this.endDate = Date.fromString(d);
544
                                }
545
                                if (!this.endDate) {
546
                                        this.endDate = (new Date('12/31/2999')); // using the JS Date.parse function which expects mm/dd/yyyy
547
                                }
548
                                if (this.endDate.getTime() < this.startDate.getTime()) {
549
                                        this.endDate = this.startDate;
550
                                }
551
                                this.setDisplayedMonth(this.displayedMonth, this.displayedYear);
552
                        },
553
                        setPosition : function(v, h)
554
                        {
555
                                this.verticalPosition = v;
556
                                this.horizontalPosition = h;
557
                        },
558
                        setOffset : function(v, h)
559
                        {
560
                                this.verticalOffset = parseInt(v) || 0;
561
                                this.horizontalOffset = parseInt(h) || 0;
562
                        },
563
                        setDisabled : function(s)
564
                        {
565
                                $e = $(this.ele);
566
                                $e[s ? 'addClass' : 'removeClass']('dp-disabled');
567
                                if (this.button) {
568
                                        $but = $(this.button);
569
                                        $but[s ? 'addClass' : 'removeClass']('dp-disabled');
570
                                        $but.attr('title', s ? '' : $.dpText.TEXT_CHOOSE_DATE);
571
                                }
572
                                if ($e.is(':text')) {
573
                                        $e.attr('disabled', s ? 'disabled' : '');
574
                                }
575
                        },
576
                        setDisplayedMonth : function(m, y)
577
                        {
578
                                if (this.startDate == undefined || this.endDate == undefined) {
579
                                        return;
580
                                }
581
                                var s = new Date(this.startDate.getTime());
582
                                s.setDate(1);
583
                                var e = new Date(this.endDate.getTime());
584
                                e.setDate(1);
585
                                
586
                                var t;
587
                                
588
                                if (isNaN(m) && isNaN(y)) {
589
                                        // no month or year passed - default to current month
590
                                        t = new Date().zeroTime();
591
                                        t.setDate(1);
592
                                } else if (isNaN(m)) {
593
                                        // just year passed in - presume we want the displayedMonth
594
                                        t = new Date(y, this.displayedMonth, 1);
595
                                } else if (isNaN(y)) {
596
                                        // just month passed in - presume we want the displayedYear
597
                                        t = new Date(this.displayedYear, m, 1);
598
                                } else {
599
                                        // year and month passed in - that's the date we want!
600
                                        t = new Date(y, m, 1)
601
                                }
602
                                
603
                                // check if the desired date is within the range of our defined startDate and endDate
604
                                if (t.getTime() < s.getTime()) {
605
                                        t = s;
606
                                } else if (t.getTime() > e.getTime()) {
607
                                        t = e;
608
                                }
609
                                this.displayedMonth = t.getMonth();
610
                                this.displayedYear = t.getFullYear();
611
                        },
612
                        setSelected : function(d, v, moveToMonth)
613
                        {
614
                                if (this.selectMultiple == false) {
615
                                        this.selectedDates = {};
616
                                }
617
                                if (moveToMonth) {
618
                                        this.setDisplayedMonth(d.getMonth(), d.getFullYear());
619
                                }
620
                                this.selectedDates[d.getTime()] = v;
621
                        },
622
                        isSelected : function(t)
623
                        {
624
                                return this.selectedDates[t];
625
                        },
626
                        getSelected : function()
627
                        {
628
                                var r = [];
629
                                for(t in this.selectedDates) {
630
                                        if (this.selectedDates[t] == true) {
631
                                                r.push(new Date(Number(t)));
632
                                        }
633
                                }
634
                                return r;
635
                        },
636
                        display : function(eleAlignTo)
637
                        {
638
                                if ($(this.ele).is('.dp-disabled')) return;
639
                                
640
                                eleAlignTo = eleAlignTo || this.ele;
641
                                var c = this;
642
                                var $ele = $(eleAlignTo);
643
                                var eleOffset = $ele.offset();
644
                                
645
                                
646
                                var _checkMouse = function(e)
647
                                {
648
                                        var el = e.target;
649
                                        var cal = $('#dp-popup')[0];
650
                                        while (true){
651
                                                if (el == cal) {
652
                                                        return true;
653
                                                } else if (el == document) {
654
                                                        c._closeCalendar();
655
                                                        return false;
656
                                                } else {
657
                                                        el = $(el).parent()[0];
658
                                                }
659
                                        }
660
                                };
661
                                this._checkMouse = _checkMouse;
662
                                
663
                                this._closeCalendar(true);
664
                                
665
                                $('body')
666
                                        .append(
667
                                                $('<div></div>')
668
                                                        .attr('id', 'dp-popup')
669
                                                        .css(
670
                                                                {
671
                                                                        'top'        :        eleOffset.top + c.verticalOffset,
672
                                                                        'left'        :        eleOffset.left + c.horizontalOffset
673
                                                                }
674
                                                        )
675
                                                        .append(
676
                                                                $('<h2></h2>'),
677
                                                                $('<div id="dp-nav-prev"></div>')
678
                                                                        .append(
679
                                                                                $('<a id="dp-nav-prev-year" href="#" title="' + $.dpText.TEXT_PREV_YEAR + '">&lt;&lt;</a>')
680
                                                                                        .bind(
681
                                                                                                'click',
682
                                                                                                function()
683
                                                                                                {
684
                                                                                                        return c._displayNewMonth.call(c, this, 0, -1);
685
                                                                                                }
686
                                                                                        ),
687
                                                                                $('<a id="dp-nav-prev-month" href="#" title="' + $.dpText.TEXT_PREV_MONTH + '">&lt;</a>')
688
                                                                                        .bind(
689
                                                                                                'click',
690
                                                                                                function()
691
                                                                                                {
692
                                                                                                        return c._displayNewMonth.call(c, this, -1, 0);
693
                                                                                                }
694
                                                                                        )
695
                                                                        ),
696
                                                                $('<div id="dp-nav-next"></div>')
697
                                                                        .append(
698
                                                                                $('<a id="dp-nav-next-year" href="#" title="' + $.dpText.TEXT_NEXT_YEAR + '">&gt;&gt;</a>')
699
                                                                                        .bind(
700
                                                                                                'click',
701
                                                                                                function()
702
                                                                                                {
703
                                                                                                        return c._displayNewMonth.call(c, this, 0, 1);
704
                                                                                                }
705
                                                                                        ),
706
                                                                                $('<a id="dp-nav-next-month" href="#" title="' + $.dpText.TEXT_NEXT_MONTH + '">&gt;</a>')
707
                                                                                        .bind(
708
                                                                                                'click',
709
                                                                                                function()
710
                                                                                                {
711
                                                                                                        return c._displayNewMonth.call(c, this, 1, 0);
712
                                                                                                }
713
                                                                                        )
714
                                                                        ),
715
                                                                $('<div></div>')
716
                                                                        .attr('id', 'dp-calendar')
717
                                                        )
718
                                                        .bgIframe()
719
                                                );
720
                                        
721
                                var $pop = $('#dp-popup');
722
                                
723
                                if (this.showYearNavigation == false) {
724
                                        $('#dp-nav-prev-year, #dp-nav-next-year').css('display', 'none');
725
                                }
726
                                if (this.displayClose) {
727
                                        $pop.append(
728
                                                $('<a href="#" id="dp-close">' + $.dpText.TEXT_CLOSE + '</a>')
729
                                                        .bind(
730
                                                                'click',
731
                                                                function()
732
                                                                {
733
                                                                        c._closeCalendar();
734
                                                                        return false;
735
                                                                }
736
                                                        )
737
                                        );
738
                                }
739
                                c._renderCalendar();
740
                                
741
                                if (this.verticalPosition == $.dpConst.POS_BOTTOM) {
742
                                        $pop.css('top', eleOffset.top + $ele.height() - $pop.height() + c.verticalOffset);
743
                                }
744
                                if (this.horizontalPosition == $.dpConst.POS_RIGHT) {
745
                                        $pop.css('left', eleOffset.left + $ele.width() - $pop.width() + c.horizontalOffset);
746
                                }
747
                                
748
                                $(this.ele).trigger('dpDisplayed', $pop);
749
                                
750
                                $(document).bind('mousedown', this._checkMouse);
751
                        },
752
                        setRenderCallback : function(a)
753
                        {
754
                                if (a && typeof(a) == 'function') {
755
                                        a = [a];
756
                                }
757
                                this.renderCallback = this.renderCallback.concat(a);
758
                        },
759
                        cellRender : function ($td, thisDate, month, year) {
760
                                var c = this.dpController;
761
                                var d = new Date(thisDate.getTime());
762
                                
763
                                // add our click handlers to deal with it when the days are clicked...
764
                                
765
                                $td.bind(
766
                                        'click',
767
                                        function()
768
                                        {
769
                                                var $this = $(this);
770
                                                if (!$this.is('.disabled')) {
771
                                                        c.setSelected(d, !$this.is('.selected') || !c.selectMultiple);
772
                                                        var s = c.isSelected(d.getTime());
773
                                                        $(c.ele).trigger('dateSelected', [d, $td, s]);
774
                                                        if (c.closeOnSelect) {
775
                                                                c._closeCalendar();
776
                                                        } else {
777
                                                                $this[s ? 'addClass' : 'removeClass']('selected');
778
                                                        }
779
                                                }
780
                                        }
781
                                );
782
                                
783
                                if (c.isSelected(d.getTime())) {
784
                                        $td.addClass('selected');
785
                                }
786
                                
787
                                // call any extra renderCallbacks that were passed in
788
                                for (var i=0; i<c.renderCallback.length; i++) {
789
                                        c.renderCallback[i].apply(this, arguments);
790
                                }
791
                                
792
                                
793
                        },
794
                        // ele is the clicked button - only proceed if it doesn't have the class disabled...
795
                        // m and y are -1, 0 or 1 depending which direction we want to go in...
796
                        _displayNewMonth : function(ele, m, y) 
797
                        {
798
                                if (!$(ele).is('.disabled')) {
799
                                        this.setDisplayedMonth(this.displayedMonth + m, this.displayedYear + y);
800
                                        this._clearCalendar();
801
                                        this._renderCalendar();
802
                                        $(this.ele).trigger('dpMonthChanged', [this.displayedMonth, this.displayedYear]);
803
                                }
804
                                ele.blur();
805
                                return false;
806
                        },
807
                        _renderCalendar : function()
808
                        {
809
                                // set the title...
810
                                $('#dp-popup h2').html(Date.monthNames[this.displayedMonth] + ' ' + this.displayedYear);
811
                                
812
                                // render the calendar...
813
                                $('#dp-calendar').renderCalendar(
814
                                        {
815
                                                month                        : this.displayedMonth,
816
                                                year                        : this.displayedYear,
817
                                                renderCallback        : this.cellRender,
818
                                                dpController        : this,
819
                                                hoverClass                : this.hoverClass
820
                                        }
821
                                );
822
                                
823
                                // update the status of the control buttons and disable dates before startDate or after endDate...
824
                                // TODO: When should the year buttons be disabled? When you can't go forward a whole year from where you are or is that annoying?
825
                                if (this.displayedYear == this.startDate.getFullYear() && this.displayedMonth == this.startDate.getMonth()) {
826
                                        $('#dp-nav-prev-year').addClass('disabled');
827
                                        $('#dp-nav-prev-month').addClass('disabled');
828
                                        $('#dp-calendar td.other-month').each(
829
                                                function()
830
                                                {
831
                                                        var $this = $(this);
832
                                                        if (Number($this.text()) > 20) {
833
                                                                $this.addClass('disabled');
834
                                                        }
835
                                                }
836
                                        );
837
                                        var d = this.startDate.getDate();
838
                                        $('#dp-calendar td.current-month').each(
839
                                                function()
840
                                                {
841
                                                        var $this = $(this);
842
                                                        if (Number($this.text()) < d) {
843
                                                                $this.addClass('disabled');
844
                                                        }
845
                                                }
846
                                        );
847
                                } else {
848
                                        $('#dp-nav-prev-year').removeClass('disabled');
849
                                        $('#dp-nav-prev-month').removeClass('disabled');
850
                                        var d = this.startDate.getDate();
851
                                        if (d > 20) {
852
                                                // check if the startDate is last month as we might need to add some disabled classes...
853
                                                var sd = new Date(this.startDate.getTime());
854
                                                sd.addMonths(1);
855
                                                if (this.displayedYear == sd.getFullYear() && this.displayedMonth == sd.getMonth()) {
856
                                                        $('#dp-calendar td.other-month').each(
857
                                                                function()
858
                                                                {
859
                                                                        var $this = $(this);
860
                                                                        if (Number($this.text()) < d) {
861
                                                                                $this.addClass('disabled');
862
                                                                        }
863
                                                                }
864
                                                        );
865
                                                }
866
                                        }
867
                                }
868
                                if (this.displayedYear == this.endDate.getFullYear() && this.displayedMonth == this.endDate.getMonth()) {
869
                                        $('#dp-nav-next-year').addClass('disabled');
870
                                        $('#dp-nav-next-month').addClass('disabled');
871
                                        $('#dp-calendar td.other-month').each(
872
                                                function()
873
                                                {
874
                                                        var $this = $(this);
875
                                                        if (Number($this.text()) < 14) {
876
                                                                $this.addClass('disabled');
877
                                                        }
878
                                                }
879
                                        );
880
                                        var d = this.endDate.getDate();
881
                                        $('#dp-calendar td.current-month').each(
882
                                                function()
883
                                                {
884
                                                        var $this = $(this);
885
                                                        if (Number($this.text()) > d) {
886
                                                                $this.addClass('disabled');
887
                                                        }
888
                                                }
889
                                        );
890
                                } else {
891
                                        $('#dp-nav-next-year').removeClass('disabled');
892
                                        $('#dp-nav-next-month').removeClass('disabled');
893
                                        var d = this.endDate.getDate();
894
                                        if (d < 13) {
895
                                                // check if the endDate is next month as we might need to add some disabled classes...
896
                                                var ed = new Date(this.endDate.getTime());
897
                                                ed.addMonths(-1);
898
                                                if (this.displayedYear == ed.getFullYear() && this.displayedMonth == ed.getMonth()) {
899
                                                        $('#dp-calendar td.other-month').each(
900
                                                                function()
901
                                                                {
902
                                                                        var $this = $(this);
903
                                                                        if (Number($this.text()) > d) {
904
                                                                                $this.addClass('disabled');
905
                                                                        }
906
                                                                }
907
                                                        );
908
                                                }
909
                                        }
910
                                }
911
                        },
912
                        _closeCalendar : function(programatic)
913
                        {
914
                                $(document).unbind('mousedown', this._checkMouse);
915
                                this._clearCalendar();
916
                                $('#dp-popup a').unbind();
917
                                $('#dp-popup').empty().remove();
918
                                if (!programatic) {
919
                                        $(this.ele).trigger('dpClosed', [this.getSelected()]);
920
                                }
921
                        },
922
                        // empties the current dp-calendar div and makes sure that all events are unbound
923
                        // and expandos removed to avoid memory leaks...
924
                        _clearCalendar : function()
925
                        {
926
                                // TODO.
927
                                $('#dp-calendar td').unbind();
928
                                $('#dp-calendar').empty();
929
                        }
930
                }
931
        );
932
        
933
        // static constants
934
        $.dpConst = {
935
                SHOW_HEADER_NONE        :        0,
936
                SHOW_HEADER_SHORT        :        1,
937
                SHOW_HEADER_LONG        :        2,
938
                POS_TOP                                :        0,
939
                POS_BOTTOM                        :        1,
940
                POS_LEFT                        :        0,
941
                POS_RIGHT                        :        1
942
        };
943
        // localisable text
944
        $.dpText = {
945
                TEXT_PREV_YEAR                :        'Previous year',
946
                TEXT_PREV_MONTH                :        'Previous month',
947
                TEXT_NEXT_YEAR                :        'Next year',
948
                TEXT_NEXT_MONTH                :        'Next month',
949
                TEXT_CLOSE                        :        'Close',
950
                TEXT_CHOOSE_DATE        :        'Choose date'
951
        };
952
        // version
953
        $.dpVersion = '$Id: jquery.datePicker.js 2036 2007-06-05 22:55:15Z kelvin.luck $';
954

    
955
        function _getController(ele)
956
        {
957
                if (ele._dpId) return $.event._dpCache[ele._dpId];
958
                return false;
959
        };
960
        
961
        // make it so that no error is thrown if bgIframe plugin isn't included (allows you to use conditional
962
        // comments to only include bgIframe where it is needed in IE without breaking this plugin).
963
        if ($.fn.bgIframe == undefined) {
964
                $.fn.bgIframe = function() {return this; };
965
        };
966

    
967

    
968
        // clean-up
969
        $(window)
970
                .bind('unload', function() {
971
                        var els = $.event._dpCache || [];
972
                        for (var i in els) {
973
                                $(els[i].ele)._dpDestroy();
974
                        }
975
                });
976
                
977
        
978
})(jQuery);