zebra-datepicker-rails 0.0.2 → 1.8.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed19a461f13ccbbe0a83334d0c2bae01798bb7f6
4
- data.tar.gz: bd7aac2eb6b94e3ddeb89911bf57655837ce35cf
3
+ metadata.gz: 59788182ff6bd589f820e7a50c0332d8bb8bc0b3
4
+ data.tar.gz: 9a66e3fcfceac5c82301885d543d90839b0c990e
5
5
  SHA512:
6
- metadata.gz: e44d53d9cb9529a2036b4786bc0412942e919c4f6b271edda5a28305501ba19d82f2ce0c976332508a6f38aa0a1ab7ea60d764d47ec9e258b1a5c4fb337adf9e
7
- data.tar.gz: a9c93f0c98d5d1603393915bc691d3a364634bbfa155e5d479f78b96b86e7402225b83408995026917934ea78a28505a8942cfa097bee99cd33f612703d22b5d
6
+ metadata.gz: 7a78d8d34d3b3fab0536ae8fb1b0f008cea68925678bc4705c9dabd3b5b3a5a4db29e2bc21564607f2f99d7226e587278d9f707ca048751857f32b17b008b2f6
7
+ data.tar.gz: 5f86c45d3fdc51d1556ca6d95e04cab81800b4f92ccbc46761797938396f32853422e73a2f39f88a2b8082bf97eb414624de7e6da97c8b9a9b6ac5a05eebe922
@@ -1,5 +1,5 @@
1
1
  module ZebraDatepickerRails
2
2
  module Rails
3
- VERSION = "0.0.2"
3
+ VERSION = "1.8.7"
4
4
  end
5
5
  end
