2 * MultiDatesPicker v1.6.1
3 * http://multidatespickr.sourceforge.net/
5 * Copyright 2011, Luca Lauretta
6 * Dual licensed under the MIT or GPL version 2 licenses.
9 $.extend($.ui
, { multiDatesPicker
: { version
: "1.6.1" } });
11 $.fn
.multiDatesPicker = function(method
) {
12 var mdp_arguments
= arguments
;
14 var today_date
= new Date();
15 var day_zero
= new Date(0);
18 function removeDate(date
, type
) {
19 if(!type
) type
= 'picked';
20 date
= dateConvert
.call(this, date
);
21 for(var i
in this.multiDatesPicker
.dates
[type
])
22 if(!methods
.compareDates(this.multiDatesPicker
.dates
[type
][i
], date
))
23 return this.multiDatesPicker
.dates
[type
].splice(i
, 1).pop();
25 function removeIndex(index
, type
) {
26 if(!type
) type
= 'picked';
27 return this.multiDatesPicker
.dates
[type
].splice(index
, 1).pop();
29 function addDate(date
, type
, no_sort
) {
30 if(!type
) type
= 'picked';
31 date
= dateConvert
.call(this, date
);
33 // @todo: use jQuery UI datepicker method instead
37 date
.setMilliseconds(0);
39 if (methods
.gotDate
.call(this, date
, type
) === false) {
40 this.multiDatesPicker
.dates
[type
].push(date
);
41 if(!no_sort
) this.multiDatesPicker
.dates
[type
].sort(methods
.compareDates
);
44 function sortDates(type
) {
45 if(!type
) type
= 'picked';
46 this.multiDatesPicker
.dates
[type
].sort(methods
.compareDates
);
48 function dateConvert(date
, desired_type
, date_format
) {
49 if(!desired_type
) desired_type
= 'object';/*
50 if(!date_format && (typeof date == 'string')) {
51 date_format = $(this).datepicker('option', 'dateFormat');
52 if(!date_format) date_format = $.datepicker._defaults.dateFormat;
55 return methods
.dateConvert
.call(this, date
, desired_type
, date_format
);
59 init : function( options
) {
61 this.multiDatesPicker
.changed
= false;
64 beforeShow: function(input
, inst
) {
65 this.multiDatesPicker
.changed
= false;
66 if(this.multiDatesPicker
.originalBeforeShow
)
67 this.multiDatesPicker
.originalBeforeShow
.call(this, input
, inst
);
69 onSelect : function(dateText
, inst
) {
71 this.multiDatesPicker
.changed
= true;
74 $this.multiDatesPicker('toggleDate', dateText
);
77 if (this.multiDatesPicker
.mode
== 'normal' && this.multiDatesPicker
.dates
.picked
.length
> 0 && this.multiDatesPicker
.pickableRange
) {
78 var min_date
= this.multiDatesPicker
.dates
.picked
[0],
79 max_date
= new Date(min_date
.getTime());
81 methods
.sumDays(max_date
, this.multiDatesPicker
.pickableRange
-1);
83 // counts the number of disabled dates in the range
84 if(this.multiDatesPicker
.adjustRangeToDisabled
) {
86 disabled
= this.multiDatesPicker
.dates
.disabled
.slice(0);
89 for(var i
= 0; i
< disabled
.length
; i
++) {
90 if(disabled
[i
].getTime() <= max_date
.getTime()) {
91 if((min_date
.getTime() <= disabled
[i
].getTime()) && (disabled
[i
].getTime() <= max_date
.getTime()) ) {
94 disabled
.splice(i
, 1);
98 max_date
.setDate(max_date
.getDate() + c_disabled
);
99 } while(c_disabled
!= 0);
102 if(this.multiDatesPicker
.maxDate
&& (max_date
> this.multiDatesPicker
.maxDate
))
103 max_date
= this.multiDatesPicker
.maxDate
;
106 .datepicker("option", "minDate", min_date
)
107 .datepicker("option", "maxDate", max_date
);
110 .datepicker("option", "minDate", this.multiDatesPicker
.minDate
)
111 .datepicker("option", "maxDate", this.multiDatesPicker
.maxDate
);
114 if(this.tagName
== 'INPUT') { // for inputs
116 $this.multiDatesPicker('getDates', 'string')
120 if(this.multiDatesPicker
.originalOnSelect
&& dateText
)
121 this.multiDatesPicker
.originalOnSelect
.call(this, dateText
, inst
);
123 // thanks to bibendus83 -> http://sourceforge.net/tracker/?func=detail&atid=1495384&aid=3403159&group_id=358205
124 if ($this.datepicker('option', 'altField') != undefined && $this.datepicker('option', 'altField') != "") {
125 $($this.datepicker('option', 'altField')).val(
126 $this.multiDatesPicker('getDates', 'string')
130 beforeShowDay : function(date
) {
132 gotThisDate
= $this.multiDatesPicker('gotDate', date
) !== false,
133 isDisabledCalendar
= $this.datepicker('option', 'disabled'),
134 isDisabledDate
= $this.multiDatesPicker('gotDate', date
, 'disabled') !== false,
135 areAllSelected
= this.multiDatesPicker
.maxPicks
== this.multiDatesPicker
.dates
.picked
.length
;
137 var custom
= [true, ''];
138 if(this.multiDatesPicker
.originalBeforeShowDay
)
139 custom
= this.multiDatesPicker
.originalBeforeShowDay
.call(this, date
);
141 var highlight_class
= gotThisDate
? 'ui-state-highlight' : custom
[1];
142 var highlight_class
= (gotThisDate
? 'ui-state-highlight' : '') + ((custom
[1] && gotThisDate
) ? ' ' : '') + custom
[1];
143 var selectable_date
= !(isDisabledCalendar
|| isDisabledDate
|| (areAllSelected
&& !highlight_class
));
144 custom
[0] = selectable_date
&& custom
[0];
145 custom
[1] = highlight_class
;
148 onClose: function(dateText
, inst
) {
149 if(this.tagName
== 'INPUT' && this.multiDatesPicker
.changed
) {
150 $(inst
.dpDiv
[0]).stop(false,true);
151 setTimeout('$("#'+inst
.id
+'").datepicker("show")',50);
153 if(this.multiDatesPicker
.originalOnClose
) this.multiDatesPicker
.originalOnClose
.call(this, dateText
, inst
);
158 this.multiDatesPicker
.originalBeforeShow
= options
.beforeShow
;
159 this.multiDatesPicker
.originalOnSelect
= options
.onSelect
;
160 this.multiDatesPicker
.originalBeforeShowDay
= options
.beforeShowDay
;
161 this.multiDatesPicker
.originalOnClose
= options
.onClose
;
163 $this.datepicker(options
);
165 this.multiDatesPicker
.minDate
= $.datepicker
._determineDate(this, options
.minDate
, null);
166 this.multiDatesPicker
.maxDate
= $.datepicker
._determineDate(this, options
.maxDate
, null);
168 if(options
.addDates
) methods
.addDates
.call(this, options
.addDates
);
169 if(options
.addDisabledDates
)
170 methods
.addDates
.call(this, options
.addDisabledDates
, 'disabled');
172 methods
.setMode
.call(this, options
);
177 $this.datepicker('option', mdp_events
);
179 if(this.tagName
== 'INPUT') $this.val($this.multiDatesPicker('getDates', 'string'));
181 // Fixes the altField filled with defaultDate by default
182 var altFieldOption
= $this.datepicker('option', 'altField');
183 if (altFieldOption
) $(altFieldOption
).val($this.multiDatesPicker('getDates', 'string'));
185 compareDates : function(date1
, date2
) {
186 date1
= dateConvert
.call(this, date1
);
187 date2
= dateConvert
.call(this, date2
);
188 // return > 0 means date1 is later than date2
189 // return == 0 means date1 is the same day as date2
190 // return < 0 means date1 is earlier than date2
191 var diff
= date1
.getFullYear() - date2
.getFullYear();
193 diff
= date1
.getMonth() - date2
.getMonth();
195 diff
= date1
.getDate() - date2
.getDate();
199 sumDays : function( date
, n_days
) {
200 var origDateType
= typeof date
;
201 obj_date
= dateConvert
.call(this, date
);
202 obj_date
.setDate(obj_date
.getDate() + n_days
);
203 return dateConvert
.call(this, obj_date
, origDateType
);
205 dateConvert : function( date
, desired_format
, dateFormat
) {
206 var from_format
= typeof date
;
208 if(from_format
== desired_format
) {
209 if(from_format
== 'object') {
213 $.error('Received date is in a non supported format!');
221 if(typeof date
== 'undefined') date
= new Date(0);
223 if(desired_format
!= 'string' && desired_format
!= 'object' && desired_format
!= 'number')
224 $.error('Date format "'+ desired_format
+'" not supported!');
227 dateFormat
= $.datepicker
._defaults
.dateFormat
;
229 // thanks to bibendus83 -> http://sourceforge.net/tracker/index.php?func=detail&aid=3213174&group_id=358205&atid=1495382
230 var dp_dateFormat
= $this.datepicker('option', 'dateFormat');
232 dateFormat
= dp_dateFormat
;
236 // converts to object as a neutral format
237 switch(from_format
) {
238 case 'object': break;
239 case 'string': date
= $.datepicker
.parseDate(dateFormat
, date
); break;
240 case 'number': date
= new Date(date
); break;
241 default: $.error('Conversion from "'+ desired_format
+'" format not allowed on jQuery.multiDatesPicker');
243 // then converts to the desired format
244 switch(desired_format
) {
245 case 'object': return date
;
246 case 'string': return $.datepicker
.formatDate(dateFormat
, date
);
247 case 'number': return date
.getTime();
248 default: $.error('Conversion to "'+ desired_format
+'" format not allowed on jQuery.multiDatesPicker');
252 gotDate : function( date
, type
) {
253 if(!type
) type
= 'picked';
254 for(var i
= 0; i
< this.multiDatesPicker
.dates
[type
].length
; i
++) {
255 if(methods
.compareDates
.call(this, this.multiDatesPicker
.dates
[type
][i
], date
) === 0) {
261 getDates : function( format
, type
) {
262 if(!format
) format
= 'string';
263 if(!type
) type
= 'picked';
266 return this.multiDatesPicker
.dates
[type
];
269 var o_dates
= new Array();
270 for(var i
in this.multiDatesPicker
.dates
[type
])
274 this.multiDatesPicker
.dates
[type
][i
],
280 default: $.error('Format "'+format
+'" not supported!');
283 addDates : function( dates
, type
) {
284 if(dates
.length
> 0) {
285 if(!type
) type
= 'picked';
286 switch(typeof dates
) {
291 if (typeof dates
[i
] != "function")
292 addDate
.call(this, dates
[i
], type
, true);
293 sortDates
.call(this, type
);
295 } // else does the same as 'string'
298 addDate
.call(this, dates
, type
);
301 $.error('Date format "'+ typeof dates
+'" not allowed on jQuery.multiDatesPicker');
303 $(this).datepicker('refresh');
305 $.error('Empty array of dates received.');
308 removeDates : function( dates
, type
) {
309 if(!type
) type
= 'picked';
311 if (Object
.prototype.toString
.call(dates
) === '[object Array]') {
312 for(var i
in dates
.sort(function(a
,b
){return b
-a
})) {
313 removed
.push(removeDate
.call(this, dates
[i
], type
));
316 removed
.push(removeDate
.call(this, dates
, type
));
318 $(this).datepicker('refresh');
321 removeIndexes : function( indexes
, type
) {
322 if(!type
) type
= 'picked';
324 if (Object
.prototype.toString
.call(indexes
) === '[object Array]') {
325 for(var i
in indexes
.sort(function(a
,b
){return b
-a
})) {
326 removed
.push(removeIndex
.call(this, indexes
[i
], type
));
329 removed
.push(removeIndex
.call(this, indexes
, type
));
331 $(this).datepicker('refresh');
334 resetDates : function ( type
) {
335 if(!type
) type
= 'picked';
336 this.multiDatesPicker
.dates
[type
] = [];
337 $(this).datepicker('refresh');
339 toggleDate : function( date
, type
) {
340 if(!type
) type
= 'picked';
342 switch(this.multiDatesPicker
.mode
) {
344 this.multiDatesPicker
.dates
[type
] = []; // deletes all picked/disabled dates
345 var end
= this.multiDatesPicker
.autoselectRange
[1];
346 var begin
= this.multiDatesPicker
.autoselectRange
[0];
347 if(end
< begin
) { // switch
348 end
= this.multiDatesPicker
.autoselectRange
[0];
349 begin
= this.multiDatesPicker
.autoselectRange
[1];
351 for(var i
= begin
; i
< end
; i
++)
352 methods
.addDates
.call(this, methods
.sumDays(date
, i
), type
);
355 if(methods
.gotDate
.call(this, date
) === false) // adds dates
356 methods
.addDates
.call(this, date
, type
);
357 else // removes dates
358 methods
.removeDates
.call(this, date
, type
);
362 setMode : function( options
) {
364 if(options
.mode
) this.multiDatesPicker
.mode
= options
.mode
;
366 switch(this.multiDatesPicker
.mode
) {
368 for(option
in options
)
372 case 'pickableRange':
373 case 'adjustRangeToDisabled':
374 this.multiDatesPicker
[option
] = options
[option
];
376 //default: $.error('Option ' + option + ' ignored for mode "'.options.mode.'".');
382 for(option
in options
)
384 case 'autoselectRange':
386 case 'pickableRange':
387 case 'adjustRangeToDisabled':
388 this.multiDatesPicker
[option
] = options
[option
];
390 //default: $.error('Option ' + option + ' does not exist for setMode on jQuery.multiDatesPicker');
392 if(mandatory
> 0) $.error('Some mandatory options not specified!');
397 if(options.pickableRange) {
398 $this.datepicker("option", "maxDate", options.pickableRange);
399 $this.datepicker("option", "minDate", this.multiDatesPicker.minDate);
403 if(mdp_events
.onSelect
)
404 mdp_events
.onSelect();
405 $this.datepicker('refresh');
409 this.each(function() {
410 if (!this.multiDatesPicker
) {
411 this.multiDatesPicker
= {
417 adjustRangeToDisabled
: true
421 if(methods
[method
]) {
422 var exec_result
= methods
[method
].apply(this, Array
.prototype.slice
.call(mdp_arguments
, 1));
433 } else if( typeof method
=== 'object' || ! method
) {
434 return methods
.init
.apply(this, mdp_arguments
);
436 $.error('Method ' + method
+ ' does not exist on jQuery.multiDatesPicker');
441 if(method
!= 'gotDate' && method
!= 'getDates') {
448 var PROP_NAME
= 'multiDatesPicker';
449 var dpuuid
= new Date().getTime();
452 $.multiDatesPicker
= {version
: false};
453 //$.multiDatesPicker = new MultiDatesPicker(); // singleton instance
454 $.multiDatesPicker
.initialized
= false;
455 $.multiDatesPicker
.uuid
= new Date().getTime();
456 $.multiDatesPicker
.version
= $.ui
.multiDatesPicker
.version
;
458 // Workaround for #4055
459 // Add another global to avoid noConflict issues with inline event handlers
460 window
['DP_jQuery_' + dpuuid
] = $;