@@ -1,2878 +1 @@
1
- /**
2
- * Zebra_DatePicker
3
- *
4
- * Zebra_DatePicker is a small, compact and highly configurable date picker plugin for jQuery
5
- *
6
- * Visit {@link http://stefangabos.ro/jquery/zebra-datepicker/} for more information.
7
- *
8
- * For more resources visit {@link http://stefangabos.ro/}
9
- *
10
- * @author Stefan Gabos <contact@stefangabos.ro>
11
- * @version 1.8.4 (last revision: August 11, 2013)
12
- * @copyright (c) 2011 - 2013 Stefan Gabos
13
- * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LESSER GENERAL PUBLIC LICENSE
14
- * @package Zebra_DatePicker
15
- */
16
- ;(function($) {
17
-
18
- $.Zebra_DatePicker = function(element, options) {
19
-
20
- var defaults = {
21
-
22
- // setting this property to a jQuery element, will result in the date picker being always visible, the indicated
23
- // element being the date picker's container;
24
- always_visible: false,
25
-
26
- // days of the week; Sunday to Saturday
27
- days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
28
-
29
- // by default, the abbreviated name of a day consists of the first 2 letters from the day's full name;
30
- // while this is common for most languages, there are also exceptions for languages like Thai, Loa, Myanmar,
31
- // etc. where this is not correct; for these cases, specify an array with the abbreviations to be used for
32
- // the 7 days of the week; leave it FALSE to use the first 2 letters of a day's name as the abbreviation.
33
- //
34
- // default is FALSE
35
- days_abbr: false,
36
-
37
- // direction of the calendar
38
- //
39
- // a positive or negative integer: n (a positive integer) creates a future-only calendar beginning at n days
40
- // after today; -n (a negative integer); if n is 0, the calendar has no restrictions. use boolean true for
41
- // a future-only calendar starting with today and use boolean false for a past-only calendar ending today.
42
- //
43
- // you may also set this property to an array with two elements in the following combinations:
44
- //
45
- // - first item is boolean TRUE (calendar starts today), an integer > 0 (calendar starts n days after
46
- // today), or a valid date given in the format defined by the "format" attribute, using English for
47
- // month names (calendar starts at the specified date), and the second item is boolean FALSE (the calendar
48
- // has no ending date), an integer > 0 (calendar ends n days after the starting date), or a valid date
49
- // given in the format defined by the "format" attribute, using English for month names, and which occurs
50
- // after the starting date (calendar ends at the specified date)
51
- //
52
- // - first item is boolean FALSE (calendar ends today), an integer < 0 (calendar ends n days before today),
53
- // or a valid date given in the format defined by the "format" attribute, using English for month names
54
- // (calendar ends at the specified date), and the second item is an integer > 0 (calendar ends n days
55
- // before the ending date), or a valid date given in the format defined by the "format" attribute, using
56
- // English for month names and which occurs before the starting date (calendar starts at the specified
57
- // date)
58
- //
59
- // [1, 7] - calendar starts tomorrow and ends seven days after that
60
- // [true, 7] - calendar starts today and ends seven days after that
61
- // ['2013-01-01', false] - calendar starts on January 1st 2013 and has no ending date ("format" is YYYY-MM-DD)
62
- // [false, '2012-01-01'] - calendar ends today and starts on January 1st 2012 ("format" is YYYY-MM-DD)
63
- //
64
- // note that "disabled_dates" property will still apply!
65
- //
66
- // default is 0 (no restrictions)
67
- direction: 0,
68
-
69
- // an array of disabled dates in the following format: 'day month year weekday' where "weekday" is optional
70
- // and can be 0-6 (Saturday to Sunday); the syntax is similar to cron's syntax: the values are separated by
71
- // spaces and may contain * (asterisk) - (dash) and , (comma) delimiters:
72
- //
73
- // ['1 1 2012'] would disable January 1, 2012;
74
- // ['* 1 2012'] would disable all days in January 2012;
75
- // ['1-10 1 2012'] would disable January 1 through 10 in 2012;
76
- // ['1,10 1 2012'] would disable January 1 and 10 in 2012;
77
- // ['1-10,20,22,24 1-3 *'] would disable 1 through 10, plus the 22nd and 24th of January through March for every year;
78
- // ['* * * 0,6'] would disable all Saturdays and Sundays;
79
- // ['01 07 2012', '02 07 2012', '* 08 2012'] would disable 1st and 2nd of July 2012, and all of August of 2012
80
- //
81
- // default is FALSE, no disabled dates
82
- disabled_dates: false,
83
-
84
- // an array of enabled dates in the same format as required for "disabled_dates" property.
85
- // to be used together with the "disabled_dates" property by first setting the "disabled_dates" property to
86
- // something like "[* * * *]" (which will disable everything) and the setting the "enabled_dates" property to,
87
- // say, "[* * * 0,6]" to enable just weekends.
88
- enabled_dates: false,
89
-
90
- // week's starting day
91
- //
92
- // valid values are 0 to 6, Sunday to Saturday
93
- //
94
- // default is 1, Monday
95
- first_day_of_week: 1,
96
-
97
- // format of the returned date
98
- //
99
- // accepts the following characters for date formatting: d, D, j, l, N, w, S, F, m, M, n, Y, y borrowing
100
- // syntax from (PHP's date function)
101
- //
102
- // note that when setting a date format without days ('d', 'j'), the users will be able to select only years
103
- // and months, and when setting a format without months and days ('F', 'm', 'M', 'n', 'd', 'j'), the
104
- // users will be able to select only years; likewise, when setting a date format with just months ('F', 'm',
105
- // 'M', 'n') or just years ('Y', 'y'), users will be able to select only months and years, respectively.
106
- //
107
- // also note that the value of the "view" property (see below) may be overridden if it is the case: a value of
108
- // "days" for the "view" property makes no sense if the date format doesn't allow the selection of days.
109
- //
110
- // default is Y-m-d
111
- format: 'Y-m-d',
112
-
113
- // should the icon for opening the datepicker be inside the element?
114
- // if set to FALSE, the icon will be placed to the right of the parent element, while if set to TRUE it will
115
- // be placed to the right of the parent element, but *inside* the element itself
116
- //
117
- // default is TRUE
118
- inside: true,
119
-
120
- // the caption for the "Clear" button
121
- lang_clear_date: 'Clear date',
122
-
123
- // months names
124
- months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
125
-
126
- // by default, the abbreviated name of a month consists of the first 3 letters from the month's full name;
127
- // while this is common for most languages, there are also exceptions for languages like Thai, Loa, Myanmar,
128
- // etc. where this is not correct; for these cases, specify an array with the abbreviations to be used for
129
- // the months of the year; leave it FALSE to use the first 3 letters of a month's name as the abbreviation.
130
- //
131
- // default is FALSE
132
- months_abbr: false,
133
-
134
- // the offset, in pixels (x, y), to shift the date picker's position relative to the top-right of the icon
135
- // that toggles the date picker or, if the icon is disabled, relative to the top-right corner of the element
136
- // the plugin is attached to.
137
- //
138
- // note that this only applies if the position of element relative to the browser's viewport doesn't require
139
- // the date picker to be placed automatically so that it is visible!
140
- //
141
- // default is [5, -5]
142
- offset: [5, -5],
143
-
144
- // if set as a jQuery element with a Zebra_DatePicker attached, that particular date picker will use the
145
- // current date picker's value as starting date
146
- // note that the rules set in the "direction" property will still apply, only that the reference date will
147
- // not be the current system date but the value selected in the current date picker
148
- // default is FALSE (not paired with another date picker)
149
- pair: false,
150
-
151
- // should the element the calendar is attached to, be read-only?
152
- // if set to TRUE, a date can be set only through the date picker and cannot be entered manually
153
- //
154
- // default is TRUE
155
- readonly_element: true,
156
-
157
- // should days from previous and/or next month be selectable when visible?
158
- // note that if the value of this property is set to TRUE, the value of "show_other_months" will be considered
159
- // TRUE regardless of the actual value!
160
- //
161
- // default is FALSE
162
- select_other_months: false,
163
-
164
- // should the "Clear date" button be visible?
165
- //
166
- // accepted values are:
167
- //
168
- // - 0 (zero) - the button for clearing a previously selected date is shown only if a previously selected date
169
- // already exists; this means that if the input the date picker is attached to is empty, and the user selects
170
- // a date for the first time, this button will not be visible; once the user picked a date and opens the date
171
- // picker again, this time the button will be visible.
172
- //
173
- // - TRUE will make the button visible all the time
174
- //
175
- // - FALSE will disable the button
176
- //
177
- // default is "0" (without quotes)
178
- show_clear_date: 0,
179
-
180
- // should a calendar icon be added to the elements the plugin is attached to?
181
- //
182
- // default is TRUE
183
- show_icon: true,
184
-
185
- // should days from previous and/or next month be visible?
186
- //
187
- // default is TRUE
188
- show_other_months: true,
189
-
190
- // should the "Today" button be visible?
191
- // setting it to anything but boolean FALSE will enable the button and will use the property's value as
192
- // caption for the button; setting it to FALSE will disable the button
193
- //
194
- // default is "Today"
195
- show_select_today: 'Today',
196
-
197
- // should an extra column be shown, showing the number of each week?
198
- // anything other than FALSE will enable this feature, and use the given value as column title
199
- // i.e. show_week_number: 'Wk' would enable this feature and have "Wk" as the column's title
200
- //
201
- // default is FALSE
202
- show_week_number: false,
203
-
204
- // a default date to start the date picker with
205
- // must be specified in the format defined by the "format" property, or it will be ignored!
206
- // note that this value is used only if there is no value in the field the date picker is attached to!
207
- start_date: false,
208
-
209
- // how should the date picker start; valid values are "days", "months" and "years"
210
- // note that the date picker is always cycling days-months-years when clicking in the date picker's header,
211
- // and years-months-days when selecting dates (unless one or more of the views are missing due to the date's
212
- // format)
213
- //
214
- // also note that the value of the "view" property may be overridden if the date's format requires so! (i.e.
215
- // "days" for the "view" property makes no sense if the date format doesn't allow the selection of days)
216
- //
217
- // default is "days"
218
- view: 'days',
219
-
220
- // days of the week that are considered "weekend days"
221
- // valid values are 0 to 6, Sunday to Saturday
222
- //
223
- // default values are 0 and 6 (Saturday and Sunday)
224
- weekend_days: [0, 6],
225
-
226
- // when set to TRUE, day numbers < 10 will be prefixed with 0; set to FALSE if you don't want that
227
- //
228
- // default is TRUE
229
- zero_pad: false,
230
-
231
- // callback function to be executed whenever the user changes the view (days/months/years), as well as when
232
- // the user navigates by clicking on the "next"/"previous" icons in any of the views;
233
- //
234
- // the callback function called by this event takes 3 arguments - the first argument represents the current
235
- // view (can be "days", "months" or "years"), the second argument represents an array containing the "active"
236
- // elements (not disabled) from the view, as jQuery elements, allowing for easy customization and interaction
237
- // with particular cells in the date picker's view, while the third argument is a reference to the element
238
- // the date picker is attached to, as a jQuery object
239
- //
240
- // for simplifying searching for particular dates, each element in the second argument will also have a
241
- // "date" data attribute whose format depends on the value of the "view" argument:
242
- // - YYYY-MM-DD for elements in the "days" view
243
- // - YYYY-MM for elements in the "months" view
244
- // - YYYY for elements in the "years" view
245
- onChange: null,
246
-
247
- // callback function to be executed when the user clicks the "Clear" button
248
- // the callback function takes a single argument:
249
- // - a reference to the element the date picker is attached to, as a jQuery object
250
- onClear: null,
251
-
252
- // callback function to be executed when a date is selected
253
- // the callback function takes 4 arguments:
254
- // - the date in the format specified by the "format" attribute;
255
- // - the date in YYYY-MM-DD format
256
- // - the date as a JavaScript Date object
257
- // - a reference to the element the date picker is attached to, as a jQuery object
258
- onSelect: null
259
-
260
- };
261
-
262
- // private properties
263
- var view, datepicker, icon, header, daypicker, monthpicker, yearpicker, cleardate, current_system_month, current_system_year,
264
- current_system_day, first_selectable_month, first_selectable_year, first_selectable_day, selected_month, selected_year,
265
- default_day, default_month, default_year, enabled_dates, disabled_dates, shim, start_date, end_date, last_selectable_day,
266
- last_selectable_year, last_selectable_month, daypicker_cells, monthpicker_cells, yearpicker_cells, views, clickables,
267
- selecttoday, footer, show_select_today, timeout;
268
-
269
- var plugin = this;
270
-
271
- plugin.settings = {};
272
-
273
- // the jQuery version of the element
274
- // "element" (without the $) will point to the DOM element
275
- var $element = $(element);
276
-
277
- /**
278
- * Constructor method. Initializes the date picker.
279
- *
280
- * @return void
281
- */
282
- var init = function(update) {
283
-
284
- // merge default settings with user-settings (unless we're just updating settings)
285
- if (!update) plugin.settings = $.extend({}, defaults, options);
286
-
287
- // if the element should be read-only, set the "readonly" attribute
288
- if (plugin.settings.readonly_element) $element.attr('readonly', 'readonly');
289
-
290
- // determine the views the user can cycle through, depending on the format
291
- // that is, if the format doesn't contain the day, the user will be able to cycle only through years and months,
292
- // whereas if the format doesn't contain months nor days, the user will only be able to select years
293
-
294
- var
295
-
296
- // the characters that may be present in the date format and that represent days, months and years
297
- date_chars = {
298
- days: ['d', 'j', 'D'],
299
- months: ['F', 'm', 'M', 'n', 't'],
300
- years: ['o', 'Y', 'y']
301
- },
302
-
303
- // some defaults
304
- has_days = false,
305
- has_months = false,
306
- has_years = false,
307
- type = null;
308
-
309
- // iterate through all the character blocks
310
- for (type in date_chars)
311
-
312
- // iterate through the characters of each block
313
- $.each(date_chars[type], function(index, character) {
314
-
315
- // if current character exists in the "format" property
316
- if (plugin.settings.format.indexOf(character) > -1)
317
-
318
- // set to TRUE the appropriate flag
319
- if (type == 'days') has_days = true;
320
- else if (type == 'months') has_months = true;
321
- else if (type == 'years') has_years = true;
322
-
323
- });
324
-
325
- // if user can cycle through all the views, set the flag accordingly
326
- if (has_days && has_months && has_years) views = ['years', 'months', 'days'];
327
-
328
- // if user can cycle only through year and months, set the flag accordingly
329
- else if (!has_days && has_months && has_years) views = ['years', 'months'];
330
-
331
- // if user can only see the year picker, set the flag accordingly
332
- else if (!has_days && !has_months && has_years) views = ['years'];
333
-
334
- // if user can only see the month picker, set the flag accordingly
335
- else if (!has_days && has_months && !has_years) views = ['months'];
336
-
337
- // if invalid format (no days, no months, no years) use the default where the user is able to cycle through
338
- // all the views
339
- else views = ['years', 'months', 'days'];
340
-
341
- // if the starting view is not amongst the views the user can cycle through, set the correct starting view
342
- if ($.inArray(plugin.settings.view, views) == -1) plugin.settings.view = views[views.length - 1];
343
-
344
- // parse the rules for disabling dates and turn them into arrays of arrays
345
-
346
- // array that will hold the rules for enabling/disabling dates
347
- disabled_dates = []; enabled_dates = [];
348
-
349
- var dates;
350
-
351
- // it's the same logic for preparing the enabled/disable dates...
352
- for (var l = 0; l < 2; l++) {
353
-
354
- // first time we're doing disabled dates,
355
- if (l === 0) dates = plugin.settings.disabled_dates;
356
-
357
- // second time we're doing enabled_dates
358
- else dates = plugin.settings.enabled_dates;
359
-
360
- // if we have a non-empty array
361
- if ($.isArray(dates) && dates.length > 0)
362
-
363
- // iterate through the rules
364
- $.each(dates, function() {
365
-
366
- // split the values in rule by white space
367
- var rules = this.split(' ');
368
-
369
- // there can be a maximum of 4 rules (days, months, years and, optionally, day of the week)
370
- for (var i = 0; i < 4; i++) {
371
-
372
- // if one of the values is not available
373
- // replace it with a * (wildcard)
374
- if (!rules[i]) rules[i] = '*';
375
-
376
- // if rule contains a comma, create a new array by splitting the rule by commas
377
- // if there are no commas create an array containing the rule's string
378
- rules[i] = (rules[i].indexOf(',') > -1 ? rules[i].split(',') : new Array(rules[i]));
379
-
380
- // iterate through the items in the rule
381
- for (var j = 0; j < rules[i].length; j++)
382
-
383
- // if item contains a dash (defining a range)
384
- if (rules[i][j].indexOf('-') > -1) {
385
-
386
- // get the lower and upper limits of the range
387
- var limits = rules[i][j].match(/^([0-9]+)\-([0-9]+)/);
388
-
389
- // if range is valid
390
- if (null !== limits) {
391
-
392
- // iterate through the range
393
- for (var k = to_int(limits[1]); k <= to_int(limits[2]); k++)
394
-
395
- // if value is not already among the values of the rule
396
- // add it to the rule
397
- if ($.inArray(k, rules[i]) == -1) rules[i].push(k + '');
398
-
399
- // remove the range indicator
400
- rules[i].splice(j, 1);
401
-
402
- }
403
-
404
- }
405
-
406
- // iterate through the items in the rule
407
- // and make sure that numbers are numbers
408
- for (j = 0; j < rules[i].length; j++) rules[i][j] = (isNaN(to_int(rules[i][j])) ? rules[i][j] : to_int(rules[i][j]));
409
-
410
- }
411
-
412
- // add to the correct list of processed rules
413
- // first time we're doing disabled dates,
414
- if (l === 0) disabled_dates.push(rules);
415
-
416
- // second time we're doing enabled_dates
417
- else enabled_dates.push(rules);
418
-
419
- });
420
-
421
- }
422
-
423
- var
424
-
425
- // cache the current system date
426
- date = new Date(),
427
-
428
- // when the date picker's starting date depends on the value of another date picker, this value will be
429
- // set by the other date picker
430
- // this value will be used as base for all calculations (if not set, will be the same as the current
431
- // system date)
432
- reference_date = (!plugin.settings.reference_date ? ($element.data('zdp_reference_date') && undefined !== $element.data('zdp_reference_date') ? $element.data('zdp_reference_date') : date) : plugin.settings.reference_date),
433
-
434
- tmp_start_date, tmp_end_date;
435
-
436
- // reset these values here as this method might be called more than once during a date picker's lifetime
437
- // (when the selectable dates depend on the values from another date picker)
438
- start_date = undefined; end_date = undefined;
439
-
440
- // extract the date parts
441
- // also, save the current system month/day/year - we'll use them to highlight the current system date
442
- first_selectable_month = reference_date.getMonth();
443
- current_system_month = date.getMonth();
444
- first_selectable_year = reference_date.getFullYear();
445
- current_system_year = date.getFullYear();
446
- first_selectable_day = reference_date.getDate();
447
- current_system_day = date.getDate();
448
-
449
- // check if the calendar has any restrictions
450
-
451
- // calendar is future-only, starting today
452
- // it means we have a starting date (the current system date), but no ending date
453
- if (plugin.settings.direction === true) start_date = reference_date;
454
-
455
- // calendar is past only, ending today
456
- else if (plugin.settings.direction === false) {
457
-
458
- // it means we have an ending date (the reference date), but no starting date
459
- end_date = reference_date;
460
-
461
- // extract the date parts
462
- last_selectable_month = end_date.getMonth();
463
- last_selectable_year = end_date.getFullYear();
464
- last_selectable_day = end_date.getDate();
465
-
466
- } else if (
467
-
468
- // if direction is not given as an array and the value is an integer > 0
469
- (!$.isArray(plugin.settings.direction) && is_integer(plugin.settings.direction) && to_int(plugin.settings.direction) > 0) ||
470
-
471
- // or direction is given as an array
472
- ($.isArray(plugin.settings.direction) && (
473
-
474
- // and first entry is a valid date
475
- (tmp_start_date = check_date(plugin.settings.direction[0])) ||
476
- // or a boolean TRUE
477
- plugin.settings.direction[0] === true ||
478
- // or an integer > 0
479
- (is_integer(plugin.settings.direction[0]) && plugin.settings.direction[0] > 0)
480
-
481
- ) && (
482
-
483
- // and second entry is a valid date
484
- (tmp_end_date = check_date(plugin.settings.direction[1])) ||
485
- // or a boolean FALSE
486
- plugin.settings.direction[1] === false ||
487
- // or integer >= 0
488
- (is_integer(plugin.settings.direction[1]) && plugin.settings.direction[1] >= 0)
489
-
490
- ))
491
-
492
- ) {
493
-
494
- // if an exact starting date was given, use that as a starting date
495
- if (tmp_start_date) start_date = tmp_start_date;
496
-
497
- // otherwise
498
- else
499
-
500
- // figure out the starting date
501
- // use the Date object to normalize the date
502
- // for example, 2011 05 33 will be transformed to 2011 06 02
503
- start_date = new Date(
504
- first_selectable_year,
505
- first_selectable_month,
506
- first_selectable_day + (!$.isArray(plugin.settings.direction) ? to_int(plugin.settings.direction) : to_int(plugin.settings.direction[0] === true ? 0 : plugin.settings.direction[0]))
507
- );
508
-
509
- // re-extract the date parts
510
- first_selectable_month = start_date.getMonth();
511
- first_selectable_year = start_date.getFullYear();
512
- first_selectable_day = start_date.getDate();
513
-
514
- // if an exact ending date was given and the date is after the starting date, use that as a ending date
515
- if (tmp_end_date && +tmp_end_date >= +start_date) end_date = tmp_end_date;
516
-
517
- // if have information about the ending date
518
- else if (!tmp_end_date && plugin.settings.direction[1] !== false && $.isArray(plugin.settings.direction))
519
-
520
- // figure out the ending date
521
- // use the Date object to normalize the date
522
- // for example, 2011 05 33 will be transformed to 2011 06 02
523
- end_date = new Date(
524
- first_selectable_year,
525
- first_selectable_month,
526
- first_selectable_day + to_int(plugin.settings.direction[1])
527
- );
528
-
529
- // if a valid ending date exists
530
- if (end_date) {
531
-
532
- // extract the date parts
533
- last_selectable_month = end_date.getMonth();
534
- last_selectable_year = end_date.getFullYear();
535
- last_selectable_day = end_date.getDate();
536
-
537
- }
538
-
539
- } else if (
540
-
541
- // if direction is not given as an array and the value is an integer < 0
542
- (!$.isArray(plugin.settings.direction) && is_integer(plugin.settings.direction) && to_int(plugin.settings.direction) < 0) ||
543
-
544
- // or direction is given as an array
545
- ($.isArray(plugin.settings.direction) && (
546
-
547
- // and first entry is boolean FALSE
548
- plugin.settings.direction[0] === false ||
549
- // or an integer < 0
550
- (is_integer(plugin.settings.direction[0]) && plugin.settings.direction[0] < 0)
551
-
552
- ) && (
553
-
554
- // and second entry is a valid date
555
- (tmp_start_date = check_date(plugin.settings.direction[1])) ||
556
- // or an integer >= 0
557
- (is_integer(plugin.settings.direction[1]) && plugin.settings.direction[1] >= 0)
558
-
559
- ))
560
-
561
- ) {
562
-
563
- // figure out the ending date
564
- // use the Date object to normalize the date
565
- // for example, 2011 05 33 will be transformed to 2011 06 02
566
- end_date = new Date(
567
- first_selectable_year,
568
- first_selectable_month,
569
- first_selectable_day + (!$.isArray(plugin.settings.direction) ? to_int(plugin.settings.direction) : to_int(plugin.settings.direction[0] === false ? 0 : plugin.settings.direction[0]))
570
- );
571
-
572
- // re-extract the date parts
573
- last_selectable_month = end_date.getMonth();
574
- last_selectable_year = end_date.getFullYear();
575
- last_selectable_day = end_date.getDate();
576
-
577
- // if an exact starting date was given, and the date is before the ending date, use that as a starting date
578
- if (tmp_start_date && +tmp_start_date < +end_date) start_date = tmp_start_date;
579
-
580
- // if have information about the starting date
581
- else if (!tmp_start_date && $.isArray(plugin.settings.direction))
582
-
583
- // figure out the staring date
584
- // use the Date object to normalize the date
585
- // for example, 2011 05 33 will be transformed to 2011 06 02
586
- start_date = new Date(
587
- last_selectable_year,
588
- last_selectable_month,
589
- last_selectable_day - to_int(plugin.settings.direction[1])
590
- );
591
-
592
- // if a valid starting date exists
593
- if (start_date) {
594
-
595
- // extract the date parts
596
- first_selectable_month = start_date.getMonth();
597
- first_selectable_year = start_date.getFullYear();
598
- first_selectable_day = start_date.getDate();
599
-
600
- }
601
-
602
- // if there are disabled dates
603
- } else if ($.isArray(plugin.settings.disabled_dates) && plugin.settings.disabled_dates.length > 0)
604
-
605
- // iterate through the rules for disabling dates
606
- for (var interval in disabled_dates)
607
-
608
- // only if there is a rule that disables *everything*
609
- if (disabled_dates[interval][0] == '*' && disabled_dates[interval][1] == '*' && disabled_dates[interval][2] == '*' && disabled_dates[interval][3] == '*') {
610
-
611
- var tmpDates = [];
612
-
613
- // iterate through the rules for enabling dates
614
- // looking for the minimum/maximum selectable date (if it's the case)
615
- $.each(enabled_dates, function() {
616
-
617
- var rule = this;
618
-
619
- // if the rule doesn't apply to all years
620
- if (rule[2][0] != '*')
621
-
622
- // format date and store it in our stack
623
- tmpDates.push(parseInt(
624
- rule[2][0] +
625
- (rule[1][0] == '*' ? '12' : str_pad(rule[1][0], 2)) +
626
- (rule[0][0] == '*' ? (rule[1][0] == '*' ? '31' : new Date(rule[2][0], rule[1][0], 0).getDate()) : str_pad(rule[0][0], 2)), 10));
627
-
628
- });
629
-
630
- // sort dates ascending
631
- tmpDates.sort();
632
-
633
- // if we have any rules
634
- if (tmpDates.length > 0) {
635
-
636
- // get date parts
637
- var matches = (tmpDates[0] + '').match(/([0-9]{4})([0-9]{2})([0-9]{2})/);
638
-
639
- // assign the date parts to the appropriate variables
640
- first_selectable_year = parseInt(matches[1], 10);
641
- first_selectable_month = parseInt(matches[2], 10) - 1;
642
- first_selectable_day = parseInt(matches[3], 10);
643
-
644
- }
645
-
646
- // don't look further
647
- break;
648
-
649
- }
650
-
651
- // if first selectable date exists but is disabled, find the actual first selectable date
652
- if (is_disabled(first_selectable_year, first_selectable_month, first_selectable_day)) {
653
-
654
- // loop until we find the first selectable year
655
- while (is_disabled(first_selectable_year)) {
656
-
657
- // if calendar is past-only,
658
- if (!start_date) {
659
-
660
- // decrement the year
661
- first_selectable_year--;
662
-
663
- // because we've changed years, reset the month to December
664
- first_selectable_month = 11;
665
-
666
- // otherwise
667
- } else {
668
-
669
- // increment the year
670
- first_selectable_year++;
671
-
672
- // because we've changed years, reset the month to January
673
- first_selectable_month = 0;
674
-
675
- }
676
-
677
- }
678
-
679
- // loop until we find the first selectable month
680
- while (is_disabled(first_selectable_year, first_selectable_month)) {
681
-
682
- // if calendar is past-only
683
- if (!start_date) {
684
-
685
- // decrement the month
686
- first_selectable_month--;
687
-
688
- // because we've changed months, reset the day to the last day of the month
689
- first_selectable_day = new Date(first_selectable_year, first_selectable_month + 1, 0).getDate();
690
-
691
- // otherwise
692
- } else {
693
-
694
- // increment the month
695
- first_selectable_month++;
696
-
697
- // because we've changed months, reset the day to the first day of the month
698
- first_selectable_day = 1;
699
-
700
- }
701
-
702
- // if we moved to a following year
703
- if (first_selectable_month > 11) {
704
-
705
- // increment the year
706
- first_selectable_year++;
707
-
708
- // reset the month to January
709
- first_selectable_month = 0;
710
-
711
- // because we've changed months, reset the day to the first day of the month
712
- first_selectable_day = 1;
713
-
714
- // if we moved to a previous year
715
- } else if (first_selectable_month < 0) {
716
-
717
- // decrement the year
718
- first_selectable_year--;
719
-
720
- // reset the month to December
721
- first_selectable_month = 11;
722
-
723
- // because we've changed months, reset the day to the last day of the month
724
- first_selectable_day = new Date(first_selectable_year, first_selectable_month + 1, 0).getDate();
725
-
726
- }
727
-
728
- }
729
-
730
- // loop until we find the first selectable day
731
- while (is_disabled(first_selectable_year, first_selectable_month, first_selectable_day)) {
732
-
733
- // if calendar is past-only, decrement the day
734
- if (!start_date) first_selectable_day--;
735
-
736
- // otherwise, increment the day
737
- else first_selectable_day++;
738
-
739
- // use the Date object to normalize the date
740
- // for example, 2011 05 33 will be transformed to 2011 06 02
741
- date = new Date(first_selectable_year, first_selectable_month, first_selectable_day);
742
-
743
- // re-extract date parts from the normalized date
744
- // as we use them in the current loop
745
- first_selectable_year = date.getFullYear();
746
- first_selectable_month = date.getMonth();
747
- first_selectable_day = date.getDate();
748
-
749
- }
750
-
751
- // use the Date object to normalize the date
752
- // for example, 2011 05 33 will be transformed to 2011 06 02
753
- date = new Date(first_selectable_year, first_selectable_month, first_selectable_day);
754
-
755
- // re-extract date parts from the normalized date
756
- // as we use them in the current loop
757
- first_selectable_year = date.getFullYear();
758
- first_selectable_month = date.getMonth();
759
- first_selectable_day = date.getDate();
760
-
761
- }
762
-
763
- // get the default date, from the element, and check if it represents a valid date, according to the required format
764
- var default_date = check_date($element.val() || (plugin.settings.start_date ? plugin.settings.start_date : ''));
765
-
766
- // if there is a default date but it is disabled
767
- if (default_date && is_disabled(default_date.getFullYear(), default_date.getMonth(), default_date.getDate()))
768
-
769
- // clear the value of the parent element
770
- $element.val('');
771
-
772
- // updates value for the date picker whose starting date depends on the selected date (if any)
773
- update_dependent(default_date);
774
-
775
- // if date picker is not always visible
776
- if (!plugin.settings.always_visible) {
777
-
778
- // if we're just creating the date picker
779
- if (!update) {
780
-
781
- // if a calendar icon should be added to the element the plugin is attached to, create the icon now
782
- if (plugin.settings.show_icon) {
783
-
784
- // strangely, in Firefox 21+ (or maybe even earlier) input elements have their "display" property
785
- // set to "inline" instead of "inline-block" as do all the other browsers.
786
- // because this behavior brakes the positioning of the icon, we'll set the "display" property to
787
- // "inline-block" before anything else;
788
- if (browser.name == 'firefox' && $element.is('input[type="text"]') && $element.css('display') == 'inline') $element.css('display', 'inline-block');
789
-
790
- // we create a wrapper for the parent element so that we can later position the icon
791
- // also, make sure the wrapper inherits some important css properties of the parent element
792
- var icon_wrapper = jQuery('<span class="Zebra_DatePicker_Icon_Wrapper"></span>').css({
793
- 'display': $element.css('display'),
794
- 'position': $element.css('position') == 'static' ? 'relative' : $element.css('position'),
795
- 'float': $element.css('float'),
796
- 'top': $element.css('top'),
797
- 'right': $element.css('right'),
798
- 'bottom': $element.css('bottom'),
799
- 'left': $element.css('left')
800
- });
801
-
802
- // put wrapper around the element
803
- // also, make sure we set some important css properties for it
804
- $element.wrap(icon_wrapper).css({
805
- 'position': 'relative',
806
- 'top': 'auto',
807
- 'right': 'auto',
808
- 'bottom': 'auto',
809
- 'left': 'auto'
810
- });
811
-
812
- // create the actual calendar icon (show a disabled icon if the element is disabled)
813
- icon = jQuery('<button type="button" class="Zebra_DatePicker_Icon' + ($element.attr('disabled') == 'disabled' ? ' Zebra_DatePicker_Icon_Disabled' : '') + '">Pick a date</button>');
814
-
815
- // a reference to the icon, as a global property
816
- plugin.icon = icon;
817
-
818
- // the date picker will open when clicking both the icon and the element the plugin is attached to
819
- clickables = icon.add($element);
820
-
821
- // if calendar icon is not visible, the date picker will open when clicking the element
822
- } else clickables = $element;
823
-
824
- // attach the click event to the clickable elements (icon and/or element)
825
- clickables.bind('click', function(e) {
826
-
827
- e.preventDefault();
828
-
829
- // if element is not disabled
830
- if (!$element.attr('disabled'))
831
-
832
- // if the date picker is visible, hide it
833
- if (datepicker.css('display') != 'none') plugin.hide();
834
-
835
- // if the date picker is not visible, show it
836
- else plugin.show();
837
-
838
- });
839
-
840
- // if icon exists, inject it into the DOM, right after the parent element (and inside the wrapper)
841
- if (undefined !== icon) icon.insertAfter($element);
842
-
843
- }
844
-
845
- // if calendar icon exists
846
- if (undefined !== icon) {
847
-
848
- // needed when updating: remove any inline style set previously by library,
849
- // so we get the right values below
850
- icon.attr('style', '');
851
-
852
- // if calendar icon is to be placed *inside* the element
853
- // add an extra class to the icon
854
- if (plugin.settings.inside) icon.addClass('Zebra_DatePicker_Icon_Inside');
855
-
856
- var
857
-
858
- // get element' width and height (including margins)
859
- element_width = $element.outerWidth(),
860
- element_height = $element.outerHeight(),
861
- element_margin_left = parseInt($element.css('marginLeft'), 10) || 0,
862
- element_margin_top = parseInt($element.css('marginTop'), 10) || 0,
863
-
864
- // get icon's width, height and margins
865
- icon_width = icon.outerWidth(),
866
- icon_height = icon.outerHeight(),
867
- icon_margin_left = parseInt(icon.css('marginLeft'), 10) || 0,
868
- icon_margin_right = parseInt(icon.css('marginRight'), 10) || 0;
869
-
870
- // if icon is to be placed *inside* the element
871
- // position the icon accordingly
872
- if (plugin.settings.inside)
873
-
874
- icon.css({
875
- 'top': element_margin_top + ((element_height - icon_height) / 2),
876
- 'left': element_margin_left + (element_width - icon_width - icon_margin_right)
877
- });
878
-
879
- // if icon is to be placed to the right of the element
880
- // position the icon accordingly
881
- else
882
-
883
- icon.css({
884
- 'top': element_margin_top + ((element_height - icon_height) / 2),
885
- 'left': element_margin_left + element_width + icon_margin_left
886
- });
887
-
888
- }
889
-
890
- }
891
-
892
- // if calendar icon exists (there's no icon if the date picker is always visible or it is specifically hidden)
893
- if (undefined !== icon)
894
-
895
- // if parent element is not visible (has display: none, width and height are explicitly set to 0, an ancestor
896
- // element is hidden, so the element is not shown on the page), hide the icon, or show it otherwise
897
- if (!($element.is(':visible'))) icon.hide(); else icon.show();
898
-
899
- // if the "Today" button is to be shown and it makes sense to be shown
900
- // (the "days" view is available and "today" is not a disabled date)
901
- show_select_today = (plugin.settings.show_select_today !== false && $.inArray('days', views) > -1 && !is_disabled(current_system_year, current_system_month, current_system_day) ? plugin.settings.show_select_today : false);
902
-
903
- // if we just needed to recompute the things above, return now
904
- if (update) return;
905
-
906
- // if icon exists, update its position when the page is resized
907
- if (icon) $(window).bind('resize', _resize);
908
-
909
- // generate the container that will hold everything
910
- var html = '' +
911
- '<div class="Zebra_DatePicker">' +
912
- '<table class="dp_header">' +
913
- '<tr>' +
914
- '<td class="dp_previous">&#171;</td>' +
915
- '<td class="dp_caption">&#032;</td>' +
916
- '<td class="dp_next">&#187;</td>' +
917
- '</tr>' +
918
- '</table>' +
919
- '<table class="dp_daypicker"></table>' +
920
- '<table class="dp_monthpicker"></table>' +
921
- '<table class="dp_yearpicker"></table>' +
922
- '<table class="dp_footer"><tr>' +
923
- '<td class="dp_today"' + (plugin.settings.show_clear_date !== false ? ' style="width:50%"' : '') + '>' + show_select_today + '</td>' +
924
- '<td class="dp_clear"' + (show_select_today !== false ? ' style="width:50%"' : '') + '>' + plugin.settings.lang_clear_date + '</td>' +
925
- '</tr></table>' +
926
- '</div>';
927
-
928
- // create a jQuery object out of the HTML above and create a reference to it
929
- datepicker = $(html);
930
-
931
- // a reference to the calendar, as a global property
932
- plugin.datepicker = datepicker;
933
-
934
- // create references to the different parts of the date picker
935
- header = $('table.dp_header', datepicker);
936
- daypicker = $('table.dp_daypicker', datepicker);
937
- monthpicker = $('table.dp_monthpicker', datepicker);
938
- yearpicker = $('table.dp_yearpicker', datepicker);
939
- footer = $('table.dp_footer', datepicker);
940
- selecttoday = $('td.dp_today', footer);
941
- cleardate = $('td.dp_clear', footer);
942
-
943
- // if date picker is not always visible
944
- if (!plugin.settings.always_visible)
945
-
946
- // inject the container into the DOM
947
- $('body').append(datepicker);
948
-
949
- // otherwise, if element is not disabled
950
- else if (!$element.attr('disabled')) {
951
-
952
- // inject the date picker into the designated container element
953
- plugin.settings.always_visible.append(datepicker);
954
-
955
- // and make it visible right away
956
- plugin.show();
957
-
958
- }
959
-
960
- // add the mouseover/mousevents to all to the date picker's cells
961
- // except those that are not selectable
962
- datepicker.
963
- delegate('td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked, .dp_week_number)', 'mouseover', function() {
964
- $(this).addClass('dp_hover');
965
- }).
966
- delegate('td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked, .dp_week_number)', 'mouseout', function() {
967
- $(this).removeClass('dp_hover');
968
- });
969
-
970
- // prevent text highlighting for the text in the header
971
- // (for the case when user keeps clicking the "next" and "previous" buttons)
972
- disable_text_select($('td', header));
973
-
974
- // event for when clicking the "previous" button
975
- $('.dp_previous', header).bind('click', function() {
976
-
977
- // if button is not disabled
978
- if (!$(this).hasClass('dp_blocked')) {
979
-
980
- // if view is "months"
981
- // decrement year by one
982
- if (view == 'months') selected_year--;
983
-
984
- // if view is "years"
985
- // decrement years by 12
986
- else if (view == 'years') selected_year -= 12;
987
-
988
- // if view is "days"
989
- // decrement the month and
990
- // if month is out of range
991
- else if (--selected_month < 0) {
992
-
993
- // go to the last month of the previous year
994
- selected_month = 11;
995
- selected_year--;
996
-
997
- }
998
-
999
- // generate the appropriate view
1000
- manage_views();
1001
-
1002
- }
1003
-
1004
- });
1005
-
1006
- // attach a click event to the caption in header
1007
- $('.dp_caption', header).bind('click', function() {
1008
-
1009
- // if current view is "days", take the user to the next view, depending on the format
1010
- if (view == 'days') view = ($.inArray('months', views) > -1 ? 'months' : ($.inArray('years', views) > -1 ? 'years' : 'days'));
1011
-
1012
- // if current view is "months", take the user to the next view, depending on the format
1013
- else if (view == 'months') view = ($.inArray('years', views) > -1 ? 'years' : ($.inArray('days', views) > -1 ? 'days' : 'months'));
1014
-
1015
- // if current view is "years", take the user to the next view, depending on the format
1016
- else view = ($.inArray('days', views) > -1 ? 'days' : ($.inArray('months', views) > -1 ? 'months' : 'years'));
1017
-
1018
- // generate the appropriate view
1019
- manage_views();
1020
-
1021
- });
1022
-
1023
- // event for when clicking the "next" button
1024
- $('.dp_next', header).bind('click', function() {
1025
-
1026
- // if button is not disabled
1027
- if (!$(this).hasClass('dp_blocked')) {
1028
-
1029
- // if view is "months"
1030
- // increment year by 1
1031
- if (view == 'months') selected_year++;
1032
-
1033
- // if view is "years"
1034
- // increment years by 12
1035
- else if (view == 'years') selected_year += 12;
1036
-
1037
- // if view is "days"
1038
- // increment the month and
1039
- // if month is out of range
1040
- else if (++selected_month == 12) {
1041
-
1042
- // go to the first month of the next year
1043
- selected_month = 0;
1044
- selected_year++;
1045
-
1046
- }
1047
-
1048
- // generate the appropriate view
1049
- manage_views();
1050
-
1051
- }
1052
-
1053
- });
1054
-
1055
- // attach a click event for the cells in the day picker
1056
- daypicker.delegate('td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_week_number)', 'click', function() {
1057
-
1058
- // if other months are selectable and currently clicked cell contains a class with the cell's date
1059
- if (plugin.settings.select_other_months && null !== (matches = $(this).attr('class').match(/date\_([0-9]{4})(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])/)))
1060
-
1061
- // use the stored date
1062
- select_date(matches[1], matches[2], matches[3], 'days', $(this));
1063
-
1064
- // put selected date in the element the plugin is attached to, and hide the date picker
1065
- else select_date(selected_year, selected_month, to_int($(this).html()), 'days', $(this));
1066
-
1067
- });
1068
-
1069
- // attach a click event for the cells in the month picker
1070
- monthpicker.delegate('td:not(.dp_disabled)', 'click', function() {
1071
-
1072
- // get the month we've clicked on
1073
- var matches = $(this).attr('class').match(/dp\_month\_([0-9]+)/);
1074
-
1075
- // set the selected month
1076
- selected_month = to_int(matches[1]);
1077
-
1078
- // if user can select only years and months
1079
- if ($.inArray('days', views) == -1)
1080
-
1081
- // put selected date in the element the plugin is attached to, and hide the date picker
1082
- select_date(selected_year, selected_month, 1, 'months', $(this));
1083
-
1084
- else {
1085
-
1086
- // direct the user to the "days" view
1087
- view = 'days';
1088
-
1089
- // if date picker is always visible
1090
- // empty the value in the text box the date picker is attached to
1091
- if (plugin.settings.always_visible) $element.val('');
1092
-
1093
- // generate the appropriate view
1094
- manage_views();
1095
-
1096
- }
1097
-
1098
- });
1099
-
1100
- // attach a click event for the cells in the year picker
1101
- yearpicker.delegate('td:not(.dp_disabled)', 'click', function() {
1102
-
1103
- // set the selected year
1104
- selected_year = to_int($(this).html());
1105
-
1106
- // if user can select only years
1107
- if ($.inArray('months', views) == -1)
1108
-
1109
- // put selected date in the element the plugin is attached to, and hide the date picker
1110
- select_date(selected_year, 1, 1, 'years', $(this));
1111
-
1112
- else {
1113
-
1114
- // direct the user to the "months" view
1115
- view = 'months';
1116
-
1117
- // if date picker is always visible
1118
- // empty the value in the text box the date picker is attached to
1119
- if (plugin.settings.always_visible) $element.val('');
1120
-
1121
- // generate the appropriate view
1122
- manage_views();
1123
-
1124
- }
1125
-
1126
- });
1127
-
1128
- // function to execute when the "Today" button is clicked
1129
- $(selecttoday).bind('click', function(e) {
1130
-
1131
- e.preventDefault();
1132
-
1133
- // select the current date
1134
- select_date(current_system_year, current_system_month, current_system_day, 'days', $('.dp_current', daypicker));
1135
-
1136
- // if date picker is always visible
1137
- if (plugin.settings.always_visible)
1138
-
1139
- // repaint the datepicker so it centers on the currently selected date
1140
- plugin.show();
1141
-
1142
- // hide the date picker
1143
- plugin.hide();
1144
-
1145
- });
1146
-
1147
- // function to execute when the "Clear" button is clicked
1148
- $(cleardate).bind('click', function(e) {
1149
-
1150
- e.preventDefault();
1151
-
1152
- // clear the element's value
1153
- $element.val('');
1154
-
1155
- // if date picker is not always visible
1156
- if (!plugin.settings.always_visible) {
1157
-
1158
- // reset these values
1159
- default_day = null; default_month = null; default_year = null; selected_month = null; selected_year = null;
1160
-
1161
- }
1162
-
1163
- // hide the date picker
1164
- plugin.hide();
1165
-
1166
- // if a callback function exists for when clearing a date
1167
- if (plugin.settings.onClear && typeof plugin.settings.onClear == 'function')
1168
-
1169
- // execute the callback function and pass as argument the element the plugin is attached to
1170
- plugin.settings.onClear($element);
1171
-
1172
- });
1173
-
1174
- // if date picker is not always visible
1175
- if (!plugin.settings.always_visible)
1176
-
1177
- // bind some events to the document
1178
- $(document).bind({
1179
-
1180
- //whenever anything is clicked on the page or a key is pressed
1181
- 'mousedown': _mousedown,
1182
- 'keyup': _keyup
1183
-
1184
- });
1185
-
1186
- // last thing is to pre-render some of the date picker right away
1187
- manage_views();
1188
-
1189
- };
1190
-
1191
- /**
1192
- * Destroys the date picker.
1193
- *
1194
- * @return void
1195
- */
1196
- plugin.destroy = function() {
1197
-
1198
- // remove the attached icon (if it exists)...
1199
- if (undefined !== plugin.icon) plugin.icon.remove();
1200
-
1201
- // ...and the calendar
1202
- plugin.datepicker.remove();
1203
-
1204
- // remove associated event handlers from the document
1205
- $(document).unbind('keyup', _keyup);
1206
- $(document).unbind('mousedown', _mousedown);
1207
- $(window).unbind('resize', _resize);
1208
-
1209
- // remove association with the element
1210
- $element.removeData('Zebra_DatePicker');
1211
-
1212
- // completely delete object
1213
- delete plugin;
1214
-
1215
- };
1216
-
1217
- /**
1218
- * Hides the date picker.
1219
- *
1220
- * @return void
1221
- */
1222
- plugin.hide = function() {
1223
-
1224
- // if date picker is not always visible
1225
- if (!plugin.settings.always_visible) {
1226
-
1227
- // hide the iFrameShim in Internet Explorer 6
1228
- iframeShim('hide');
1229
-
1230
- // hide the date picker
1231
- datepicker.hide();
1232
-
1233
- }
1234
-
1235
- };
1236
-
1237
- /**
1238
- * Shows the date picker.
1239
- *
1240
- * @return void
1241
- */
1242
- plugin.show = function() {
1243
-
1244
- // always show the view defined in settings
1245
- view = plugin.settings.view;
1246
-
1247
- // get the default date, from the element, and check if it represents a valid date, according to the required format
1248
- var default_date = check_date($element.val() || (plugin.settings.start_date ? plugin.settings.start_date : ''));
1249
-
1250
- // if the value represents a valid date
1251
- if (default_date) {
1252
-
1253
- // extract the date parts
1254
- // we'll use these to highlight the default date in the date picker and as starting point to
1255
- // what year and month to start the date picker with
1256
- // why separate values? because selected_* will change as user navigates within the date picker
1257
- default_month = default_date.getMonth();
1258
- selected_month = default_date.getMonth();
1259
- default_year = default_date.getFullYear();
1260
- selected_year = default_date.getFullYear();
1261
- default_day = default_date.getDate();
1262
-
1263
- // if the default date represents a disabled date
1264
- if (is_disabled(default_year, default_month, default_day)) {
1265
-
1266
- // clear the value of the parent element
1267
- $element.val('');
1268
-
1269
- // the calendar will start with the first selectable year/month
1270
- selected_month = first_selectable_month;
1271
- selected_year = first_selectable_year;
1272
-
1273
- }
1274
-
1275
- // if a default value is not available, or value does not represent a valid date
1276
- } else {
1277
-
1278
- // the calendar will start with the first selectable year/month
1279
- selected_month = first_selectable_month;
1280
- selected_year = first_selectable_year;
1281
-
1282
- }
1283
-
1284
- // generate the appropriate view
1285
- manage_views();
1286
-
1287
- // if date picker is not always visible and the calendar icon is visible
1288
- if (!plugin.settings.always_visible) {
1289
-
1290
- var
1291
-
1292
- // get the date picker width and height
1293
- datepicker_width = datepicker.outerWidth(),
1294
- datepicker_height = datepicker.outerHeight(),
1295
-
1296
- // compute the date picker's default left and top
1297
- // this will be computed relative to the icon's top-right corner (if the calendar icon exists), or
1298
- // relative to the element's top-right corner otherwise, to which the offsets given at initialization
1299
- // are added/subtracted
1300
- left = (undefined !== icon ? icon.offset().left + icon.outerWidth(true) : $element.offset().left + $element.outerWidth(true)) + plugin.settings.offset[0],
1301
- top = (undefined !== icon ? icon.offset().top : $element.offset().top) - datepicker_height + plugin.settings.offset[1],
1302
-
1303
- // get browser window's width and height
1304
- window_width = $(window).width(),
1305
- window_height = $(window).height(),
1306
-
1307
- // get browser window's horizontal and vertical scroll offsets
1308
- window_scroll_top = $(window).scrollTop(),
1309
- window_scroll_left = $(window).scrollLeft();
1310
-
1311
- // if date picker is outside the viewport, adjust its position so that it is visible
1312
- if (left + datepicker_width > window_scroll_left + window_width) left = window_scroll_left + window_width - datepicker_width;
1313
- if (left < window_scroll_left) left = window_scroll_left;
1314
- if (top + datepicker_height > window_scroll_top + window_height) top = window_scroll_top + window_height - datepicker_height;
1315
- if (top < window_scroll_top) top = window_scroll_top;
1316
-
1317
- // make the date picker visible
1318
- datepicker.css({
1319
- 'left': left,
1320
- 'top': top
1321
- });
1322
-
1323
- // fade-in the date picker
1324
- // for Internet Explorer < 9 show the date picker instantly or fading alters the font's weight
1325
- datepicker.fadeIn(browser.name == 'explorer' && browser.version < 9 ? 0 : 150, 'linear');
1326
-
1327
- // show the iFrameShim in Internet Explorer 6
1328
- iframeShim();
1329
-
1330
- // if date picker is always visible, show it
1331
- } else datepicker.show();
1332
-
1333
- };
1334
-
1335
- /**
1336
- * Updates the configuration options given as argument
1337
- *
1338
- * @param object values An object containing any number of configuration options to be updated
1339
- *
1340
- * @return void
1341
- */
1342
- plugin.update = function(values) {
1343
-
1344
- // if original direction not saved, save it now
1345
- if (plugin.original_direction) plugin.original_direction = plugin.direction;
1346
-
1347
- // update configuration options
1348
- plugin.settings = $.extend(plugin.settings, values);
1349
-
1350
- // reinitialize the object with the new options
1351
- init(true);
1352
-
1353
- };
1354
-
1355
- /**
1356
- * Checks if a string represents a valid date according to the format defined by the "format" property.
1357
- *
1358
- * @param string str_date A string representing a date, formatted accordingly to the "format" property.
1359
- * For example, if "format" is "Y-m-d" the string should look like "2011-06-01"
1360
- *
1361
- * @return mixed Returns a JavaScript Date object if string represents a valid date according
1362
- * formatted according to the "format" property, or FALSE otherwise.
1363
- *
1364
- * @access private
1365
- */
1366
- var check_date = function(str_date) {
1367
-
1368
- // treat argument as a string
1369
- str_date += '';
1370
-
1371
- // if value is given
1372
- if ($.trim(str_date) !== '') {
1373
-
1374
- var
1375
-
1376
- // prepare the format by removing white space from it
1377
- // and also escape characters that could have special meaning in a regular expression
1378
- format = escape_regexp(plugin.settings.format),
1379
-
1380
- // allowed characters in date's format
1381
- format_chars = ['d','D','j','l','N','S','w','F','m','M','n','Y','y'],
1382
-
1383
- // "matches" will contain the characters defining the date's format
1384
- matches = [],
1385
-
1386
- // "regexp" will contain the regular expression built for each of the characters used in the date's format
1387
- regexp = [],
1388
-
1389
- // "position" will contain the position of the caracter found in the date's format
1390
- position = null,
1391
-
1392
- // "segments" will contain the matches of the regular expression
1393
- segments = null;
1394
-
1395
- // iterate through the allowed characters in date's format
1396
- for (var i = 0; i < format_chars.length; i++)
1397
-
1398
- // if character is found in the date's format
1399
- if ((position = format.indexOf(format_chars[i])) > -1)
1400
-
1401
- // save it, alongside the character's position
1402
- matches.push({character: format_chars[i], position: position});
1403
-
1404
- // sort characters defining the date's format based on their position, ascending
1405
- matches.sort(function(a, b){ return a.position - b.position; });
1406
-
1407
- // iterate through the characters defining the date's format
1408
- $.each(matches, function(index, match) {
1409
-
1410
- // add to the array of regular expressions, based on the character
1411
- switch (match.character) {
1412
-
1413
- case 'd': regexp.push('0[1-9]|[12][0-9]|3[01]'); break;
1414
- case 'D': regexp.push('[a-z]{3}'); break;
1415
- case 'j': regexp.push('[1-9]|[12][0-9]|3[01]'); break;
1416
- case 'l': regexp.push('[a-z]+'); break;
1417
- case 'N': regexp.push('[1-7]'); break;
1418
- case 'S': regexp.push('st|nd|rd|th'); break;
1419
- case 'w': regexp.push('[0-6]'); break;
1420
- case 'F': regexp.push('[a-z]+'); break;
1421
- case 'm': regexp.push('0[1-9]|1[012]+'); break;
1422
- case 'M': regexp.push('[a-z]{3}'); break;
1423
- case 'n': regexp.push('[1-9]|1[012]'); break;
1424
- case 'Y': regexp.push('[0-9]{4}'); break;
1425
- case 'y': regexp.push('[0-9]{2}'); break;
1426
-
1427
- }
1428
-
1429
- });
1430
-
1431
- // if we have an array of regular expressions
1432
- if (regexp.length) {
1433
-
1434
- // we will replace characters in the date's format in reversed order
1435
- matches.reverse();
1436
-
1437
- // iterate through the characters in date's format
1438
- $.each(matches, function(index, match) {
1439
-
1440
- // replace each character with the appropriate regular expression
1441
- format = format.replace(match.character, '(' + regexp[regexp.length - index - 1] + ')');
1442
-
1443
- });
1444
-
1445
- // the final regular expression
1446
- regexp = new RegExp('^' + format + '$', 'ig');
1447
-
1448
- // if regular expression was matched
1449
- if ((segments = regexp.exec(str_date))) {
1450
-
1451
- // check if date is a valid date (i.e. there's no February 31)
1452
-
1453
- var tmpdate = new Date(),
1454
- original_day = tmpdate.getDate(),
1455
- original_month = tmpdate.getMonth() + 1,
1456
- original_year = tmpdate.getFullYear(),
1457
- english_days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
1458
- english_months = ['January','February','March','April','May','June','July','August','September','October','November','December'],
1459
- iterable,
1460
-
1461
- // by default, we assume the date is valid
1462
- valid = true;
1463
-
1464
- // reverse back the characters in the date's format
1465
- matches.reverse();
1466
-
1467
- // iterate through the characters in the date's format
1468
- $.each(matches, function(index, match) {
1469
-
1470
- // if the date is not valid, don't look further
1471
- if (!valid) return true;
1472
-
1473
- // based on the character
1474
- switch (match.character) {
1475
-
1476
- case 'm':
1477
- case 'n':
1478
-
1479
- // extract the month from the value entered by the user
1480
- original_month = to_int(segments[index + 1]);
1481
-
1482
- break;
1483
-
1484
- case 'd':
1485
- case 'j':
1486
-
1487
- // extract the day from the value entered by the user
1488
- original_day = to_int(segments[index + 1]);
1489
-
1490
- break;
1491
-
1492
- case 'D':
1493
- case 'l':
1494
- case 'F':
1495
- case 'M':
1496
-
1497
- // if day is given as day name, we'll check against the names in the used language
1498
- if (match.character == 'D' || match.character == 'l') iterable = plugin.settings.days;
1499
-
1500
- // if month is given as month name, we'll check against the names in the used language
1501
- else iterable = plugin.settings.months;
1502
-
1503
- // by default, we assume the day or month was not entered correctly
1504
- valid = false;
1505
-
1506
- // iterate through the month/days in the used language
1507
- $.each(iterable, function(key, value) {
1508
-
1509
- // if month/day was entered correctly, don't look further
1510
- if (valid) return true;
1511
-
1512
- // if month/day was entered correctly
1513
- if (segments[index + 1].toLowerCase() == value.substring(0, (match.character == 'D' || match.character == 'M' ? 3 : value.length)).toLowerCase()) {
1514
-
1515
- // extract the day/month from the value entered by the user
1516
- switch (match.character) {
1517
-
1518
- case 'D': segments[index + 1] = english_days[key].substring(0, 3); break;
1519
- case 'l': segments[index + 1] = english_days[key]; break;
1520
- case 'F': segments[index + 1] = english_months[key]; original_month = key + 1; break;
1521
- case 'M': segments[index + 1] = english_months[key].substring(0, 3); original_month = key + 1; break;
1522
-
1523
- }
1524
-
1525
- // day/month value is valid
1526
- valid = true;
1527
-
1528
- }
1529
-
1530
- });
1531
-
1532
- break;
1533
-
1534
- case 'Y':
1535
-
1536
- // extract the year from the value entered by the user
1537
- original_year = to_int(segments[index + 1]);
1538
-
1539
- break;
1540
-
1541
- case 'y':
1542
-
1543
- // extract the year from the value entered by the user
1544
- original_year = '19' + to_int(segments[index + 1]);
1545
-
1546
- break;
1547
-
1548
- }
1549
- });
1550
-
1551
- // if everything is ok so far
1552
- if (valid) {
1553
-
1554
- // generate a Date object using the values entered by the user
1555
- // (handle also the case when original_month and/or original_day are undefined - i.e date format is "Y-m" or "Y")
1556
- var date = new Date(original_year, (original_month || 1) - 1, original_day || 1);
1557
-
1558
- // if, after that, the date is the same as the date entered by the user
1559
- if (date.getFullYear() == original_year && date.getDate() == (original_day || 1) && date.getMonth() == ((original_month || 1) - 1))
1560
-
1561
- // return the date as JavaScript date object
1562
- return date;
1563
-
1564
- }
1565
-
1566
- }
1567
-
1568
- }
1569
-
1570
- // if script gets this far, return false as something must've went wrong
1571
- return false;
1572
-
1573
- }
1574
-
1575
- };
1576
-
1577
- /**
1578
- * Prevents the possibility of selecting text on a given element. Used on the "previous" and "next" buttons
1579
- * where text might get accidentally selected when user quickly clicks on the buttons.
1580
- *
1581
- * Code by http://chris-barr.com/index.php/entry/disable_text_selection_with_jquery/
1582
- *
1583
- * @param jQuery Element el A jQuery element on which to prevents text selection.
1584
- *
1585
- * @return void
1586
- *
1587
- * @access private
1588
- */
1589
- var disable_text_select = function(el) {
1590
-
1591
- // if browser is Firefox
1592
- if (browser.name == 'firefox') el.css('MozUserSelect', 'none');
1593
-
1594
- // if browser is Internet Explorer
1595
- else if (browser.name == 'explorer') el.bind('selectstart', function() { return false; });
1596
-
1597
- // for the other browsers
1598
- else el.mousedown(function() { return false; });
1599
-
1600
- };
1601
-
1602
- /**
1603
- * Escapes special characters in a string, preparing it for use in a regular expression.
1604
- *
1605
- * @param string str The string in which special characters should be escaped.
1606
- *
1607
- * @return string Returns the string with escaped special characters.
1608
- *
1609
- * @access private
1610
- */
1611
- var escape_regexp = function(str) {
1612
-
1613
- // return string with special characters escaped
1614
- return str.replace(/([-.,*+?^${}()|[\]\/\\])/g, '\\$1');
1615
-
1616
- };
1617
-
1618
- /**
1619
- * Formats a JavaScript date object to the format specified by the "format" property.
1620
- * Code taken from http://electricprism.com/aeron/calendar/
1621
- *
1622
- * @param date date A valid JavaScript date object
1623
- *
1624
- * @return string Returns a string containing the formatted date
1625
- *
1626
- * @access private
1627
- */
1628
- var format = function(date) {
1629
-
1630
- var result = '',
1631
-
1632
- // extract parts of the date:
1633
- // day number, 1 - 31
1634
- j = date.getDate(),
1635
-
1636
- // day of the week, 0 - 6, Sunday - Saturday
1637
- w = date.getDay(),
1638
-
1639
- // the name of the day of the week Sunday - Saturday
1640
- l = plugin.settings.days[w],
1641
-
1642
- // the month number, 1 - 12
1643
- n = date.getMonth() + 1,
1644
-
1645
- // the month name, January - December
1646
- f = plugin.settings.months[n - 1],
1647
-
1648
- // the year (as a string)
1649
- y = date.getFullYear() + '';
1650
-
1651
- // iterate through the characters in the format
1652
- for (var i = 0; i < plugin.settings.format.length; i++) {
1653
-
1654
- // extract the current character
1655
- var chr = plugin.settings.format.charAt(i);
1656
-
1657
- // see what character it is
1658
- switch(chr) {
1659
-
1660
- // year as two digits
1661
- case 'y': y = y.substr(2);
1662
-
1663
- // year as four digits
1664
- case 'Y': result += y; break;
1665
-
1666
- // month number, prefixed with 0
1667
- case 'm': n = str_pad(n, 2);
1668
-
1669
- // month number, not prefixed with 0
1670
- case 'n': result += n; break;
1671
-
1672
- // month name, three letters
1673
- case 'M': f = ($.isArray(plugin.settings.months_abbr) && undefined !== plugin.settings.months_abbr[n - 1] ? plugin.settings.months_abbr[n - 1] : plugin.settings.months[n - 1].substr(0, 3));
1674
-
1675
- // full month name
1676
- case 'F': result += f; break;
1677
-
1678
- // day number, prefixed with 0
1679
- case 'd': j = str_pad(j, 2);
1680
-
1681
- // day number not prefixed with 0
1682
- case 'j': result += j; break;
1683
-
1684
- // day name, three letters
1685
- case 'D': l = ($.isArray(plugin.settings.days_abbr) && undefined !== plugin.settings.days_abbr[w] ? plugin.settings.days_abbr[w] : plugin.settings.days[w].substr(0, 3));
1686
-
1687
- // full day name
1688
- case 'l': result += l; break;
1689
-
1690
- // ISO-8601 numeric representation of the day of the week, 1 - 7
1691
- case 'N': w++;
1692
-
1693
- // day of the week, 0 - 6
1694
- case 'w': result += w; break;
1695
-
1696
- // English ordinal suffix for the day of the month, 2 characters
1697
- // (st, nd, rd or th (works well with j))
1698
- case 'S':
1699
-
1700
- if (j % 10 == 1 && j != '11') result += 'st';
1701
-
1702
- else if (j % 10 == 2 && j != '12') result += 'nd';
1703
-
1704
- else if (j % 10 == 3 && j != '13') result += 'rd';
1705
-
1706
- else result += 'th';
1707
-
1708
- break;
1709
-
1710
- // this is probably the separator
1711
- default: result += chr;
1712
-
1713
- }
1714
-
1715
- }
1716
-
1717
- // return formated date
1718
- return result;
1719
-
1720
- };
1721
-
1722
- /**
1723
- * Generates the day picker view, and displays it
1724
- *
1725
- * @return void
1726
- *
1727
- * @access private
1728
- */
1729
- var generate_daypicker = function() {
1730
-
1731
- var
1732
-
1733
- // get the number of days in the selected month
1734
- days_in_month = new Date(selected_year, selected_month + 1, 0).getDate(),
1735
-
1736
- // get the selected month's starting day (from 0 to 6)
1737
- first_day = new Date(selected_year, selected_month, 1).getDay(),
1738
-
1739
- // how many days are there in the previous month
1740
- days_in_previous_month = new Date(selected_year, selected_month, 0).getDate(),
1741
-
1742
- // how many days are there to be shown from the previous month
1743
- days_from_previous_month = first_day - plugin.settings.first_day_of_week;
1744
-
1745
- // the final value of how many days are there to be shown from the previous month
1746
- days_from_previous_month = days_from_previous_month < 0 ? 7 + days_from_previous_month : days_from_previous_month;
1747
-
1748
- // manage header caption and enable/disable navigation buttons if necessary
1749
- manage_header(plugin.settings.months[selected_month] + ', ' + selected_year);
1750
-
1751
- // start generating the HTML
1752
- var html = '<tr>';
1753
-
1754
- // if a column featuring the number of the week is to be shown
1755
- if (plugin.settings.show_week_number)
1756
-
1757
- // column title
1758
- html += '<th>' + plugin.settings.show_week_number + '</th>';
1759
-
1760
- // name of week days
1761
- // show the abbreviated day names (or only the first two letters of the full name if no abbreviations are specified)
1762
- // and also, take in account the value of the "first_day_of_week" property
1763
- for (var i = 0; i < 7; i++)
1764
-
1765
- html += '<th>' + ($.isArray(plugin.settings.days_abbr) && undefined !== plugin.settings.days_abbr[(plugin.settings.first_day_of_week + i) % 7] ? plugin.settings.days_abbr[(plugin.settings.first_day_of_week + i) % 7] : plugin.settings.days[(plugin.settings.first_day_of_week + i) % 7].substr(0, 2)) + '</th>';
1766
-
1767
- html += '</tr><tr>';
1768
-
1769
- // the calendar shows a total of 42 days
1770
- for (i = 0; i < 42; i++) {
1771
-
1772
- // seven days per row
1773
- if (i > 0 && i % 7 === 0) html += '</tr><tr>';
1774
-
1775
- // if week number is to be shown
1776
- if (i % 7 === 0 && plugin.settings.show_week_number)
1777
-
1778
- // show ISO 8601 week number
1779
- html += '<td class="dp_week_number">' + getWeekNumber(new Date(selected_year, selected_month, (i - days_from_previous_month + 1))) + '</td>';
1780
-
1781
- // the number of the day in month
1782
- var day = (i - days_from_previous_month + 1);
1783
-
1784
- // if dates in previous/next month can be selected, and this is one of those days
1785
- if (plugin.settings.select_other_months && (i < days_from_previous_month || day > days_in_month)) {
1786
-
1787
- // use the Date object to normalize the date
1788
- // for example, 2011 05 33 will be transformed to 2011 06 02
1789
- var real_date = new Date(selected_year, selected_month, day),
1790
- real_year = real_date.getFullYear(),
1791
- real_month = real_date.getMonth(),
1792
- real_day = real_date.getDate();
1793
-
1794
- // extract normalized date parts and merge them
1795
- real_date = real_year + str_pad(real_month, 2) + str_pad(real_day, 2);
1796
-
1797
- }
1798
-
1799
- // if this is a day from the previous month
1800
- if (i < days_from_previous_month)
1801
-
1802
- html += '<td class="' + (plugin.settings.select_other_months && !is_disabled(real_year, real_month, real_day) ? 'dp_not_in_month_selectable date_' + real_date : 'dp_not_in_month') + '">' + (plugin.settings.select_other_months || plugin.settings.show_other_months ? str_pad(days_in_previous_month - days_from_previous_month + i + 1, plugin.settings.zero_pad ? 2 : 0) : '&nbsp;') + '</td>';
1803
-
1804
- // if this is a day from the next month
1805
- else if (day > days_in_month)
1806
-
1807
- html += '<td class="' + (plugin.settings.select_other_months && !is_disabled(real_year, real_month, real_day) ? 'dp_not_in_month_selectable date_' + real_date : 'dp_not_in_month') + '">' + (plugin.settings.select_other_months || plugin.settings.show_other_months ? str_pad(day - days_in_month, plugin.settings.zero_pad ? 2 : 0) : '&nbsp;') + '</td>';
1808
-
1809
- // if this is a day from the current month
1810
- else {
1811
-
1812
- var
1813
-
1814
- // get the week day (0 to 6, Sunday to Saturday)
1815
- weekday = (plugin.settings.first_day_of_week + i) % 7,
1816
-
1817
- class_name = '';
1818
-
1819
- // if date needs to be disabled
1820
- if (is_disabled(selected_year, selected_month, day)) {
1821
-
1822
- // if day is in weekend
1823
- if ($.inArray(weekday, plugin.settings.weekend_days) > -1) class_name = 'dp_weekend_disabled';
1824
-
1825
- // if work day
1826
- else class_name += ' dp_disabled';
1827
-
1828
- // highlight the current system date
1829
- if (selected_month == current_system_month && selected_year == current_system_year && current_system_day == day) class_name += ' dp_disabled_current';
1830
-
1831
- // if there are no restrictions
1832
- } else {
1833
-
1834
- // if day is in weekend
1835
- if ($.inArray(weekday, plugin.settings.weekend_days) > -1) class_name = 'dp_weekend';
1836
-
1837
- // highlight the currently selected date
1838
- if (selected_month == default_month && selected_year == default_year && default_day == day) class_name += ' dp_selected';
1839
-
1840
- // highlight the current system date
1841
- if (selected_month == current_system_month && selected_year == current_system_year && current_system_day == day) class_name += ' dp_current';
1842
-
1843
- }
1844
-
1845
- // print the day of the month
1846
- html += '<td' + (class_name !== '' ? ' class="' + $.trim(class_name) + '"' : '') + '>' + (plugin.settings.zero_pad ? str_pad(day, 2) : day) + '</td>';
1847
-
1848
- }
1849
-
1850
- }
1851
-
1852
- // wrap up generating the day picker
1853
- html += '</tr>';
1854
-
1855
- // inject the day picker into the DOM
1856
- daypicker.html($(html));
1857
-
1858
- // if date picker is always visible
1859
- if (plugin.settings.always_visible)
1860
-
1861
- // cache all the cells
1862
- // (we need them so that we can easily remove the "dp_selected" class from all of them when user selects a date)
1863
- daypicker_cells = $('td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked, .dp_week_number)', daypicker);
1864
-
1865
- // make the day picker visible
1866
- daypicker.show();
1867
-
1868
- };
1869
-
1870
- /**
1871
- * Generates the month picker view, and displays it
1872
- *
1873
- * @return void
1874
- *
1875
- * @access private
1876
- */
1877
- var generate_monthpicker = function() {
1878
-
1879
- // manage header caption and enable/disable navigation buttons if necessary
1880
- manage_header(selected_year);
1881
-
1882
- // start generating the HTML
1883
- var html = '<tr>';
1884
-
1885
- // iterate through all the months
1886
- for (var i = 0; i < 12; i++) {
1887
-
1888
- // three month per row
1889
- if (i > 0 && i % 3 === 0) html += '</tr><tr>';
1890
-
1891
- var class_name = 'dp_month_' + i;
1892
-
1893
- // if month needs to be disabled
1894
- if (is_disabled(selected_year, i)) class_name += ' dp_disabled';
1895
-
1896
- // else, if a date is already selected and this is that particular month, highlight it
1897
- else if (default_month !== false && default_month == i) class_name += ' dp_selected';
1898
-
1899
- // else, if this the current system month, highlight it
1900
- else if (current_system_month == i && current_system_year == selected_year) class_name += ' dp_current';
1901
-
1902
- // first three letters of the month's name
1903
- html += '<td class="' + $.trim(class_name) + '">' + ($.isArray(plugin.settings.months_abbr) && undefined !== plugin.settings.months_abbr[i] ? plugin.settings.months_abbr[i] : plugin.settings.months[i].substr(0, 3)) + '</td>';
1904
-
1905
- }
1906
-
1907
- // wrap up
1908
- html += '</tr>';
1909
-
1910
- // inject into the DOM
1911
- monthpicker.html($(html));
1912
-
1913
- // if date picker is always visible
1914
- if (plugin.settings.always_visible)
1915
-
1916
- // cache all the cells
1917
- // (we need them so that we can easily remove the "dp_selected" class from all of them when user selects a month)
1918
- monthpicker_cells = $('td:not(.dp_disabled)', monthpicker);
1919
-
1920
- // make the month picker visible
1921
- monthpicker.show();
1922
-
1923
- };
1924
-
1925
- /**
1926
- * Generates the year picker view, and displays it
1927
- *
1928
- * @return void
1929
- *
1930
- * @access private
1931
- */
1932
- var generate_yearpicker = function() {
1933
-
1934
- // manage header caption and enable/disable navigation buttons if necessary
1935
- manage_header(selected_year - 7 + ' - ' + (selected_year + 4));
1936
-
1937
- // start generating the HTML
1938
- var html = '<tr>';
1939
-
1940
- // we're showing 9 years at a time, current year in the middle
1941
- for (var i = 0; i < 12; i++) {
1942
-
1943
- // three years per row
1944
- if (i > 0 && i % 3 === 0) html += '</tr><tr>';
1945
-
1946
- var class_name = '';
1947
-
1948
- // if year needs to be disabled
1949
- if (is_disabled(selected_year - 7 + i)) class_name += ' dp_disabled';
1950
-
1951
- // else, if a date is already selected and this is that particular year, highlight it
1952
- else if (default_year && default_year == selected_year - 7 + i) class_name += ' dp_selected';
1953
-
1954
- // else, if this is the current system year, highlight it
1955
- else if (current_system_year == (selected_year - 7 + i)) class_name += ' dp_current';
1956
-
1957
- // first three letters of the month's name
1958
- html += '<td' + ($.trim(class_name) !== '' ? ' class="' + $.trim(class_name) + '"' : '') + '>' + (selected_year - 7 + i) + '</td>';
1959
-
1960
- }
1961
-
1962
- // wrap up
1963
- html += '</tr>';
1964
-
1965
- // inject into the DOM
1966
- yearpicker.html($(html));
1967
-
1968
- // if date picker is always visible
1969
- if (plugin.settings.always_visible)
1970
-
1971
- // cache all the cells
1972
- // (we need them so that we can easily remove the "dp_selected" class from all of them when user selects a year)
1973
- yearpicker_cells = $('td:not(.dp_disabled)', yearpicker);
1974
-
1975
- // make the year picker visible
1976
- yearpicker.show();
1977
-
1978
- };
1979
-
1980
- /**
1981
- * Generates an iFrame shim in Internet Explorer 6 so that the date picker appears above select boxes.
1982
- *
1983
- * @return void
1984
- *
1985
- * @access private
1986
- */
1987
- var iframeShim = function(action) {
1988
-
1989
- // this is necessary only if browser is Internet Explorer 6
1990
- if (browser.name == 'explorer' && browser.version == 6) {
1991
-
1992
- // if the iFrame was not yet created
1993
- // "undefined" evaluates as FALSE
1994
- if (!shim) {
1995
-
1996
- // the iFrame has to have the element's zIndex minus 1
1997
- var zIndex = to_int(datepicker.css('zIndex')) - 1;
1998
-
1999
- // create the iFrame
2000
- shim = jQuery('<iframe>', {
2001
- 'src': 'javascript:document.write("")',
2002
- 'scrolling': 'no',
2003
- 'frameborder': 0,
2004
- 'allowtransparency': 'true',
2005
- css: {
2006
- 'zIndex': zIndex,
2007
- 'position': 'absolute',
2008
- 'top': -1000,
2009
- 'left': -1000,
2010
- 'width': datepicker.outerWidth(),
2011
- 'height': datepicker.outerHeight(),
2012
- 'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)',
2013
- 'display': 'none'
2014
- }
2015
- });
2016
-
2017
- // inject iFrame into DOM
2018
- $('body').append(shim);
2019
-
2020
- }
2021
-
2022
- // what do we need to do
2023
- switch (action) {
2024
-
2025
- // hide the iFrame?
2026
- case 'hide':
2027
-
2028
- // set the iFrame's display property to "none"
2029
- shim.hide();
2030
-
2031
- break;
2032
-
2033
- // show the iFrame?
2034
- default:
2035
-
2036
- // get date picker top and left position
2037
- var offset = datepicker.offset();
2038
-
2039
- // position the iFrame shim right underneath the date picker
2040
- // and set its display to "block"
2041
- shim.css({
2042
- 'top': offset.top,
2043
- 'left': offset.left,
2044
- 'display': 'block'
2045
- });
2046
-
2047
- }
2048
-
2049
- }
2050
-
2051
- };
2052
-
2053
- /**
2054
- * Checks if, according to the restrictions of the calendar and/or the values defined by the "disabled_dates"
2055
- * property, a day, a month or a year needs to be disabled.
2056
- *
2057
- * @param integer year The year to check
2058
- * @param integer month The month to check
2059
- * @param integer day The day to check
2060
- *
2061
- * @return boolean Returns TRUE if the given value is not disabled or FALSE otherwise
2062
- *
2063
- * @access private
2064
- */
2065
- var is_disabled = function(year, month, day) {
2066
-
2067
- // don't check bogus values
2068
- if ((undefined === year || isNaN(year)) && (undefined === month || isNaN(month)) && (undefined === day || isNaN(day))) return false;
2069
-
2070
- // if calendar has direction restrictions
2071
- if (!(!$.isArray(plugin.settings.direction) && to_int(plugin.settings.direction) === 0)) {
2072
-
2073
- var
2074
- // normalize and merge arguments then transform the result to an integer
2075
- now = to_int(str_concat(year, (typeof month != 'undefined' ? str_pad(month, 2) : ''), (typeof day != 'undefined' ? str_pad(day, 2) : ''))),
2076
-
2077
- // get the length of the argument
2078
- len = (now + '').length;
2079
-
2080
- // if we're checking days
2081
- if (len == 8 && (
2082
-
2083
- // day is before the first selectable date
2084
- (typeof start_date != 'undefined' && now < to_int(str_concat(first_selectable_year, str_pad(first_selectable_month, 2), str_pad(first_selectable_day, 2)))) ||
2085
-
2086
- // or day is after the last selectable date
2087
- (typeof end_date != 'undefined' && now > to_int(str_concat(last_selectable_year, str_pad(last_selectable_month, 2), str_pad(last_selectable_day, 2))))
2088
-
2089
- // day needs to be disabled
2090
- )) return true;
2091
-
2092
- // if we're checking months
2093
- else if (len == 6 && (
2094
-
2095
- // month is before the first selectable month
2096
- (typeof start_date != 'undefined' && now < to_int(str_concat(first_selectable_year, str_pad(first_selectable_month, 2)))) ||
2097
-
2098
- // or day is after the last selectable date
2099
- (typeof end_date != 'undefined' && now > to_int(str_concat(last_selectable_year, str_pad(last_selectable_month, 2))))
2100
-
2101
- // month needs to be disabled
2102
- )) return true;
2103
-
2104
- // if we're checking years
2105
- else if (len == 4 && (
2106
-
2107
- // year is before the first selectable year
2108
- (typeof start_date != 'undefined' && now < first_selectable_year) ||
2109
-
2110
- // or day is after the last selectable date
2111
- (typeof end_date != 'undefined' && now > last_selectable_year)
2112
-
2113
- // year needs to be disabled
2114
- )) return true;
2115
-
2116
- }
2117
-
2118
- // if month is given as argument, increment it (as JavaScript uses 0 for January, 1 for February...)
2119
- if (typeof month != 'undefined') month = month + 1;
2120
-
2121
- // by default, we assume the day/month/year is not enabled nor disabled
2122
- var disabled = false, enabled = false;
2123
-
2124
- // if there are rules for disabling dates
2125
- if (disabled_dates)
2126
-
2127
- // iterate through the rules for disabling dates
2128
- $.each(disabled_dates, function() {
2129
-
2130
- // if the date is to be disabled, don't look any further
2131
- if (disabled) return;
2132
-
2133
- var rule = this;
2134
-
2135
- // if the rules apply for the current year
2136
- if ($.inArray(year, rule[2]) > -1 || $.inArray('*', rule[2]) > -1)
2137
-
2138
- // if the rules apply for the current month
2139
- if ((typeof month != 'undefined' && $.inArray(month, rule[1]) > -1) || $.inArray('*', rule[1]) > -1)
2140
-
2141
- // if the rules apply for the current day
2142
- if ((typeof day != 'undefined' && $.inArray(day, rule[0]) > -1) || $.inArray('*', rule[0]) > -1) {
2143
-
2144
- // if day is to be disabled whatever the day
2145
- // don't look any further
2146
- if (rule[3] == '*') return (disabled = true);
2147
-
2148
- // get the weekday
2149
- var weekday = new Date(year, month - 1, day).getDay();
2150
-
2151
- // if weekday is to be disabled
2152
- // don't look any further
2153
- if ($.inArray(weekday, rule[3]) > -1) return (disabled = true);
2154
-
2155
- }
2156
-
2157
- });
2158
-
2159
- // if there are rules that explicitly enable dates
2160
- if (enabled_dates)
2161
-
2162
- // iterate through the rules for enabling dates
2163
- $.each(enabled_dates, function() {
2164
-
2165
- // if the date is to be enabled, don't look any further
2166
- if (enabled) return;
2167
-
2168
- var rule = this;
2169
-
2170
- // if the rules apply for the current year
2171
- if ($.inArray(year, rule[2]) > -1 || $.inArray('*', rule[2]) > -1) {
2172
-
2173
- // the year is enabled
2174
- enabled = true;
2175
-
2176
- // if we're also checking months
2177
- if (typeof month != 'undefined') {
2178
-
2179
- // we assume the month is enabled
2180
- enabled = true;
2181
-
2182
- // if the rules apply for the current month
2183
- if ($.inArray(month, rule[1]) > -1 || $.inArray('*', rule[1]) > -1) {
2184
-
2185
- // if we're also checking days
2186
- if (typeof day != 'undefined') {
2187
-
2188
- // we assume the day is enabled
2189
- enabled = true;
2190
-
2191
- // if the rules apply for the current day
2192
- if ($.inArray(day, rule[0]) > -1 || $.inArray('*', rule[0]) > -1) {
2193
-
2194
- // if day is to be enabled whatever the day
2195
- // don't look any further
2196
- if (rule[3] == '*') return (enabled = true);
2197
-
2198
- // get the weekday
2199
- var weekday = new Date(year, month - 1, day).getDay();
2200
-
2201
- // if weekday is to be enabled
2202
- // don't look any further
2203
- if ($.inArray(weekday, rule[3]) > -1) return (enabled = true);
2204
-
2205
- // if we get this far, it means the day is not enabled
2206
- enabled = false;
2207
-
2208
- // if day is not enabled
2209
- } else enabled = false;
2210
-
2211
- }
2212
-
2213
- // if month is not enabled
2214
- } else enabled = false;
2215
-
2216
- }
2217
-
2218
- }
2219
-
2220
- });
2221
-
2222
- // if checked date is enabled, return false
2223
- if (enabled_dates && enabled) return false;
2224
-
2225
- // if checked date is disabled return false
2226
- else if (disabled_dates && disabled) return true;
2227
-
2228
- // if script gets this far it means that the day/month/year doesn't need to be disabled
2229
- return false;
2230
-
2231
- };
2232
-
2233
- /**
2234
- * Checks whether a value is an integer number.
2235
- *
2236
- * @param mixed value Value to check
2237
- *
2238
- * @return Returns TRUE if the value represents an integer number, or FALSE otherwise
2239
- *
2240
- * @access private
2241
- */
2242
- var is_integer = function(value) {
2243
-
2244
- // return TRUE if value represents an integer number, or FALSE otherwise
2245
- return (value + '').match(/^\-?[0-9]+$/) ? true : false;
2246
-
2247
- };
2248
-
2249
- /**
2250
- * Sets the caption in the header of the date picker and enables or disables navigation buttons when necessary.
2251
- *
2252
- * @param string caption String that needs to be displayed in the header
2253
- *
2254
- * @return void
2255
- *
2256
- * @access private
2257
- */
2258
- var manage_header = function(caption) {
2259
-
2260
- // update the caption in the header
2261
- $('.dp_caption', header).html(caption);
2262
-
2263
- // if calendar has direction restrictions or we're looking only at months
2264
- if (!(!$.isArray(plugin.settings.direction) && to_int(plugin.settings.direction) === 0) || (views.length == 1 && views[0] == 'months')) {
2265
-
2266
- // get the current year and month
2267
- var year = selected_year,
2268
- month = selected_month,
2269
- next, previous;
2270
-
2271
- // if current view is showing days
2272
- if (view == 'days') {
2273
-
2274
- // check if we can click on the "previous" button
2275
- previous = !is_disabled(month - 1 < 0 ? str_concat(year - 1, '11') : str_concat(year, str_pad(month - 1, 2)));
2276
-
2277
- // check if we can click on the "next" button
2278
- next = !is_disabled(month + 1 > 11 ? str_concat(year + 1, '00') : str_concat(year, str_pad(month + 1, 2)));
2279
-
2280
- // if current view is showing months
2281
- } else if (view == 'months') {
2282
-
2283
- // check if we can click on the "previous" button
2284
- if (!start_date || start_date.getFullYear() <= year - 1) previous = true;
2285
-
2286
- // check if we can click on the "next" button
2287
- if (!end_date || end_date.getFullYear() >= year + 1) next = true;
2288
-
2289
- // if current view is showing years
2290
- } else if (view == 'years') {
2291
-
2292
- // check if we can click on the "previous" button
2293
- if (!start_date || start_date.getFullYear() < year - 7) previous = true;
2294
-
2295
- // check if we can click on the "next" button
2296
- if (!end_date || end_date.getFullYear() > year + 4) next = true;
2297
-
2298
- }
2299
-
2300
- // if we cannot click on the "previous" button
2301
- if (!previous) {
2302
-
2303
- // disable the "previous" button
2304
- $('.dp_previous', header).addClass('dp_blocked');
2305
- $('.dp_previous', header).removeClass('dp_hover');
2306
-
2307
- // otherwise enable the "previous" button
2308
- } else $('.dp_previous', header).removeClass('dp_blocked');
2309
-
2310
- // if we cannot click on the "next" button
2311
- if (!next) {
2312
-
2313
- // disable the "next" button
2314
- $('.dp_next', header).addClass('dp_blocked');
2315
- $('.dp_next', header).removeClass('dp_hover');
2316
-
2317
- // otherwise enable the "next" button
2318
- } else $('.dp_next', header).removeClass('dp_blocked');
2319
-
2320
- }
2321
-
2322
- };
2323
-
2324
- /**
2325
- * Shows the appropriate view (days, months or years) according to the current value of the "view" property.
2326
- *
2327
- * @return void
2328
- *
2329
- * @access private
2330
- */
2331
- var manage_views = function() {
2332
-
2333
- // if the day picker was not yet generated
2334
- if (daypicker.text() === '' || view == 'days') {
2335
-
2336
- // if the day picker was not yet generated
2337
- if (daypicker.text() === '') {
2338
-
2339
- // if date picker is not always visible
2340
- if (!plugin.settings.always_visible)
2341
-
2342
- // temporarily set the date picker's left outside of view
2343
- // so that we can later grab its width and height
2344
- datepicker.css('left', -1000);
2345
-
2346
- // temporarily make the date picker visible
2347
- // so that we can later grab its width and height
2348
- datepicker.show();
2349
-
2350
- // generate the day picker
2351
- generate_daypicker();
2352
-
2353
- // get the day picker's width and height
2354
- var width = daypicker.outerWidth(),
2355
- height = daypicker.outerHeight();
2356
-
2357
- // make the month picker have the same size as the day picker
2358
- monthpicker.css({
2359
- 'width': width,
2360
- 'height': height
2361
- });
2362
-
2363
- // make the year picker have the same size as the day picker
2364
- yearpicker.css({
2365
- 'width': width,
2366
- 'height': height
2367
- });
2368
-
2369
- // make the header and the footer have the same size as the day picker
2370
- header.css('width', width);
2371
- footer.css('width', width);
2372
-
2373
- // hide the date picker again
2374
- datepicker.hide();
2375
-
2376
- // if the day picker was previously generated at least once
2377
- // generate the day picker
2378
- } else generate_daypicker();
2379
-
2380
- // hide the year and the month pickers
2381
- monthpicker.hide();
2382
- yearpicker.hide();
2383
-
2384
- // if the view is "months"
2385
- } else if (view == 'months') {
2386
-
2387
- // generate the month picker
2388
- generate_monthpicker();
2389
-
2390
- // hide the day and the year pickers
2391
- daypicker.hide();
2392
- yearpicker.hide();
2393
-
2394
- // if the view is "years"
2395
- } else if (view == 'years') {
2396
-
2397
- // generate the year picker
2398
- generate_yearpicker();
2399
-
2400
- // hide the day and the month pickers
2401
- daypicker.hide();
2402
- monthpicker.hide();
2403
-
2404
- }
2405
-
2406
- // if a callback function exists for when navigating through months/years
2407
- if (plugin.settings.onChange && typeof plugin.settings.onChange == 'function' && undefined !== view) {
2408
-
2409
- // get the "active" elements in the view (ignoring the disabled ones)
2410
- var elements = (view == 'days' ?
2411
- daypicker.find('td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked)') :
2412
- (view == 'months' ?
2413
- monthpicker.find('td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked)') :
2414
- yearpicker.find('td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked)')));
2415
-
2416
- // iterate through the active elements
2417
- // and attach a "date" data attribute to each element in the form of
2418
- // YYYY-MM-DD if the view is "days"
2419
- // YYYY-MM if the view is "months"
2420
- // YYYY if the view is "years"
2421
- // so it's easy to identify elements in the list
2422
- elements.each(function() {
2423
-
2424
- // if view is "days"
2425
- if (view == 'days')
2426
-
2427
- // attach a "date" data attribute to each element in the form of of YYYY-MM-DD for easily identifying sought elements
2428
- $(this).data('date', selected_year + '-' + str_pad(selected_month + 1, 2) + '-' + str_pad(to_int($(this).text()), 2));
2429
-
2430
- // if view is "months"
2431
- else if (view == 'months') {
2432
-
2433
- // get the month's number for the element's class
2434
- var matches = $(this).attr('class').match(/dp\_month\_([0-9]+)/);
2435
-
2436
- // attach a "date" data attribute to each element in the form of of YYYY-MM for easily identifying sought elements
2437
- $(this).data('date', selected_year + '-' + str_pad(to_int(matches[1]) + 1, 2));
2438
-
2439
- // if view is "years"
2440
- } else
2441
-
2442
- // attach a "date" data attribute to each element in the form of of YYYY for easily identifying sought elements
2443
- $(this).data('date', to_int($(this).text()));
2444
-
2445
- });
2446
-
2447
- // execute the callback function and send as arguments the current view, the elements in the view, and
2448
- // the element the plugin is attached to
2449
- plugin.settings.onChange(view, elements, $element);
2450
-
2451
- }
2452
-
2453
- // assume the footer is visible
2454
- footer.show();
2455
-
2456
- // if the button for clearing a previously selected date needs to be visible all the time,
2457
- // or the "Clear" button needs to be shown only when a date was previously selected, and now it's the case,
2458
- // or the date picker is always visible and the "Clear" button was not explicitly disabled
2459
- if (
2460
- plugin.settings.show_clear_date === true ||
2461
- (plugin.settings.show_clear_date === 0 && $element.val() !== '') ||
2462
- (plugin.settings.always_visible && plugin.settings.show_clear_date !== false)
2463
- ) {
2464
-
2465
- // show the "Clear" button
2466
- cleardate.show();
2467
-
2468
- // if the "Today" button is visible
2469
- if (show_select_today) {
2470
-
2471
- // show it, and set it's width to 50% of the available space
2472
- selecttoday.css('width', '50%');
2473
-
2474
- // the "Clear date" button only takes up 50% of the available space
2475
- cleardate.css('width', '50%');
2476
-
2477
- // if the "Today" button is not visible
2478
- } else {
2479
-
2480
- // hide the "Today" button
2481
- selecttoday.hide();
2482
-
2483
- // the "Clear date" button takes up 100% of the available space
2484
- cleardate.css('width', '100%');
2485
-
2486
- }
2487
-
2488
- // otherwise
2489
- } else {
2490
-
2491
- // hide the "Clear" button
2492
- cleardate.hide();
2493
-
2494
- // if the "Today" button is visible, it will now take up all the available space
2495
- if (show_select_today) selecttoday.show().css('width', '100%');
2496
-
2497
- // if the "Today" button is also not visible, hide the footer entirely
2498
- else footer.hide();
2499
-
2500
- }
2501
-
2502
-
2503
- };
2504
-
2505
- /**
2506
- * Puts the specified date in the element the plugin is attached to, and hides the date picker.
2507
- *
2508
- * @param integer year The year
2509
- *
2510
- * @param integer month The month
2511
- *
2512
- * @param integer day The day
2513
- *
2514
- * @param string view The view from where the method was called
2515
- *
2516
- * @param object cell The element that was clicked
2517
- *
2518
- * @return void
2519
- *
2520
- * @access private
2521
- */
2522
- var select_date = function(year, month, day, view, cell) {
2523
-
2524
- var
2525
-
2526
- // construct a new date object from the arguments
2527
- default_date = new Date(year, month, day, 12, 0, 0),
2528
-
2529
- // pointer to the cells in the current view
2530
- view_cells = (view == 'days' ? daypicker_cells : (view == 'months' ? monthpicker_cells : yearpicker_cells)),
2531
-
2532
- // the selected date, formatted correctly
2533
- selected_value = format(default_date);
2534
-
2535
- // set the currently selected and formated date as the value of the element the plugin is attached to
2536
- $element.val(selected_value);
2537
-
2538
- // if date picker is always visible
2539
- if (plugin.settings.always_visible) {
2540
-
2541
- // extract the date parts and reassign values to these variables
2542
- // so that everything will be correctly highlighted
2543
- default_month = default_date.getMonth();
2544
- selected_month = default_date.getMonth();
2545
- default_year = default_date.getFullYear();
2546
- selected_year = default_date.getFullYear();
2547
- default_day = default_date.getDate();
2548
-
2549
- // remove the "selected" class from all cells in the current view
2550
- view_cells.removeClass('dp_selected');
2551
-
2552
- // add the "selected" class to the currently selected cell
2553
- cell.addClass('dp_selected');
2554
-
2555
- }
2556
-
2557
- // hide the date picker
2558
- plugin.hide();
2559
-
2560
- // updates value for the date picker whose starting date depends on the selected date (if any)
2561
- update_dependent(default_date);
2562
-
2563
- // if a callback function exists for when selecting a date
2564
- if (plugin.settings.onSelect && typeof plugin.settings.onSelect == 'function')
2565
-
2566
- // execute the callback function
2567
- plugin.settings.onSelect(selected_value, year + '-' + str_pad(month + 1, 2) + '-' + str_pad(day, 2), default_date, $element);
2568
-
2569
- // move focus to the element the plugin is attached to
2570
- $element.focus();
2571
-
2572
- };
2573
-
2574
- /**
2575
- * Concatenates any number of arguments and returns them as string.
2576
- *
2577
- * @return string Returns the concatenated values.
2578
- *
2579
- * @access private
2580
- */
2581
- var str_concat = function() {
2582
-
2583
- var str = '';
2584
-
2585
- // concatenate as string
2586
- for (var i = 0; i < arguments.length; i++) str += (arguments[i] + '');
2587
-
2588
- // return the concatenated values
2589
- return str;
2590
-
2591
- };
2592
-
2593
- /**
2594
- * Left-pad a string to a certain length with zeroes.
2595
- *
2596
- * @param string str The string to be padded.
2597
- *
2598
- * @param integer len The length to which the string must be padded
2599
- *
2600
- * @return string Returns the string left-padded with leading zeroes
2601
- *
2602
- * @access private
2603
- */
2604
- var str_pad = function(str, len) {
2605
-
2606
- // make sure argument is a string
2607
- str += '';
2608
-
2609
- // pad with leading zeroes until we get to the desired length
2610
- while (str.length < len) str = '0' + str;
2611
-
2612
- // return padded string
2613
- return str;
2614
-
2615
- };
2616
-
2617
- /**
2618
- * Returns the integer representation of a string
2619
- *
2620
- * @return int Returns the integer representation of the string given as argument
2621
- *
2622
- * @access private
2623
- */
2624
- var to_int = function(str) {
2625
-
2626
- // return the integer representation of the string given as argument
2627
- return parseInt(str , 10);
2628
-
2629
- };
2630
-
2631
- /**
2632
- * Updates the paired date picker (whose starting date depends on the value of the current date picker)
2633
- *
2634
- * @param date date A JavaScript date object representing the currently selected date
2635
- *
2636
- * @return void
2637
- *
2638
- * @access private
2639
- */
2640
- var update_dependent = function(date) {
2641
-
2642
- // if the pair element exists
2643
- if (plugin.settings.pair) {
2644
-
2645
- // iterate through the pair elements (as there may be more than just one)
2646
- $.each(plugin.settings.pair, function() {
2647
-
2648
- var $pair = $(this);
2649
-
2650
- // chances are that in the beginning the pair element doesn't have the Zebra_DatePicker attached to it yet
2651
- // (as the "start" element is usually created before the "end" element)
2652
- // so we'll have to rely on "data" to send the starting date to the pair element
2653
-
2654
- // therefore, if Zebra_DatePicker is not yet attached
2655
- if (!($pair.data && $pair.data('Zebra_DatePicker')))
2656
-
2657
- // set the starting date like this
2658
- $pair.data('zdp_reference_date', date);
2659
-
2660
- // if Zebra_DatePicker is attached to the pair element
2661
- else {
2662
-
2663
- // reference the date picker object attached to the other element
2664
- var dp = $pair.data('Zebra_DatePicker');
2665
-
2666
- // update the other date picker's starting date
2667
- // the value depends on the original value of the "direction" attribute
2668
- // (also, if the pair date picker does not have a direction, set it to 1)
2669
- dp.update({
2670
- 'reference_date': date,
2671
- 'direction': dp.settings.direction === 0 ? 1 : dp.settings.direction
2672
- });
2673
-
2674
- // if the other date picker is always visible, update the visuals now
2675
- if (dp.settings.always_visible) dp.show();
2676
-
2677
- }
2678
-
2679
- });
2680
-
2681
- }
2682
-
2683
- };
2684
-
2685
- /**
2686
- * Calculate the ISO 8601 week number for a given date.
2687
- *
2688
- * Code is based on the algorithm at http://www.tondering.dk/claus/cal/week.php#calcweekno
2689
- */
2690
- var getWeekNumber = function(date) {
2691
-
2692
- var y = date.getFullYear(),
2693
- m = date.getMonth() + 1,
2694
- d = date.getDate(),
2695
- a, b, c, s, e, f, g, n, w;
2696
-
2697
- // If month jan. or feb.
2698
- if (m < 3) {
2699
-
2700
- a = y - 1;
2701
- b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
2702
- c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
2703
- s = b - c;
2704
- e = 0;
2705
- f = d - 1 + 31 * (m - 1);
2706
-
2707
- // If month mar. through dec.
2708
- } else {
2709
-
2710
- a = y;
2711
- b = (a / 4 | 0) - (a / 100 | 0) + (a / 400 | 0);
2712
- c = ((a - 1) / 4 | 0) - ((a - 1) / 100 | 0) + ((a - 1) / 400 | 0);
2713
- s = b - c;
2714
- e = s + 1;
2715
- f = d + ((153 * (m - 3) + 2) / 5 | 0) + 58 + s;
2716
-
2717
- }
2718
-
2719
- g = (a + b) % 7;
2720
- // ISO Weekday (0 is monday, 1 is tuesday etc.)
2721
- d = (f + g - e) % 7;
2722
- n = f + 3 - d;
2723
-
2724
- if (n < 0) w = 53 - ((g - s) / 5 | 0);
2725
-
2726
- else if (n > 364 + s) w = 1;
2727
-
2728
- else w = (n / 7 | 0) + 1;
2729
-
2730
- return w;
2731
-
2732
- };
2733
-
2734
- /**
2735
- * Function to be called when the "onKeyUp" event occurs
2736
- *
2737
- * Why as a separate function and not inline when binding the event? Because only this way we can "unbind" it
2738
- * if the date picker is destroyed
2739
- *
2740
- * @return void
2741
- *
2742
- * @access private
2743
- */
2744
- var _keyup = function(e) {
2745
-
2746
- // if the date picker is visible
2747
- // and the pressed key is ESC
2748
- // hide the date picker
2749
- if (datepicker.css('display') == 'block' || e.which == 27) plugin.hide();
2750
-
2751
- };
2752
-
2753
- /**
2754
- * Function to be called when the "onMouseDown" event occurs
2755
- *
2756
- * Why as a separate function and not inline when binding the event? Because only this way we can "unbind" it
2757
- * if the date picker is destroyed
2758
- *
2759
- * @return void
2760
- *
2761
- * @access private
2762
- */
2763
- var _mousedown = function(e) {
2764
-
2765
- // if the date picker is visible
2766
- if (datepicker.css('display') == 'block') {
2767
-
2768
- // if the calendar icon is visible and we clicked it, let the onClick event of the icon to handle the event
2769
- // (we want it to toggle the date picker)
2770
- if (plugin.settings.show_icon && $(e.target).get(0) === icon.get(0)) return true;
2771
-
2772
- // if what's clicked is not inside the date picker
2773
- // hide the date picker
2774
- if ($(e.target).parents().filter('.Zebra_DatePicker').length === 0) plugin.hide();
2775
-
2776
- }
2777
-
2778
- };
2779
-
2780
- /**
2781
- * Function to be called when the "onResize" event occurs
2782
- *
2783
- * Why as a separate function and not inline when binding the event? Because only this way we can "unbind" it
2784
- * if the date picker is destroyed
2785
- *
2786
- * @return void
2787
- *
2788
- * @access private
2789
- */
2790
- var _resize = function() {
2791
-
2792
- // hide the date picker
2793
- plugin.hide();
2794
-
2795
- // we use timeouts so that we do not call the "update" method on *every* step of the resize event
2796
-
2797
- // clear a previously set timeout
2798
- clearTimeout(timeout);
2799
-
2800
- // set timeout again
2801
- timeout = setTimeout(function() {
2802
-
2803
- // update the date picker
2804
- plugin.update();
2805
-
2806
- }, 100);
2807
-
2808
- };
2809
-
2810
- // since with jQuery 1.9.0 the $.browser object was removed, we rely on this piece of code from
2811
- // http://www.quirksmode.org/js/detect.html to detect the browser
2812
- var browser = {
2813
- init: function () {
2814
- this.name = this.searchString(this.dataBrowser) || '';
2815
- this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || '';
2816
- },
2817
- searchString: function (data) {
2818
- for (var i=0;i<data.length;i++) {
2819
- var dataString = data[i].string;
2820
- var dataProp = data[i].prop;
2821
- this.versionSearchString = data[i].versionSearch || data[i].identity;
2822
- if (dataString) {
2823
- if (dataString.indexOf(data[i].subString) != -1)
2824
- return data[i].identity;
2825
- }
2826
- else if (dataProp)
2827
- return data[i].identity;
2828
- }
2829
- },
2830
- searchVersion: function (dataString) {
2831
- var index = dataString.indexOf(this.versionSearchString);
2832
- if (index == -1) return;
2833
- return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
2834
- },
2835
- dataBrowser: [
2836
- {
2837
- string: navigator.userAgent,
2838
- subString: 'Firefox',
2839
- identity: 'firefox'
2840
- },
2841
- {
2842
- string: navigator.userAgent,
2843
- subString: 'MSIE',
2844
- identity: 'explorer',
2845
- versionSearch: 'MSIE'
2846
- }
2847
- ]
2848
- };
2849
-
2850
- browser.init();
2851
-
2852
- // initialize the plugin
2853
- init();
2854
-
2855
- };
2856
-
2857
- $.fn.Zebra_DatePicker = function(options) {
2858
-
2859
- // iterate through all the elements to which we need to attach the date picker to
2860
- return this.each(function() {
2861
-
2862
- // if element has a date picker already attached
2863
- if (undefined !== $(this).data('Zebra_DatePicker'))
2864
-
2865
- // remove the attached date picker
2866
- $(this).data('Zebra_DatePicker').destroy();
2867
-
2868
- // create an instance of the plugin
2869
- var plugin = new $.Zebra_DatePicker(this, options);
2870
-
2871
- // save a reference to the newly created object
2872
- $(this).data('Zebra_DatePicker', plugin);
2873
-
2874
- });
2875
-
2876
- };
2877
-
2878
- })(jQuery);
1
+ (function(c){c.Zebra_DatePicker=function(ga,ha){var ka={always_visible:!1,days:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),days_abbr:!1,direction:0,disabled_dates:!1,enabled_dates:!1,first_day_of_week:1,format:"Y-m-d",header_navigation:["&#171;","&#187;"],inside:!0,lang_clear_date:"Clear date",months:"January February March April May June July August September October November December".split(" "),months_abbr:!1,offset:[5,-5],pair:!1,readonly_element:!0,select_other_months:!1, show_clear_date:0,show_icon:!0,show_other_months:!0,show_select_today:"Today",show_week_number:!1,start_date:!1,strict:!1,view:"days",weekend_days:[0,6],zero_pad:!1,onChange:null,onClear:null,onSelect:null},t,h,w,C,D,G,H,S,T,N,Z,g,q,y,u,p,U,J,K,V,F,$,r,v,aa,O,W,la,ma,na,A,ia,ba,X,ca,oa,a=this;a.settings={};var d=c(ga),ra=function(e){if(!e){a.settings=c.extend({},ka,ha);for(var b in d.data())0===b.indexOf("zdp_")&&(b=b.replace(/^zdp\_/,""),void 0!==ka[b]&&(a.settings[b]=d.data("zdp_"+b)))}a.settings.readonly_element&& d.attr("readonly","readonly");b={days:["d","j","D"],months:["F","m","M","n","t"],years:["o","Y","y"]};var z=!1,f=!1,k=!1,E=null;for(E in b)c.each(b[E],function(c,b){-1<a.settings.format.indexOf(b)&&("days"==E?z=!0:"months"==E?f=!0:"years"==E&&(k=!0))});A=z&&f&&k?["years","months","days"]:!z&&f&&k?["years","months"]:z||f||!k?z||!f||k?["years","months","days"]:["months"]:["years"];-1==c.inArray(a.settings.view,A)&&(a.settings.view=A[A.length-1]);F=[];V=[];for(var n=0;2>n;n++)b=0===n?a.settings.disabled_dates: a.settings.enabled_dates,c.isArray(b)&&0<b.length&&c.each(b,function(){for(var a=this.split(" "),b=0;4>b;b++){a[b]||(a[b]="*");a[b]=-1<a[b].indexOf(",")?a[b].split(","):Array(a[b]);for(var e=0;e<a[b].length;e++)if(-1<a[b][e].indexOf("-")){var z=a[b][e].match(/^([0-9]+)\-([0-9]+)/);if(null!==z){for(var f=s(z[1]);f<=s(z[2]);f++)-1==c.inArray(f,a[b])&&a[b].push(f+"");a[b].splice(e,1)}}for(e=0;e<a[b].length;e++)a[b][e]=isNaN(s(a[b][e]))?a[b][e]:s(a[b][e])}0===n?F.push(a):V.push(a)});b=new Date;var m= a.settings.reference_date?a.settings.reference_date:d.data("zdp_reference_date")&&void 0!==d.data("zdp_reference_date")?d.data("zdp_reference_date"):b,l,L;v=r=void 0;g=m.getMonth();T=b.getMonth();q=m.getFullYear();N=b.getFullYear();y=m.getDate();Z=b.getDate();if(!0===a.settings.direction)r=m;else if(!1===a.settings.direction)v=m,W=v.getMonth(),O=v.getFullYear(),aa=v.getDate();else if(!c.isArray(a.settings.direction)&&Y(a.settings.direction)&&0<s(a.settings.direction)||c.isArray(a.settings.direction)&& ((l=da(a.settings.direction[0]))||!0===a.settings.direction[0]||Y(a.settings.direction[0])&&0<a.settings.direction[0])&&((L=da(a.settings.direction[1]))||!1===a.settings.direction[1]||Y(a.settings.direction[1])&&0<=a.settings.direction[1]))r=l?l:new Date(q,g,y+(c.isArray(a.settings.direction)?s(!0===a.settings.direction[0]?0:a.settings.direction[0]):s(a.settings.direction))),g=r.getMonth(),q=r.getFullYear(),y=r.getDate(),L&&+L>=+r?v=L:!L&&!1!==a.settings.direction[1]&&c.isArray(a.settings.direction)&& (v=new Date(q,g,y+s(a.settings.direction[1]))),v&&(W=v.getMonth(),O=v.getFullYear(),aa=v.getDate());else if(!c.isArray(a.settings.direction)&&Y(a.settings.direction)&&0>s(a.settings.direction)||c.isArray(a.settings.direction)&&(!1===a.settings.direction[0]||Y(a.settings.direction[0])&&0>a.settings.direction[0])&&((l=da(a.settings.direction[1]))||Y(a.settings.direction[1])&&0<=a.settings.direction[1]))v=new Date(q,g,y+(c.isArray(a.settings.direction)?s(!1===a.settings.direction[0]?0:a.settings.direction[0]): s(a.settings.direction))),W=v.getMonth(),O=v.getFullYear(),aa=v.getDate(),l&&+l<+v?r=l:!l&&c.isArray(a.settings.direction)&&(r=new Date(O,W,aa-s(a.settings.direction[1]))),r&&(g=r.getMonth(),q=r.getFullYear(),y=r.getDate());else if(c.isArray(a.settings.disabled_dates)&&0<a.settings.disabled_dates.length)for(var P in F)if("*"==F[P][0]&&"*"==F[P][1]&&"*"==F[P][2]&&"*"==F[P][3]){var fa=[];c.each(V,function(){"*"!=this[2][0]&&fa.push(parseInt(this[2][0]+("*"==this[1][0]?"12":x(this[1][0],2))+("*"==this[0][0]? "*"==this[1][0]?"31":(new Date(this[2][0],this[1][0],0)).getDate():x(this[0][0],2)),10))});fa.sort();if(0<fa.length){var Q=(fa[0]+"").match(/([0-9]{4})([0-9]{2})([0-9]{2})/);q=parseInt(Q[1],10);g=parseInt(Q[2],10)-1;y=parseInt(Q[3],10)}break}if(B(q,g,y)){for(;B(q);)r?(q++,g=0):(q--,g=11);for(;B(q,g);)r?(g++,y=1):(g--,y=(new Date(q,g+1,0)).getDate()),11<g?(q++,g=0,y=1):0>g&&(q--,g=11,y=(new Date(q,g+1,0)).getDate());for(;B(q,g,y);)r?y++:y--,b=new Date(q,g,y),q=b.getFullYear(),g=b.getMonth(),y=b.getDate(); b=new Date(q,g,y);q=b.getFullYear();g=b.getMonth();y=b.getDate()}(l=da(d.val()||(a.settings.start_date?a.settings.start_date:"")))&&a.settings.strict&&B(l.getFullYear(),l.getMonth(),l.getDate())&&d.val("");e||pa(r);if(!a.settings.always_visible&&(e||(a.settings.show_icon?("firefox"==M.name&&d.is('input[type="text"]')&&"inline"==d.css("display")&&d.css("display","inline-block"),l=jQuery('<span class="Zebra_DatePicker_Icon_Wrapper"></span>').css({display:d.css("display"),position:"static"==d.css("position")? "relative":d.css("position"),"float":d.css("float"),top:d.css("top"),right:d.css("right"),bottom:d.css("bottom"),left:d.css("left")}),d.wrap(l).css({position:"relative",top:"auto",right:"auto",bottom:"auto",left:"auto"}),w=jQuery('<button type="button" class="Zebra_DatePicker_Icon'+("disabled"==d.attr("disabled")?" Zebra_DatePicker_Icon_Disabled":"")+'">Pick a date</button>'),a.icon=w,ia=w.add(d)):ia=d,ia.bind("click",function(b){b.preventDefault();d.attr("disabled")||("none"!=h.css("display")?a.hide(): a.show())}),void 0!==w&&w.insertAfter(d)),void 0!==w)){w.attr("style","");a.settings.inside&&w.addClass("Zebra_DatePicker_Icon_Inside");l=d.outerWidth();L=d.outerHeight();P=parseInt(d.css("marginLeft"),10)||0;b=parseInt(d.css("marginTop"),10)||0;var m=w.outerWidth(),qa=w.outerHeight(),ua=parseInt(w.css("marginLeft"),10)||0,va=parseInt(w.css("marginRight"),10)||0;a.settings.inside?w.css({top:b+(L-qa)/2,left:P+(l-m-va)}):w.css({top:b+(L-qa)/2,left:P+l+ua})}ca=!1!==a.settings.show_select_today&&-1<c.inArray("days", A)&&!B(N,T,Z)?a.settings.show_select_today:!1;e||(c(window).bind("resize.Zebra_DatePicker",function(){a.hide();void 0!==w&&(clearTimeout(oa),oa=setTimeout(function(){a.update()},100))}),h=c('<div class="Zebra_DatePicker"><table class="dp_header"><tr><td class="dp_previous">'+a.settings.header_navigation[0]+'</td><td class="dp_caption">&#032;</td><td class="dp_next">'+a.settings.header_navigation[1]+'</td></tr></table><table class="dp_daypicker"></table><table class="dp_monthpicker"></table><table class="dp_yearpicker"></table><table class="dp_footer"><tr><td class="dp_today"'+ (!1!==a.settings.show_clear_date?' style="width:50%"':"")+">"+ca+'</td><td class="dp_clear"'+(!1!==ca?' style="width:50%"':"")+">"+a.settings.lang_clear_date+"</td></tr></table></div>"),a.datepicker=h,C=c("table.dp_header",h),D=c("table.dp_daypicker",h),G=c("table.dp_monthpicker",h),H=c("table.dp_yearpicker",h),X=c("table.dp_footer",h),ba=c("td.dp_today",X),S=c("td.dp_clear",X),a.settings.always_visible?d.attr("disabled")||(a.settings.always_visible.append(h),a.show()):c("body").append(h),h.delegate("td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked, .dp_week_number)", "mouseover",function(){c(this).addClass("dp_hover")}).delegate("td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked, .dp_week_number)","mouseout",function(){c(this).removeClass("dp_hover")}),wa(c("td",C)),c(".dp_previous",C).bind("click",function(){c(this).hasClass("dp_blocked")||("months"==t?p--:"years"==t?p-=12:0>--u&&(u=11,p--),R())}),c(".dp_caption",C).bind("click",function(){t="days"==t?-1<c.inArray("months",A)?"months":-1<c.inArray("years",A)?"years":"days":"months"==t? -1<c.inArray("years",A)?"years":-1<c.inArray("days",A)?"days":"months":-1<c.inArray("days",A)?"days":-1<c.inArray("months",A)?"months":"years";R()}),c(".dp_next",C).bind("click",function(){c(this).hasClass("dp_blocked")||("months"==t?p++:"years"==t?p+=12:12==++u&&(u=0,p++),R())}),D.delegate("td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_week_number)","click",function(){a.settings.select_other_months&&null!==(Q=c(this).attr("class").match(/date\_([0-9]{4})(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])/))? ea(Q[1],Q[2]-1,Q[3],"days",c(this)):ea(p,u,s(c(this).html()),"days",c(this))}),G.delegate("td:not(.dp_disabled)","click",function(){var b=c(this).attr("class").match(/dp\_month\_([0-9]+)/);u=s(b[1]);-1==c.inArray("days",A)?ea(p,u,1,"months",c(this)):(t="days",a.settings.always_visible&&d.val(""),R())}),H.delegate("td:not(.dp_disabled)","click",function(){p=s(c(this).html());-1==c.inArray("months",A)?ea(p,1,1,"years",c(this)):(t="months",a.settings.always_visible&&d.val(""),R())}),c(ba).bind("click", function(b){b.preventDefault();ea(N,T,Z,"days",c(".dp_current",D));a.settings.always_visible&&a.show();a.hide()}),c(S).bind("click",function(b){b.preventDefault();d.val("");a.settings.always_visible?(K=J=U=null,c("td.dp_selected",h).removeClass("dp_selected")):p=u=K=J=U=null;a.hide();if(a.settings.onClear&&"function"==typeof a.settings.onClear)a.settings.onClear(d)}),a.settings.always_visible||c(document).bind({"mousedown.Zebra_DatePicker":function(b){if("block"==h.css("display")){if(a.settings.show_icon&& c(b.target).get(0)===w.get(0))return!0;0===c(b.target).parents().filter(".Zebra_DatePicker").length&&a.hide()}},"keyup.Zebra_DatePicker":function(b){"block"!=h.css("display")&&27!=b.which||a.hide()}}),R())};a.destroy=function(){void 0!==a.icon&&a.icon.remove();a.datepicker.remove();c(document).unbind("keyup.Zebra_DatePicker");c(document).unbind("mousedown.Zebra_DatePicker");c(window).unbind("resize.Zebra_DatePicker");d.removeData("Zebra_DatePicker");delete a};a.hide=function(){a.settings.always_visible|| (sa("hide"),h.hide())};a.show=function(){t=a.settings.view;var e=da(d.val()||(a.settings.start_date?a.settings.start_date:""));e?(J=e.getMonth(),u=e.getMonth(),K=e.getFullYear(),p=e.getFullYear(),U=e.getDate(),B(K,J,U)&&(a.settings.strict&&d.val(""),u=g,p=q)):(u=g,p=q);R();if(a.settings.always_visible)h.show();else{var e=h.outerWidth(),b=h.outerHeight(),z=(void 0!==w?w.offset().left+w.outerWidth(!0):d.offset().left+d.outerWidth(!0))+a.settings.offset[0],f=(void 0!==w?w.offset().top:d.offset().top)- b+a.settings.offset[1],k=c(window).width(),E=c(window).height(),n=c(window).scrollTop(),m=c(window).scrollLeft();z+e>m+k&&(z=m+k-e);z<m&&(z=m);f+b>n+E&&(f=n+E-b);f<n&&(f=n);h.css({left:z,top:f});h.fadeIn("explorer"==M.name&&9>M.version?0:150,"linear");sa()}};a.update=function(e){a.original_direction&&(a.original_direction=a.direction);a.settings=c.extend(a.settings,e);ra(!0)};var da=function(e){e+="";if(""!==c.trim(e)){for(var b=a.settings.format.replace(/([-.,*+?^${}()|[\]\/\\])/g,"\\$1"),z="dDjlNSwFmMnYy".split(""), f=[],k=[],E=null,n=null,m=0;m<z.length;m++)-1<(E=b.indexOf(z[m]))&&f.push({character:z[m],position:E});f.sort(function(a,b){return a.position-b.position});c.each(f,function(a,b){switch(b.character){case "d":k.push("0[1-9]|[12][0-9]|3[01]");break;case "D":k.push("[a-z]{3}");break;case "j":k.push("[1-9]|[12][0-9]|3[01]");break;case "l":k.push("[a-z]+");break;case "N":k.push("[1-7]");break;case "S":k.push("st|nd|rd|th");break;case "w":k.push("[0-6]");break;case "F":k.push("[a-z]+");break;case "m":k.push("0[1-9]|1[012]+"); break;case "M":k.push("[a-z]{3}");break;case "n":k.push("[1-9]|1[012]");break;case "Y":k.push("[0-9]{4}");break;case "y":k.push("[0-9]{2}")}});if(k.length&&(f.reverse(),c.each(f,function(a,c){b=b.replace(c.character,"("+k[k.length-a-1]+")")}),k=RegExp("^"+b+"$","ig"),n=k.exec(e))){e=new Date;var l=e.getDate(),d=e.getMonth()+1,p=e.getFullYear(),g="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),h="January February March April May June July August September October November December".split(" "), q,u=!0;f.reverse();c.each(f,function(b,e){if(!u)return!0;switch(e.character){case "m":case "n":d=s(n[b+1]);break;case "d":case "j":l=s(n[b+1]);break;case "D":case "l":case "F":case "M":q="D"==e.character||"l"==e.character?a.settings.days:a.settings.months;u=!1;c.each(q,function(a,c){if(u)return!0;if(n[b+1].toLowerCase()==c.substring(0,"D"==e.character||"M"==e.character?3:c.length).toLowerCase()){switch(e.character){case "D":n[b+1]=g[a].substring(0,3);break;case "l":n[b+1]=g[a];break;case "F":n[b+ 1]=h[a];d=a+1;break;case "M":n[b+1]=h[a].substring(0,3),d=a+1}u=!0}});break;case "Y":p=s(n[b+1]);break;case "y":p="19"+s(n[b+1])}});if(u&&(f=new Date(p,(d||1)-1,l||1),f.getFullYear()==p&&f.getDate()==(l||1)&&f.getMonth()==(d||1)-1))return f}return!1}},wa=function(a){"firefox"==M.name?a.css("MozUserSelect","none"):"explorer"==M.name?a.bind("selectstart",function(){return!1}):a.mousedown(function(){return!1})},ta=function(){var e=(new Date(p,u+1,0)).getDate(),b=(new Date(p,u,1)).getDay(),z=(new Date(p, u,0)).getDate(),b=b-a.settings.first_day_of_week,b=0>b?7+b:b;ja(a.settings.months[u]+", "+p);var f="<tr>";a.settings.show_week_number&&(f+="<th>"+a.settings.show_week_number+"</th>");for(var k=0;7>k;k++)f+="<th>"+(c.isArray(a.settings.days_abbr)&&void 0!==a.settings.days_abbr[(a.settings.first_day_of_week+k)%7]?a.settings.days_abbr[(a.settings.first_day_of_week+k)%7]:a.settings.days[(a.settings.first_day_of_week+k)%7].substr(0,2))+"</th>";f+="</tr><tr>";for(k=0;42>k;k++){0<k&&0===k%7&&(f+="</tr><tr>"); if(0===k%7&&a.settings.show_week_number){var d=new Date(p,u,k-b+1),n=d.getFullYear(),m=d.getMonth()+1,d=d.getDate(),l=void 0,g=void 0,h=void 0,s=h=void 0,q=void 0,h=g=l=void 0;3>m?(l=n-1,g=(l/4|0)-(l/100|0)+(l/400|0),h=((l-1)/4|0)-((l-1)/100|0)+((l-1)/400|0),h=g-h,s=0,q=d-1+31*(m-1)):(l=n,g=(l/4|0)-(l/100|0)+(l/400|0),h=((l-1)/4|0)-((l-1)/100|0)+((l-1)/400|0),h=g-h,s=h+1,q=d+((153*(m-3)+2)/5|0)+58+h);l=(l+g)%7;d=(q+l-s)%7;g=q+3-d;h=0>g?53-((l-h)/5|0):g>364+h?1:(g/7|0)+1;f+='<td class="dp_week_number">'+ h+"</td>"}n=k-b+1;if(a.settings.select_other_months&&(k<b||n>e))var r=new Date(p,u,n),v=r.getFullYear(),t=r.getMonth(),w=r.getDate(),r=v+x(t+1,2)+x(w,2);k<b?f+='<td class="'+(a.settings.select_other_months&&!B(v,t,w)?"dp_not_in_month_selectable date_"+r:"dp_not_in_month")+'">'+(a.settings.select_other_months||a.settings.show_other_months?x(z-b+k+1,a.settings.zero_pad?2:0):"&nbsp;")+"</td>":n>e?f+='<td class="'+(a.settings.select_other_months&&!B(v,t,w)?"dp_not_in_month_selectable date_"+r:"dp_not_in_month")+ '">'+(a.settings.select_other_months||a.settings.show_other_months?x(n-e,a.settings.zero_pad?2:0):"&nbsp;")+"</td>":(m=(a.settings.first_day_of_week+k)%7,d="",B(p,u,n)?(d=-1<c.inArray(m,a.settings.weekend_days)?"dp_weekend_disabled":d+" dp_disabled",u==T&&p==N&&Z==n&&(d+=" dp_disabled_current")):(-1<c.inArray(m,a.settings.weekend_days)&&(d="dp_weekend"),u==J&&p==K&&U==n&&(d+=" dp_selected"),u==T&&p==N&&Z==n&&(d+=" dp_current")),f+="<td"+(""!==d?' class="'+c.trim(d)+'"':"")+">"+(a.settings.zero_pad? x(n,2):n)+"</td>")}D.html(c(f+"</tr>"));a.settings.always_visible&&(la=c("td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked, .dp_week_number)",D));D.show()},xa=function(){ja(p);for(var e="<tr>",b=0;12>b;b++){0<b&&0===b%3&&(e+="</tr><tr>");var d="dp_month_"+b;B(p,b)?d+=" dp_disabled":!1!==J&&J==b?d+=" dp_selected":T==b&&N==p&&(d+=" dp_current");e+='<td class="'+c.trim(d)+'">'+(c.isArray(a.settings.months_abbr)&&void 0!==a.settings.months_abbr[b]?a.settings.months_abbr[b]:a.settings.months[b].substr(0, 3))+"</td>"}G.html(c(e+"</tr>"));a.settings.always_visible&&(ma=c("td:not(.dp_disabled)",G));G.show()},ya=function(){ja(p-7+" - "+(p+4));for(var e="<tr>",b=0;12>b;b++){0<b&&0===b%3&&(e+="</tr><tr>");var d="";B(p-7+b)?d+=" dp_disabled":K&&K==p-7+b?d+=" dp_selected":N==p-7+b&&(d+=" dp_current");e+="<td"+(""!==c.trim(d)?' class="'+c.trim(d)+'"':"")+">"+(p-7+b)+"</td>"}H.html(c(e+"</tr>"));a.settings.always_visible&&(na=c("td:not(.dp_disabled)",H));H.show()},sa=function(a){if("explorer"==M.name&&6==M.version){if(!$){var b= s(h.css("zIndex"))-1;$=jQuery("<iframe>",{src:'javascript:document.write("")',scrolling:"no",frameborder:0,allowtransparency:"true",css:{zIndex:b,position:"absolute",top:-1E3,left:-1E3,width:h.outerWidth(),height:h.outerHeight(),filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=0)",display:"none"}});c("body").append($)}switch(a){case "hide":$.hide();break;default:a=h.offset(),$.css({top:a.top,left:a.left,display:"block"})}}},B=function(e,b,d){if((void 0===e||isNaN(e))&&(void 0===b||isNaN(b))&& (void 0===d||isNaN(d)))return!1;if(c.isArray(a.settings.direction)||0!==s(a.settings.direction)){var f=s(I(e,"undefined"!=typeof b?x(b,2):"","undefined"!=typeof d?x(d,2):"")),k=(f+"").length;if(8==k&&("undefined"!=typeof r&&f<s(I(q,x(g,2),x(y,2)))||"undefined"!=typeof v&&f>s(I(O,x(W,2),x(aa,2))))||6==k&&("undefined"!=typeof r&&f<s(I(q,x(g,2)))||"undefined"!=typeof v&&f>s(I(O,x(W,2))))||4==k&&("undefined"!=typeof r&&f<q||"undefined"!=typeof v&&f>O))return!0}"undefined"!=typeof b&&(b+=1);var h=!1,n= !1;F&&c.each(F,function(){if(!h&&(-1<c.inArray(e,this[2])||-1<c.inArray("*",this[2]))&&("undefined"!=typeof b&&-1<c.inArray(b,this[1])||-1<c.inArray("*",this[1]))&&("undefined"!=typeof d&&-1<c.inArray(d,this[0])||-1<c.inArray("*",this[0]))){if("*"==this[3])return h=!0;var a=(new Date(e,b-1,d)).getDay();if(-1<c.inArray(a,this[3]))return h=!0}});V&&c.each(V,function(){if(!n&&(-1<c.inArray(e,this[2])||-1<c.inArray("*",this[2]))&&(n=!0,"undefined"!=typeof b))if(n=!0,-1<c.inArray(b,this[1])||-1<c.inArray("*", this[1])){if("undefined"!=typeof d){n=!0;if(-1<c.inArray(d,this[0])||-1<c.inArray("*",this[0])){if("*"==this[3])return n=!0;var a=(new Date(e,b-1,d)).getDay();if(-1<c.inArray(a,this[3]))return n=!0}n=!1}}else n=!1});return V&&n||!F||!h?!1:!0},Y=function(a){return(a+"").match(/^\-?[0-9]+$/)?!0:!1},ja=function(e){c(".dp_caption",C).html(e);if(c.isArray(a.settings.direction)||0!==s(a.settings.direction)||1==A.length&&"months"==A[0]){e=p;var b=u,d,f;if("days"==t)f=!B(0>b-1?I(e-1,"11"):I(e,x(b-1,2))), d=!B(11<b+1?I(e+1,"00"):I(e,x(b+1,2)));else if("months"==t){if(!r||r.getFullYear()<=e-1)f=!0;if(!v||v.getFullYear()>=e+1)d=!0}else if("years"==t){if(!r||r.getFullYear()<e-7)f=!0;if(!v||v.getFullYear()>e+4)d=!0}f?c(".dp_previous",C).removeClass("dp_blocked"):(c(".dp_previous",C).addClass("dp_blocked"),c(".dp_previous",C).removeClass("dp_hover"));d?c(".dp_next",C).removeClass("dp_blocked"):(c(".dp_next",C).addClass("dp_blocked"),c(".dp_next",C).removeClass("dp_hover"))}},R=function(){if(""===D.text()|| "days"==t){if(""===D.text()){a.settings.always_visible||h.css("left",-1E3);h.show();ta();var e=D.outerWidth(),b=D.outerHeight();G.css({width:e,height:b});H.css({width:e,height:b});C.css("width",e);X.css("width",e);h.hide()}else ta();G.hide();H.hide()}else"months"==t?(xa(),D.hide(),H.hide()):"years"==t&&(ya(),D.hide(),G.hide());a.settings.onChange&&"function"==typeof a.settings.onChange&&void 0!==t&&(e="days"==t?D.find("td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked)"):"months"== t?G.find("td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked)"):H.find("td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_blocked)"),e.each(function(){if("days"==t)if(c(this).hasClass("dp_not_in_month_selectable")){var a=c(this).attr("class").match(/date\_([0-9]{4})(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])/);c(this).data("date",a[1]+"-"+a[2]+"-"+a[3])}else c(this).data("date",p+"-"+x(u+1,2)+"-"+x(s(c(this).text()),2));else"months"==t?(a=c(this).attr("class").match(/dp\_month\_([0-9]+)/), c(this).data("date",p+"-"+x(s(a[1])+1,2))):c(this).data("date",s(c(this).text()))}),a.settings.onChange(t,e,d));X.show();!0===a.settings.show_clear_date||0===a.settings.show_clear_date&&""!==d.val()||a.settings.always_visible&&!1!==a.settings.show_clear_date?(S.show(),ca?(ba.css("width","50%"),S.css("width","50%")):(ba.hide(),S.css("width","100%"))):(S.hide(),ca?ba.show().css("width","100%"):X.hide())},ea=function(e,b,h,f,k){var g=new Date(e,b,h,12,0,0),n="days"==f?la:"months"==f?ma:na,m;m="";for(var l= g.getDate(),q=g.getDay(),s=a.settings.days[q],r=g.getMonth()+1,v=a.settings.months[r-1],t=g.getFullYear()+"",w=0;w<a.settings.format.length;w++){var y=a.settings.format.charAt(w);switch(y){case "y":t=t.substr(2);case "Y":m+=t;break;case "m":r=x(r,2);case "n":m+=r;break;case "M":v=c.isArray(a.settings.months_abbr)&&void 0!==a.settings.months_abbr[r-1]?a.settings.months_abbr[r-1]:a.settings.months[r-1].substr(0,3);case "F":m+=v;break;case "d":l=x(l,2);case "j":m+=l;break;case "D":s=c.isArray(a.settings.days_abbr)&& void 0!==a.settings.days_abbr[q]?a.settings.days_abbr[q]:a.settings.days[q].substr(0,3);case "l":m+=s;break;case "N":q++;case "w":m+=q;break;case "S":m=1==l%10&&"11"!=l?m+"st":2==l%10&&"12"!=l?m+"nd":3==l%10&&"13"!=l?m+"rd":m+"th";break;default:m+=y}}d.val(m);a.settings.always_visible&&(J=g.getMonth(),u=g.getMonth(),K=g.getFullYear(),p=g.getFullYear(),U=g.getDate(),n.removeClass("dp_selected"),k.addClass("dp_selected"),"days"==f&&k.hasClass("dp_not_in_month_selectable")&&a.show());a.hide();pa(g); if(a.settings.onSelect&&"function"==typeof a.settings.onSelect)a.settings.onSelect(m,e+"-"+x(b+1,2)+"-"+x(h,2),g,d);d.focus()},I=function(){for(var a="",b=0;b<arguments.length;b++)a+=arguments[b]+"";return a},x=function(a,b){for(a+="";a.length<b;)a="0"+a;return a},s=function(a){return parseInt(a,10)},pa=function(e){a.settings.pair&&c.each(a.settings.pair,function(){var a=c(this);a.data&&a.data("Zebra_DatePicker")?(a=a.data("Zebra_DatePicker"),a.update({reference_date:e,direction:0===a.settings.direction? 1:a.settings.direction}),a.settings.always_visible&&a.show()):a.data("zdp_reference_date",e)})},M={init:function(){this.name=this.searchString(this.dataBrowser)||"";this.version=this.searchVersion(navigator.userAgent)||this.searchVersion(navigator.appVersion)||""},searchString:function(a){for(var b=0;b<a.length;b++){var c=a[b].string,d=a[b].prop;this.versionSearchString=a[b].versionSearch||a[b].identity;if(c){if(-1!=c.indexOf(a[b].subString))return a[b].identity}else if(d)return a[b].identity}},searchVersion:function(a){var b= a.indexOf(this.versionSearchString);if(-1!=b)return parseFloat(a.substring(b+this.versionSearchString.length+1))},dataBrowser:[{string:navigator.userAgent,subString:"Firefox",identity:"firefox"},{string:navigator.userAgent,subString:"MSIE",identity:"explorer",versionSearch:"MSIE"}]};M.init();ra()};c.fn.Zebra_DatePicker=function(ga){return this.each(function(){void 0!==c(this).data("Zebra_DatePicker")&&c(this).data("Zebra_DatePicker").destroy();var ha=new c.Zebra_DatePicker(this,ga);c(this).data("Zebra_DatePicker", ha)})}})(jQuery);