| @@ -0,0 +1,1918 @@ |
| | 1 | /*! |
| | 2 | * Datepicker for Bootstrap v1.5.1 (https://github.com/eternicode/bootstrap-datepicker) |
| | 3 | * |
| | 4 | * Copyright 2012 Stefan Petre |
| | 5 | * Improvements by Andrew Rowls |
| | 6 | * Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) |
| | 7 | */(function(factory){ |
| | 8 | if (typeof define === "function" && define.amd) { |
| | 9 | define(["jquery"], factory); |
| | 10 | } else if (typeof exports === 'object') { |
| | 11 | factory(require('jquery')); |
| | 12 | } else { |
| | 13 | factory(jQuery); |
| | 14 | } |
| | 15 | }(function($, undefined){ |
| | 16 | |
| | 17 | function UTCDate(){ |
| | 18 | return new Date(Date.UTC.apply(Date, arguments)); |
| | 19 | } |
| | 20 | function UTCToday(){ |
| | 21 | var today = new Date(); |
| | 22 | return UTCDate(today.getFullYear(), today.getMonth(), today.getDate()); |
| | 23 | } |
| | 24 | function isUTCEquals(date1, date2) { |
| | 25 | return ( |
| | 26 | date1.getUTCFullYear() === date2.getUTCFullYear() && |
| | 27 | date1.getUTCMonth() === date2.getUTCMonth() && |
| | 28 | date1.getUTCDate() === date2.getUTCDate() |
| | 29 | ); |
| | 30 | } |
| | 31 | function alias(method){ |
| | 32 | return function(){ |
| | 33 | return this[method].apply(this, arguments); |
| | 34 | }; |
| | 35 | } |
| | 36 | function isValidDate(d) { |
| | 37 | return d && !isNaN(d.getTime()); |
| | 38 | } |
| | 39 | |
| | 40 | var DateArray = (function(){ |
| | 41 | var extras = { |
| | 42 | get: function(i){ |
| | 43 | return this.slice(i)[0]; |
| | 44 | }, |
| | 45 | contains: function(d){ |
| | 46 | // Array.indexOf is not cross-browser; |
| | 47 | // $.inArray doesn't work with Dates |
| | 48 | var val = d && d.valueOf(); |
| | 49 | for (var i=0, l=this.length; i < l; i++) |
| | 50 | if (this[i].valueOf() === val) |
| | 51 | return i; |
| | 52 | return -1; |
| | 53 | }, |
| | 54 | remove: function(i){ |
| | 55 | this.splice(i,1); |
| | 56 | }, |
| | 57 | replace: function(new_array){ |
| | 58 | if (!new_array) |
| | 59 | return; |
| | 60 | if (!$.isArray(new_array)) |
| | 61 | new_array = [new_array]; |
| | 62 | this.clear(); |
| | 63 | this.push.apply(this, new_array); |
| | 64 | }, |
| | 65 | clear: function(){ |
| | 66 | this.length = 0; |
| | 67 | }, |
| | 68 | copy: function(){ |
| | 69 | var a = new DateArray(); |
| | 70 | a.replace(this); |
| | 71 | return a; |
| | 72 | } |
| | 73 | }; |
| | 74 | |
| | 75 | return function(){ |
| | 76 | var a = []; |
| | 77 | a.push.apply(a, arguments); |
| | 78 | $.extend(a, extras); |
| | 79 | return a; |
| | 80 | }; |
| | 81 | })(); |
| | 82 | |
| | 83 | |
| | 84 | // Picker object |
| | 85 | |
| | 86 | var Datepicker = function(element, options){ |
| | 87 | $(element).data('datepicker', this); |
| | 88 | this._process_options(options); |
| | 89 | |
| | 90 | this.dates = new DateArray(); |
| | 91 | this.viewDate = this.o.defaultViewDate; |
| | 92 | this.focusDate = null; |
| | 93 | |
| | 94 | this.element = $(element); |
| | 95 | this.isInline = false; |
| | 96 | this.isInput = this.element.is('input'); |
| | 97 | this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .btn') : false; |
| | 98 | this.hasInput = this.component && this.element.find('input').length; |
| | 99 | if (this.component && this.component.length === 0) |
| | 100 | this.component = false; |
| | 101 | |
| | 102 | this.picker = $(DPGlobal.template); |
| | 103 | this._buildEvents(); |
| | 104 | this._attachEvents(); |
| | 105 | |
| | 106 | if (this.isInline){ |
| | 107 | this.picker.addClass('datepicker-inline').appendTo(this.element); |
| | 108 | } |
| | 109 | else { |
| | 110 | this.picker.addClass('datepicker-dropdown dropdown-menu'); |
| | 111 | } |
| | 112 | |
| | 113 | if (this.o.rtl){ |
| | 114 | this.picker.addClass('datepicker-rtl'); |
| | 115 | } |
| | 116 | |
| | 117 | this.viewMode = this.o.startView; |
| | 118 | |
| | 119 | if (this.o.calendarWeeks) |
| | 120 | this.picker.find('thead .datepicker-title, tfoot .today, tfoot .clear') |
| | 121 | .attr('colspan', function(i, val){ |
| | 122 | return parseInt(val) + 1; |
| | 123 | }); |
| | 124 | |
| | 125 | this._allow_update = false; |
| | 126 | |
| | 127 | this.setStartDate(this._o.startDate); |
| | 128 | this.setEndDate(this._o.endDate); |
| | 129 | this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled); |
| | 130 | this.setDaysOfWeekHighlighted(this.o.daysOfWeekHighlighted); |
| | 131 | this.setDatesDisabled(this.o.datesDisabled); |
| | 132 | |
| | 133 | this.fillDow(); |
| | 134 | this.fillMonths(); |
| | 135 | |
| | 136 | this._allow_update = true; |
| | 137 | |
| | 138 | this.update(); |
| | 139 | this.showMode(); |
| | 140 | |
| | 141 | if (this.isInline){ |
| | 142 | this.show(); |
| | 143 | } |
| | 144 | }; |
| | 145 | |
| | 146 | Datepicker.prototype = { |
| | 147 | constructor: Datepicker, |
| | 148 | |
| | 149 | _process_options: function(opts){ |
| | 150 | // Store raw options for reference |
| | 151 | this._o = $.extend({}, this._o, opts); |
| | 152 | // Processed options |
| | 153 | var o = this.o = $.extend({}, this._o); |
| | 154 | |
| | 155 | // Check if "de-DE" style date is available, if not language should |
| | 156 | // fallback to 2 letter code eg "de" |
| | 157 | var lang = o.language; |
| | 158 | if (!dates[lang]){ |
| | 159 | lang = lang.split('-')[0]; |
| | 160 | if (!dates[lang]) |
| | 161 | lang = defaults.language; |
| | 162 | } |
| | 163 | o.language = lang; |
| | 164 | |
| | 165 | switch (o.startView){ |
| | 166 | case 2: |
| | 167 | case 'decade': |
| | 168 | o.startView = 2; |
| | 169 | break; |
| | 170 | case 1: |
| | 171 | case 'year': |
| | 172 | o.startView = 1; |
| | 173 | break; |
| | 174 | default: |
| | 175 | o.startView = 0; |
| | 176 | } |
| | 177 | |
| | 178 | switch (o.minViewMode){ |
| | 179 | case 1: |
| | 180 | case 'months': |
| | 181 | o.minViewMode = 1; |
| | 182 | break; |
| | 183 | case 2: |
| | 184 | case 'years': |
| | 185 | o.minViewMode = 2; |
| | 186 | break; |
| | 187 | default: |
| | 188 | o.minViewMode = 0; |
| | 189 | } |
| | 190 | |
| | 191 | switch (o.maxViewMode) { |
| | 192 | case 0: |
| | 193 | case 'days': |
| | 194 | o.maxViewMode = 0; |
| | 195 | break; |
| | 196 | case 1: |
| | 197 | case 'months': |
| | 198 | o.maxViewMode = 1; |
| | 199 | break; |
| | 200 | default: |
| | 201 | o.maxViewMode = 2; |
| | 202 | } |
| | 203 | |
| | 204 | o.startView = Math.min(o.startView, o.maxViewMode); |
| | 205 | o.startView = Math.max(o.startView, o.minViewMode); |
| | 206 | |
| | 207 | // true, false, or Number > 0 |
| | 208 | if (o.multidate !== true){ |
| | 209 | o.multidate = Number(o.multidate) || false; |
| | 210 | if (o.multidate !== false) |
| | 211 | o.multidate = Math.max(0, o.multidate); |
| | 212 | } |
| | 213 | o.multidateSeparator = String(o.multidateSeparator); |
| | 214 | |
| | 215 | o.weekStart %= 7; |
| | 216 | o.weekEnd = (o.weekStart + 6) % 7; |
| | 217 | |
| | 218 | var format = DPGlobal.parseFormat(o.format); |
| | 219 | if (o.startDate !== -Infinity){ |
| | 220 | if (!!o.startDate){ |
| | 221 | if (o.startDate instanceof Date) |
| | 222 | o.startDate = this._local_to_utc(this._zero_time(o.startDate)); |
| | 223 | else |
| | 224 | o.startDate = DPGlobal.parseDate(o.startDate, format, o.language); |
| | 225 | } |
| | 226 | else { |
| | 227 | o.startDate = -Infinity; |
| | 228 | } |
| | 229 | } |
| | 230 | if (o.endDate !== Infinity){ |
| | 231 | if (!!o.endDate){ |
| | 232 | if (o.endDate instanceof Date) |
| | 233 | o.endDate = this._local_to_utc(this._zero_time(o.endDate)); |
| | 234 | else |
| | 235 | o.endDate = DPGlobal.parseDate(o.endDate, format, o.language); |
| | 236 | } |
| | 237 | else { |
| | 238 | o.endDate = Infinity; |
| | 239 | } |
| | 240 | } |
| | 241 | |
| | 242 | o.daysOfWeekDisabled = o.daysOfWeekDisabled||[]; |
| | 243 | if (!$.isArray(o.daysOfWeekDisabled)) |
| | 244 | o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/); |
| | 245 | o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d){ |
| | 246 | return parseInt(d, 10); |
| | 247 | }); |
| | 248 | |
| | 249 | o.daysOfWeekHighlighted = o.daysOfWeekHighlighted||[]; |
| | 250 | if (!$.isArray(o.daysOfWeekHighlighted)) |
| | 251 | o.daysOfWeekHighlighted = o.daysOfWeekHighlighted.split(/[,\s]*/); |
| | 252 | o.daysOfWeekHighlighted = $.map(o.daysOfWeekHighlighted, function(d){ |
| | 253 | return parseInt(d, 10); |
| | 254 | }); |
| | 255 | |
| | 256 | o.datesDisabled = o.datesDisabled||[]; |
| | 257 | if (!$.isArray(o.datesDisabled)) { |
| | 258 | var datesDisabled = []; |
| | 259 | datesDisabled.push(DPGlobal.parseDate(o.datesDisabled, format, o.language)); |
| | 260 | o.datesDisabled = datesDisabled; |
| | 261 | } |
| | 262 | o.datesDisabled = $.map(o.datesDisabled,function(d){ |
| | 263 | return DPGlobal.parseDate(d, format, o.language); |
| | 264 | }); |
| | 265 | |
| | 266 | var plc = String(o.orientation).toLowerCase().split(/\s+/g), |
| | 267 | _plc = o.orientation.toLowerCase(); |
| | 268 | plc = $.grep(plc, function(word){ |
| | 269 | return /^auto|left|right|top|bottom$/.test(word); |
| | 270 | }); |
| | 271 | o.orientation = {x: 'auto', y: 'auto'}; |
| | 272 | if (!_plc || _plc === 'auto') |
| | 273 | ; // no action |
| | 274 | else if (plc.length === 1){ |
| | 275 | switch (plc[0]){ |
| | 276 | case 'top': |
| | 277 | case 'bottom': |
| | 278 | o.orientation.y = plc[0]; |
| | 279 | break; |
| | 280 | case 'left': |
| | 281 | case 'right': |
| | 282 | o.orientation.x = plc[0]; |
| | 283 | break; |
| | 284 | } |
| | 285 | } |
| | 286 | else { |
| | 287 | _plc = $.grep(plc, function(word){ |
| | 288 | return /^left|right$/.test(word); |
| | 289 | }); |
| | 290 | o.orientation.x = _plc[0] || 'auto'; |
| | 291 | |
| | 292 | _plc = $.grep(plc, function(word){ |
| | 293 | return /^top|bottom$/.test(word); |
| | 294 | }); |
| | 295 | o.orientation.y = _plc[0] || 'auto'; |
| | 296 | } |
| | 297 | if (o.defaultViewDate) { |
| | 298 | var year = o.defaultViewDate.year || new Date().getFullYear(); |
| | 299 | var month = o.defaultViewDate.month || 0; |
| | 300 | var day = o.defaultViewDate.day || 1; |
| | 301 | o.defaultViewDate = UTCDate(year, month, day); |
| | 302 | } else { |
| | 303 | o.defaultViewDate = UTCToday(); |
| | 304 | } |
| | 305 | }, |
| | 306 | _events: [], |
| | 307 | _secondaryEvents: [], |
| | 308 | _applyEvents: function(evs){ |
| | 309 | for (var i=0, el, ch, ev; i < evs.length; i++){ |
| | 310 | el = evs[i][0]; |
| | 311 | if (evs[i].length === 2){ |
| | 312 | ch = undefined; |
| | 313 | ev = evs[i][1]; |
| | 314 | } |
| | 315 | else if (evs[i].length === 3){ |
| | 316 | ch = evs[i][1]; |
| | 317 | ev = evs[i][2]; |
| | 318 | } |
| | 319 | el.on(ev, ch); |
| | 320 | } |
| | 321 | }, |
| | 322 | _unapplyEvents: function(evs){ |
| | 323 | for (var i=0, el, ev, ch; i < evs.length; i++){ |
| | 324 | el = evs[i][0]; |
| | 325 | if (evs[i].length === 2){ |
| | 326 | ch = undefined; |
| | 327 | ev = evs[i][1]; |
| | 328 | } |
| | 329 | else if (evs[i].length === 3){ |
| | 330 | ch = evs[i][1]; |
| | 331 | ev = evs[i][2]; |
| | 332 | } |
| | 333 | el.off(ev, ch); |
| | 334 | } |
| | 335 | }, |
| | 336 | _buildEvents: function(){ |
| | 337 | var events = { |
| | 338 | keyup: $.proxy(function(e){ |
| | 339 | if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1) |
| | 340 | this.update(); |
| | 341 | }, this), |
| | 342 | keydown: $.proxy(this.keydown, this), |
| | 343 | paste: $.proxy(this.paste, this) |
| | 344 | }; |
| | 345 | |
| | 346 | if (this.o.showOnFocus === true) { |
| | 347 | events.focus = $.proxy(this.show, this); |
| | 348 | } |
| | 349 | |
| | 350 | if (this.isInput) { // single input |
| | 351 | this._events = [ |
| | 352 | [this.element, events] |
| | 353 | ]; |
| | 354 | } |
| | 355 | else if (this.component && this.hasInput) { // component: input + button |
| | 356 | this._events = [ |
| | 357 | // For components that are not readonly, allow keyboard nav |
| | 358 | [this.element.find('input'), events], |
| | 359 | [this.component, { |
| | 360 | click: $.proxy(this.show, this) |
| | 361 | }] |
| | 362 | ]; |
| | 363 | } |
| | 364 | else if (this.element.is('div')){ // inline datepicker |
| | 365 | this.isInline = true; |
| | 366 | } |
| | 367 | else { |
| | 368 | this._events = [ |
| | 369 | [this.element, { |
| | 370 | click: $.proxy(this.show, this) |
| | 371 | }] |
| | 372 | ]; |
| | 373 | } |
| | 374 | this._events.push( |
| | 375 | // Component: listen for blur on element descendants |
| | 376 | [this.element, '*', { |
| | 377 | blur: $.proxy(function(e){ |
| | 378 | this._focused_from = e.target; |
| | 379 | }, this) |
| | 380 | }], |
| | 381 | // Input: listen for blur on element |
| | 382 | [this.element, { |
| | 383 | blur: $.proxy(function(e){ |
| | 384 | this._focused_from = e.target; |
| | 385 | }, this) |
| | 386 | }] |
| | 387 | ); |
| | 388 | |
| | 389 | if (this.o.immediateUpdates) { |
| | 390 | // Trigger input updates immediately on changed year/month |
| | 391 | this._events.push([this.element, { |
| | 392 | 'changeYear changeMonth': $.proxy(function(e){ |
| | 393 | this.update(e.date); |
| | 394 | }, this) |
| | 395 | }]); |
| | 396 | } |
| | 397 | |
| | 398 | this._secondaryEvents = [ |
| | 399 | [this.picker, { |
| | 400 | click: $.proxy(this.click, this) |
| | 401 | }], |
| | 402 | [$(window), { |
| | 403 | resize: $.proxy(this.place, this) |
| | 404 | }], |
| | 405 | [$(document), { |
| | 406 | mousedown: $.proxy(function(e){ |
| | 407 | // Clicked outside the datepicker, hide it |
| | 408 | if (!( |
| | 409 | this.element.is(e.target) || |
| | 410 | this.element.find(e.target).length || |
| | 411 | this.picker.is(e.target) || |
| | 412 | this.picker.find(e.target).length || |
| | 413 | this.picker.hasClass('datepicker-inline') |
| | 414 | )){ |
| | 415 | this.hide(); |
| | 416 | } |
| | 417 | }, this) |
| | 418 | }] |
| | 419 | ]; |
| | 420 | }, |
| | 421 | _attachEvents: function(){ |
| | 422 | this._detachEvents(); |
| | 423 | this._applyEvents(this._events); |
| | 424 | }, |
| | 425 | _detachEvents: function(){ |
| | 426 | this._unapplyEvents(this._events); |
| | 427 | }, |
| | 428 | _attachSecondaryEvents: function(){ |
| | 429 | this._detachSecondaryEvents(); |
| | 430 | this._applyEvents(this._secondaryEvents); |
| | 431 | }, |
| | 432 | _detachSecondaryEvents: function(){ |
| | 433 | this._unapplyEvents(this._secondaryEvents); |
| | 434 | }, |
| | 435 | _trigger: function(event, altdate){ |
| | 436 | var date = altdate || this.dates.get(-1), |
| | 437 | local_date = this._utc_to_local(date); |
| | 438 | |
| | 439 | this.element.trigger({ |
| | 440 | type: event, |
| | 441 | date: local_date, |
| | 442 | dates: $.map(this.dates, this._utc_to_local), |
| | 443 | format: $.proxy(function(ix, format){ |
| | 444 | if (arguments.length === 0){ |
| | 445 | ix = this.dates.length - 1; |
| | 446 | format = this.o.format; |
| | 447 | } |
| | 448 | else if (typeof ix === 'string'){ |
| | 449 | format = ix; |
| | 450 | ix = this.dates.length - 1; |
| | 451 | } |
| | 452 | format = format || this.o.format; |
| | 453 | var date = this.dates.get(ix); |
| | 454 | return DPGlobal.formatDate(date, format, this.o.language); |
| | 455 | }, this) |
| | 456 | }); |
| | 457 | }, |
| | 458 | |
| | 459 | show: function(){ |
| | 460 | var element = this.component ? this.element.find('input') : this.element; |
| | 461 | if (element.attr('readonly') && this.o.enableOnReadonly === false) |
| | 462 | return; |
| | 463 | if (!this.isInline) |
| | 464 | this.picker.appendTo(this.o.container); |
| | 465 | this.place(); |
| | 466 | this.picker.show(); |
| | 467 | this._attachSecondaryEvents(); |
| | 468 | this._trigger('show'); |
| | 469 | if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) { |
| | 470 | $(this.element).blur(); |
| | 471 | } |
| | 472 | return this; |
| | 473 | }, |
| | 474 | |
| | 475 | hide: function(){ |
| | 476 | if (this.isInline) |
| | 477 | return this; |
| | 478 | if (!this.picker.is(':visible')) |
| | 479 | return this; |
| | 480 | this.focusDate = null; |
| | 481 | this.picker.hide().detach(); |
| | 482 | this._detachSecondaryEvents(); |
| | 483 | this.viewMode = this.o.startView; |
| | 484 | this.showMode(); |
| | 485 | |
| | 486 | if ( |
| | 487 | this.o.forceParse && |
| | 488 | ( |
| | 489 | this.isInput && this.element.val() || |
| | 490 | this.hasInput && this.element.find('input').val() |
| | 491 | ) |
| | 492 | ) |
| | 493 | this.setValue(); |
| | 494 | this._trigger('hide'); |
| | 495 | return this; |
| | 496 | }, |
| | 497 | |
| | 498 | remove: function(){ |
| | 499 | this.hide(); |
| | 500 | this._detachEvents(); |
| | 501 | this._detachSecondaryEvents(); |
| | 502 | this.picker.remove(); |
| | 503 | delete this.element.data().datepicker; |
| | 504 | if (!this.isInput){ |
| | 505 | delete this.element.data().date; |
| | 506 | } |
| | 507 | return this; |
| | 508 | }, |
| | 509 | |
| | 510 | paste: function(evt){ |
| | 511 | var dateString; |
| | 512 | if (evt.originalEvent.clipboardData && evt.originalEvent.clipboardData.types |
| | 513 | && $.inArray('text/plain', evt.originalEvent.clipboardData.types) !== -1) { |
| | 514 | dateString = evt.originalEvent.clipboardData.getData('text/plain'); |
| | 515 | } |
| | 516 | else if (window.clipboardData) { |
| | 517 | dateString = window.clipboardData.getData('Text'); |
| | 518 | } |
| | 519 | else { |
| | 520 | return; |
| | 521 | } |
| | 522 | this.setDate(dateString); |
| | 523 | this.update(); |
| | 524 | evt.preventDefault(); |
| | 525 | }, |
| | 526 | |
| | 527 | _utc_to_local: function(utc){ |
| | 528 | return utc && new Date(utc.getTime() + (utc.getTimezoneOffset()*60000)); |
| | 529 | }, |
| | 530 | _local_to_utc: function(local){ |
| | 531 | return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000)); |
| | 532 | }, |
| | 533 | _zero_time: function(local){ |
| | 534 | return local && new Date(local.getFullYear(), local.getMonth(), local.getDate()); |
| | 535 | }, |
| | 536 | _zero_utc_time: function(utc){ |
| | 537 | return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate())); |
| | 538 | }, |
| | 539 | |
| | 540 | getDates: function(){ |
| | 541 | return $.map(this.dates, this._utc_to_local); |
| | 542 | }, |
| | 543 | |
| | 544 | getUTCDates: function(){ |
| | 545 | return $.map(this.dates, function(d){ |
| | 546 | return new Date(d); |
| | 547 | }); |
| | 548 | }, |
| | 549 | |
| | 550 | getDate: function(){ |
| | 551 | return this._utc_to_local(this.getUTCDate()); |
| | 552 | }, |
| | 553 | |
| | 554 | getUTCDate: function(){ |
| | 555 | var selected_date = this.dates.get(-1); |
| | 556 | if (typeof selected_date !== 'undefined') { |
| | 557 | return new Date(selected_date); |
| | 558 | } else { |
| | 559 | return null; |
| | 560 | } |
| | 561 | }, |
| | 562 | |
| | 563 | clearDates: function(){ |
| | 564 | var element; |
| | 565 | if (this.isInput) { |
| | 566 | element = this.element; |
| | 567 | } else if (this.component) { |
| | 568 | element = this.element.find('input'); |
| | 569 | } |
| | 570 | |
| | 571 | if (element) { |
| | 572 | element.val(''); |
| | 573 | } |
| | 574 | |
| | 575 | this.update(); |
| | 576 | this._trigger('changeDate'); |
| | 577 | |
| | 578 | if (this.o.autoclose) { |
| | 579 | this.hide(); |
| | 580 | } |
| | 581 | }, |
| | 582 | setDates: function(){ |
| | 583 | var args = $.isArray(arguments[0]) ? arguments[0] : arguments; |
| | 584 | this.update.apply(this, args); |
| | 585 | this._trigger('changeDate'); |
| | 586 | this.setValue(); |
| | 587 | return this; |
| | 588 | }, |
| | 589 | |
| | 590 | setUTCDates: function(){ |
| | 591 | var args = $.isArray(arguments[0]) ? arguments[0] : arguments; |
| | 592 | this.update.apply(this, $.map(args, this._utc_to_local)); |
| | 593 | this._trigger('changeDate'); |
| | 594 | this.setValue(); |
| | 595 | return this; |
| | 596 | }, |
| | 597 | |
| | 598 | setDate: alias('setDates'), |
| | 599 | setUTCDate: alias('setUTCDates'), |
| | 600 | |
| | 601 | setValue: function(){ |
| | 602 | var formatted = this.getFormattedDate(); |
| | 603 | if (!this.isInput){ |
| | 604 | if (this.component){ |
| | 605 | this.element.find('input').val(formatted); |
| | 606 | } |
| | 607 | } |
| | 608 | else { |
| | 609 | this.element.val(formatted); |
| | 610 | } |
| | 611 | return this; |
| | 612 | }, |
| | 613 | |
| | 614 | getFormattedDate: function(format){ |
| | 615 | if (format === undefined) |
| | 616 | format = this.o.format; |
| | 617 | |
| | 618 | var lang = this.o.language; |
| | 619 | return $.map(this.dates, function(d){ |
| | 620 | return DPGlobal.formatDate(d, format, lang); |
| | 621 | }).join(this.o.multidateSeparator); |
| | 622 | }, |
| | 623 | |
| | 624 | setStartDate: function(startDate){ |
| | 625 | this._process_options({startDate: startDate}); |
| | 626 | this.update(); |
| | 627 | this.updateNavArrows(); |
| | 628 | return this; |
| | 629 | }, |
| | 630 | |
| | 631 | setEndDate: function(endDate){ |
| | 632 | this._process_options({endDate: endDate}); |
| | 633 | this.update(); |
| | 634 | this.updateNavArrows(); |
| | 635 | return this; |
| | 636 | }, |
| | 637 | |
| | 638 | setDaysOfWeekDisabled: function(daysOfWeekDisabled){ |
| | 639 | this._process_options({daysOfWeekDisabled: daysOfWeekDisabled}); |
| | 640 | this.update(); |
| | 641 | this.updateNavArrows(); |
| | 642 | return this; |
| | 643 | }, |
| | 644 | |
| | 645 | setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){ |
| | 646 | this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted}); |
| | 647 | this.update(); |
| | 648 | return this; |
| | 649 | }, |
| | 650 | |
| | 651 | setDatesDisabled: function(datesDisabled){ |
| | 652 | this._process_options({datesDisabled: datesDisabled}); |
| | 653 | this.update(); |
| | 654 | this.updateNavArrows(); |
| | 655 | }, |
| | 656 | |
| | 657 | place: function(){ |
| | 658 | if (this.isInline) |
| | 659 | return this; |
| | 660 | var calendarWidth = this.picker.outerWidth(), |
| | 661 | calendarHeight = this.picker.outerHeight(), |
| | 662 | visualPadding = 10, |
| | 663 | container = $(this.o.container), |
| | 664 | windowWidth = container.width(), |
| | 665 | scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(), |
| | 666 | appendOffset = container.offset(); |
| | 667 | |
| | 668 | var parentsZindex = []; |
| | 669 | this.element.parents().each(function(){ |
| | 670 | var itemZIndex = $(this).css('z-index'); |
| | 671 | if (itemZIndex !== 'auto' && itemZIndex !== 0) parentsZindex.push(parseInt(itemZIndex)); |
| | 672 | }); |
| | 673 | var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset; |
| | 674 | var offset = this.component ? this.component.parent().offset() : this.element.offset(); |
| | 675 | var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false); |
| | 676 | var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false); |
| | 677 | var left = offset.left - appendOffset.left, |
| | 678 | top = offset.top - appendOffset.top; |
| | 679 | |
| | 680 | if (this.o.container !== 'body') { |
| | 681 | top += scrollTop; |
| | 682 | } |
| | 683 | |
| | 684 | this.picker.removeClass( |
| | 685 | 'datepicker-orient-top datepicker-orient-bottom '+ |
| | 686 | 'datepicker-orient-right datepicker-orient-left' |
| | 687 | ); |
| | 688 | |
| | 689 | if (this.o.orientation.x !== 'auto'){ |
| | 690 | this.picker.addClass('datepicker-orient-' + this.o.orientation.x); |
| | 691 | if (this.o.orientation.x === 'right') |
| | 692 | left -= calendarWidth - width; |
| | 693 | } |
| | 694 | // auto x orientation is best-placement: if it crosses a window |
| | 695 | // edge, fudge it sideways |
| | 696 | else { |
| | 697 | if (offset.left < 0) { |
| | 698 | // component is outside the window on the left side. Move it into visible range |
| | 699 | this.picker.addClass('datepicker-orient-left'); |
| | 700 | left -= offset.left - visualPadding; |
| | 701 | } else if (left + calendarWidth > windowWidth) { |
| | 702 | // the calendar passes the widow right edge. Align it to component right side |
| | 703 | this.picker.addClass('datepicker-orient-right'); |
| | 704 | left += width - calendarWidth; |
| | 705 | } else { |
| | 706 | // Default to left |
| | 707 | this.picker.addClass('datepicker-orient-left'); |
| | 708 | } |
| | 709 | } |
| | 710 | |
| | 711 | // auto y orientation is best-situation: top or bottom, no fudging, |
| | 712 | // decision based on which shows more of the calendar |
| | 713 | var yorient = this.o.orientation.y, |
| | 714 | top_overflow; |
| | 715 | if (yorient === 'auto'){ |
| | 716 | top_overflow = -scrollTop + top - calendarHeight; |
| | 717 | yorient = top_overflow < 0 ? 'bottom' : 'top'; |
| | 718 | } |
| | 719 | |
| | 720 | this.picker.addClass('datepicker-orient-' + yorient); |
| | 721 | if (yorient === 'top') |
| | 722 | top -= calendarHeight + parseInt(this.picker.css('padding-top')); |
| | 723 | else |
| | 724 | top += height; |
| | 725 | |
| | 726 | if (this.o.rtl) { |
| | 727 | var right = windowWidth - (left + width); |
| | 728 | this.picker.css({ |
| | 729 | top: top, |
| | 730 | right: right, |
| | 731 | zIndex: zIndex |
| | 732 | }); |
| | 733 | } else { |
| | 734 | this.picker.css({ |
| | 735 | top: top, |
| | 736 | left: left, |
| | 737 | zIndex: zIndex |
| | 738 | }); |
| | 739 | } |
| | 740 | return this; |
| | 741 | }, |
| | 742 | |
| | 743 | _allow_update: true, |
| | 744 | update: function(){ |
| | 745 | if (!this._allow_update) |
| | 746 | return this; |
| | 747 | |
| | 748 | var oldDates = this.dates.copy(), |
| | 749 | dates = [], |
| | 750 | fromArgs = false; |
| | 751 | if (arguments.length){ |
| | 752 | $.each(arguments, $.proxy(function(i, date){ |
| | 753 | if (date instanceof Date) |
| | 754 | date = this._local_to_utc(date); |
| | 755 | dates.push(date); |
| | 756 | }, this)); |
| | 757 | fromArgs = true; |
| | 758 | } |
| | 759 | else { |
| | 760 | dates = this.isInput |
| | 761 | ? this.element.val() |
| | 762 | : this.element.data('date') || this.element.find('input').val(); |
| | 763 | if (dates && this.o.multidate) |
| | 764 | dates = dates.split(this.o.multidateSeparator); |
| | 765 | else |
| | 766 | dates = [dates]; |
| | 767 | delete this.element.data().date; |
| | 768 | } |
| | 769 | |
| | 770 | dates = $.map(dates, $.proxy(function(date){ |
| | 771 | return DPGlobal.parseDate(date, this.o.format, this.o.language); |
| | 772 | }, this)); |
| | 773 | dates = $.grep(dates, $.proxy(function(date){ |
| | 774 | return ( |
| | 775 | !this.dateWithinRange(date) || |
| | 776 | !date |
| | 777 | ); |
| | 778 | }, this), true); |
| | 779 | this.dates.replace(dates); |
| | 780 | |
| | 781 | if (this.dates.length) |
| | 782 | this.viewDate = new Date(this.dates.get(-1)); |
| | 783 | else if (this.viewDate < this.o.startDate) |
| | 784 | this.viewDate = new Date(this.o.startDate); |
| | 785 | else if (this.viewDate > this.o.endDate) |
| | 786 | this.viewDate = new Date(this.o.endDate); |
| | 787 | else |
| | 788 | this.viewDate = this.o.defaultViewDate; |
| | 789 | |
| | 790 | if (fromArgs){ |
| | 791 | // setting date by clicking |
| | 792 | this.setValue(); |
| | 793 | } |
| | 794 | else if (dates.length){ |
| | 795 | // setting date by typing |
| | 796 | if (String(oldDates) !== String(this.dates)) |
| | 797 | this._trigger('changeDate'); |
| | 798 | } |
| | 799 | if (!this.dates.length && oldDates.length) |
| | 800 | this._trigger('clearDate'); |
| | 801 | |
| | 802 | this.fill(); |
| | 803 | this.element.change(); |
| | 804 | return this; |
| | 805 | }, |
| | 806 | |
| | 807 | fillDow: function(){ |
| | 808 | var dowCnt = this.o.weekStart, |
| | 809 | html = '<tr>'; |
| | 810 | if (this.o.calendarWeeks){ |
| | 811 | this.picker.find('.datepicker-days .datepicker-switch') |
| | 812 | .attr('colspan', function(i, val){ |
| | 813 | return parseInt(val) + 1; |
| | 814 | }); |
| | 815 | html += '<th class="cw"> </th>'; |
| | 816 | } |
| | 817 | while (dowCnt < this.o.weekStart + 7){ |
| | 818 | html += '<th class="dow">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>'; |
| | 819 | } |
| | 820 | html += '</tr>'; |
| | 821 | this.picker.find('.datepicker-days thead').append(html); |
| | 822 | }, |
| | 823 | |
| | 824 | fillMonths: function(){ |
| | 825 | var html = '', |
| | 826 | i = 0; |
| | 827 | while (i < 12){ |
| | 828 | html += '<span class="month">'+dates[this.o.language].monthsShort[i++]+'</span>'; |
| | 829 | } |
| | 830 | this.picker.find('.datepicker-months td').html(html); |
| | 831 | }, |
| | 832 | |
| | 833 | setRange: function(range){ |
| | 834 | if (!range || !range.length) |
| | 835 | delete this.range; |
| | 836 | else |
| | 837 | this.range = $.map(range, function(d){ |
| | 838 | return d.valueOf(); |
| | 839 | }); |
| | 840 | this.fill(); |
| | 841 | }, |
| | 842 | |
| | 843 | getClassNames: function(date){ |
| | 844 | var cls = [], |
| | 845 | year = this.viewDate.getUTCFullYear(), |
| | 846 | month = this.viewDate.getUTCMonth(), |
| | 847 | today = new Date(); |
| | 848 | if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){ |
| | 849 | cls.push('old'); |
| | 850 | } |
| | 851 | else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){ |
| | 852 | cls.push('new'); |
| | 853 | } |
| | 854 | if (this.focusDate && date.valueOf() === this.focusDate.valueOf()) |
| | 855 | cls.push('focused'); |
| | 856 | // Compare internal UTC date with local today, not UTC today |
| | 857 | if (this.o.todayHighlight && |
| | 858 | date.getUTCFullYear() === today.getFullYear() && |
| | 859 | date.getUTCMonth() === today.getMonth() && |
| | 860 | date.getUTCDate() === today.getDate()){ |
| | 861 | cls.push('today'); |
| | 862 | } |
| | 863 | if (this.dates.contains(date) !== -1) |
| | 864 | cls.push('active'); |
| | 865 | if (!this.dateWithinRange(date) || this.dateIsDisabled(date)){ |
| | 866 | cls.push('disabled'); |
| | 867 | } |
| | 868 | if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){ |
| | 869 | cls.push('highlighted'); |
| | 870 | } |
| | 871 | |
| | 872 | if (this.range){ |
| | 873 | if (date > this.range[0] && date < this.range[this.range.length-1]){ |
| | 874 | cls.push('range'); |
| | 875 | } |
| | 876 | if ($.inArray(date.valueOf(), this.range) !== -1){ |
| | 877 | cls.push('selected'); |
| | 878 | } |
| | 879 | if (date.valueOf() === this.range[0]){ |
| | 880 | cls.push('range-start'); |
| | 881 | } |
| | 882 | if (date.valueOf() === this.range[this.range.length-1]){ |
| | 883 | cls.push('range-end'); |
| | 884 | } |
| | 885 | } |
| | 886 | return cls; |
| | 887 | }, |
| | 888 | |
| | 889 | fill: function(){ |
| | 890 | var d = new Date(this.viewDate), |
| | 891 | year = d.getUTCFullYear(), |
| | 892 | month = d.getUTCMonth(), |
| | 893 | startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity, |
| | 894 | startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity, |
| | 895 | endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity, |
| | 896 | endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity, |
| | 897 | todaytxt = dates[this.o.language].today || dates['en'].today || '', |
| | 898 | cleartxt = dates[this.o.language].clear || dates['en'].clear || '', |
| | 899 | titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat, |
| | 900 | tooltip; |
| | 901 | if (isNaN(year) || isNaN(month)) |
| | 902 | return; |
| | 903 | this.picker.find('.datepicker-days thead .datepicker-switch') |
| | 904 | .text(DPGlobal.formatDate(new UTCDate(year, month), titleFormat, this.o.language)); |
| | 905 | this.picker.find('tfoot .today') |
| | 906 | .text(todaytxt) |
| | 907 | .toggle(this.o.todayBtn !== false); |
| | 908 | this.picker.find('tfoot .clear') |
| | 909 | .text(cleartxt) |
| | 910 | .toggle(this.o.clearBtn !== false); |
| | 911 | this.picker.find('thead .datepicker-title') |
| | 912 | .text(this.o.title) |
| | 913 | .toggle(this.o.title !== ''); |
| | 914 | this.updateNavArrows(); |
| | 915 | this.fillMonths(); |
| | 916 | var prevMonth = UTCDate(year, month-1, 28), |
| | 917 | day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); |
| | 918 | prevMonth.setUTCDate(day); |
| | 919 | prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7); |
| | 920 | var nextMonth = new Date(prevMonth); |
| | 921 | if (prevMonth.getUTCFullYear() < 100){ |
| | 922 | nextMonth.setUTCFullYear(prevMonth.getUTCFullYear()); |
| | 923 | } |
| | 924 | nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); |
| | 925 | nextMonth = nextMonth.valueOf(); |
| | 926 | var html = []; |
| | 927 | var clsName; |
| | 928 | while (prevMonth.valueOf() < nextMonth){ |
| | 929 | if (prevMonth.getUTCDay() === this.o.weekStart){ |
| | 930 | html.push('<tr>'); |
| | 931 | if (this.o.calendarWeeks){ |
| | 932 | // ISO 8601: First week contains first thursday. |
| | 933 | // ISO also states week starts on Monday, but we can be more abstract here. |
| | 934 | var |
| | 935 | // Start of current week: based on weekstart/current date |
| | 936 | ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5), |
| | 937 | // Thursday of this week |
| | 938 | th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), |
| | 939 | // First Thursday of year, year from thursday |
| | 940 | yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5), |
| | 941 | // Calendar week: ms between thursdays, div ms per day, div 7 days |
| | 942 | calWeek = (th - yth) / 864e5 / 7 + 1; |
| | 943 | html.push('<td class="cw">'+ calWeek +'</td>'); |
| | 944 | |
| | 945 | } |
| | 946 | } |
| | 947 | clsName = this.getClassNames(prevMonth); |
| | 948 | clsName.push('day'); |
| | 949 | |
| | 950 | if (this.o.beforeShowDay !== $.noop){ |
| | 951 | var before = this.o.beforeShowDay(this._utc_to_local(prevMonth)); |
| | 952 | if (before === undefined) |
| | 953 | before = {}; |
| | 954 | else if (typeof(before) === 'boolean') |
| | 955 | before = {enabled: before}; |
| | 956 | else if (typeof(before) === 'string') |
| | 957 | before = {classes: before}; |
| | 958 | if (before.enabled === false) |
| | 959 | clsName.push('disabled'); |
| | 960 | if (before.classes) |
| | 961 | clsName = clsName.concat(before.classes.split(/\s+/)); |
| | 962 | if (before.tooltip) |
| | 963 | tooltip = before.tooltip; |
| | 964 | } |
| | 965 | |
| | 966 | clsName = $.unique(clsName); |
| | 967 | html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>'); |
| | 968 | tooltip = null; |
| | 969 | if (prevMonth.getUTCDay() === this.o.weekEnd){ |
| | 970 | html.push('</tr>'); |
| | 971 | } |
| | 972 | prevMonth.setUTCDate(prevMonth.getUTCDate()+1); |
| | 973 | } |
| | 974 | this.picker.find('.datepicker-days tbody').empty().append(html.join('')); |
| | 975 | |
| | 976 | var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months'; |
| | 977 | var months = this.picker.find('.datepicker-months') |
| | 978 | .find('.datepicker-switch') |
| | 979 | .text(this.o.maxViewMode < 2 ? monthsTitle : year) |
| | 980 | .end() |
| | 981 | .find('span').removeClass('active'); |
| | 982 | |
| | 983 | $.each(this.dates, function(i, d){ |
| | 984 | if (d.getUTCFullYear() === year) |
| | 985 | months.eq(d.getUTCMonth()).addClass('active'); |
| | 986 | }); |
| | 987 | |
| | 988 | if (year < startYear || year > endYear){ |
| | 989 | months.addClass('disabled'); |
| | 990 | } |
| | 991 | if (year === startYear){ |
| | 992 | months.slice(0, startMonth).addClass('disabled'); |
| | 993 | } |
| | 994 | if (year === endYear){ |
| | 995 | months.slice(endMonth+1).addClass('disabled'); |
| | 996 | } |
| | 997 | |
| | 998 | if (this.o.beforeShowMonth !== $.noop){ |
| | 999 | var that = this; |
| | 1000 | $.each(months, function(i, month){ |
| | 1001 | if (!$(month).hasClass('disabled')) { |
| | 1002 | var moDate = new Date(year, i, 1); |
| | 1003 | var before = that.o.beforeShowMonth(moDate); |
| | 1004 | if (before === false) |
| | 1005 | $(month).addClass('disabled'); |
| | 1006 | } |
| | 1007 | }); |
| | 1008 | } |
| | 1009 | |
| | 1010 | html = ''; |
| | 1011 | year = parseInt(year/10, 10) * 10; |
| | 1012 | var yearCont = this.picker.find('.datepicker-years') |
| | 1013 | .find('.datepicker-switch') |
| | 1014 | .text(year + '-' + (year + 9)) |
| | 1015 | .end() |
| | 1016 | .find('td'); |
| | 1017 | year -= 1; |
| | 1018 | var years = $.map(this.dates, function(d){ |
| | 1019 | return d.getUTCFullYear(); |
| | 1020 | }), |
| | 1021 | classes; |
| | 1022 | for (var i = -1; i < 11; i++){ |
| | 1023 | classes = ['year']; |
| | 1024 | tooltip = null; |
| | 1025 | |
| | 1026 | if (i === -1) |
| | 1027 | classes.push('old'); |
| | 1028 | else if (i === 10) |
| | 1029 | classes.push('new'); |
| | 1030 | if ($.inArray(year, years) !== -1) |
| | 1031 | classes.push('active'); |
| | 1032 | if (year < startYear || year > endYear) |
| | 1033 | classes.push('disabled'); |
| | 1034 | |
| | 1035 | if (this.o.beforeShowYear !== $.noop) { |
| | 1036 | var yrBefore = this.o.beforeShowYear(new Date(year, 0, 1)); |
| | 1037 | if (yrBefore === undefined) |
| | 1038 | yrBefore = {}; |
| | 1039 | else if (typeof(yrBefore) === 'boolean') |
| | 1040 | yrBefore = {enabled: yrBefore}; |
| | 1041 | else if (typeof(yrBefore) === 'string') |
| | 1042 | yrBefore = {classes: yrBefore}; |
| | 1043 | if (yrBefore.enabled === false) |
| | 1044 | classes.push('disabled'); |
| | 1045 | if (yrBefore.classes) |
| | 1046 | classes = classes.concat(yrBefore.classes.split(/\s+/)); |
| | 1047 | if (yrBefore.tooltip) |
| | 1048 | tooltip = yrBefore.tooltip; |
| | 1049 | } |
| | 1050 | |
| | 1051 | html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>' + year + '</span>'; |
| | 1052 | year += 1; |
| | 1053 | } |
| | 1054 | yearCont.html(html); |
| | 1055 | }, |
| | 1056 | |
| | 1057 | updateNavArrows: function(){ |
| | 1058 | if (!this._allow_update) |
| | 1059 | return; |
| | 1060 | |
| | 1061 | var d = new Date(this.viewDate), |
| | 1062 | year = d.getUTCFullYear(), |
| | 1063 | month = d.getUTCMonth(); |
| | 1064 | switch (this.viewMode){ |
| | 1065 | case 0: |
| | 1066 | if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()){ |
| | 1067 | this.picker.find('.prev').css({visibility: 'hidden'}); |
| | 1068 | } |
| | 1069 | else { |
| | 1070 | this.picker.find('.prev').css({visibility: 'visible'}); |
| | 1071 | } |
| | 1072 | if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()){ |
| | 1073 | this.picker.find('.next').css({visibility: 'hidden'}); |
| | 1074 | } |
| | 1075 | else { |
| | 1076 | this.picker.find('.next').css({visibility: 'visible'}); |
| | 1077 | } |
| | 1078 | break; |
| | 1079 | case 1: |
| | 1080 | case 2: |
| | 1081 | if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() || this.o.maxViewMode < 2){ |
| | 1082 | this.picker.find('.prev').css({visibility: 'hidden'}); |
| | 1083 | } |
| | 1084 | else { |
| | 1085 | this.picker.find('.prev').css({visibility: 'visible'}); |
| | 1086 | } |
| | 1087 | if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() || this.o.maxViewMode < 2){ |
| | 1088 | this.picker.find('.next').css({visibility: 'hidden'}); |
| | 1089 | } |
| | 1090 | else { |
| | 1091 | this.picker.find('.next').css({visibility: 'visible'}); |
| | 1092 | } |
| | 1093 | break; |
| | 1094 | } |
| | 1095 | }, |
| | 1096 | |
| | 1097 | click: function(e){ |
| | 1098 | e.preventDefault(); |
| | 1099 | e.stopPropagation(); |
| | 1100 | var target = $(e.target).closest('span, td, th'), |
| | 1101 | year, month, day; |
| | 1102 | if (target.length === 1){ |
| | 1103 | switch (target[0].nodeName.toLowerCase()){ |
| | 1104 | case 'th': |
| | 1105 | switch (target[0].className){ |
| | 1106 | case 'datepicker-switch': |
| | 1107 | this.showMode(1); |
| | 1108 | break; |
| | 1109 | case 'prev': |
| | 1110 | case 'next': |
| | 1111 | var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1); |
| | 1112 | switch (this.viewMode){ |
| | 1113 | case 0: |
| | 1114 | this.viewDate = this.moveMonth(this.viewDate, dir); |
| | 1115 | this._trigger('changeMonth', this.viewDate); |
| | 1116 | break; |
| | 1117 | case 1: |
| | 1118 | case 2: |
| | 1119 | this.viewDate = this.moveYear(this.viewDate, dir); |
| | 1120 | if (this.viewMode === 1) |
| | 1121 | this._trigger('changeYear', this.viewDate); |
| | 1122 | break; |
| | 1123 | } |
| | 1124 | this.fill(); |
| | 1125 | break; |
| | 1126 | case 'today': |
| | 1127 | this.showMode(-2); |
| | 1128 | var which = this.o.todayBtn === 'linked' ? null : 'view'; |
| | 1129 | this._setDate(UTCToday(), which); |
| | 1130 | break; |
| | 1131 | case 'clear': |
| | 1132 | this.clearDates(); |
| | 1133 | break; |
| | 1134 | } |
| | 1135 | break; |
| | 1136 | case 'span': |
| | 1137 | if (!target.hasClass('disabled')){ |
| | 1138 | this.viewDate.setUTCDate(1); |
| | 1139 | if (target.hasClass('month')){ |
| | 1140 | day = 1; |
| | 1141 | month = target.parent().find('span').index(target); |
| | 1142 | year = this.viewDate.getUTCFullYear(); |
| | 1143 | this.viewDate.setUTCMonth(month); |
| | 1144 | this._trigger('changeMonth', this.viewDate); |
| | 1145 | if (this.o.minViewMode === 1){ |
| | 1146 | this._setDate(UTCDate(year, month, day)); |
| | 1147 | this.showMode(); |
| | 1148 | } else { |
| | 1149 | this.showMode(-1); |
| | 1150 | } |
| | 1151 | } |
| | 1152 | else { |
| | 1153 | day = 1; |
| | 1154 | month = 0; |
| | 1155 | year = parseInt(target.text(), 10)||0; |
| | 1156 | this.viewDate.setUTCFullYear(year); |
| | 1157 | this._trigger('changeYear', this.viewDate); |
| | 1158 | if (this.o.minViewMode === 2){ |
| | 1159 | this._setDate(UTCDate(year, month, day)); |
| | 1160 | } |
| | 1161 | this.showMode(-1); |
| | 1162 | } |
| | 1163 | this.fill(); |
| | 1164 | } |
| | 1165 | break; |
| | 1166 | case 'td': |
| | 1167 | if (target.hasClass('day') && !target.hasClass('disabled')){ |
| | 1168 | day = parseInt(target.text(), 10)||1; |
| | 1169 | year = this.viewDate.getUTCFullYear(); |
| | 1170 | month = this.viewDate.getUTCMonth(); |
| | 1171 | if (target.hasClass('old')){ |
| | 1172 | if (month === 0){ |
| | 1173 | month = 11; |
| | 1174 | year -= 1; |
| | 1175 | } |
| | 1176 | else { |
| | 1177 | month -= 1; |
| | 1178 | } |
| | 1179 | } |
| | 1180 | else if (target.hasClass('new')){ |
| | 1181 | if (month === 11){ |
| | 1182 | month = 0; |
| | 1183 | year += 1; |
| | 1184 | } |
| | 1185 | else { |
| | 1186 | month += 1; |
| | 1187 | } |
| | 1188 | } |
| | 1189 | this._setDate(UTCDate(year, month, day)); |
| | 1190 | } |
| | 1191 | break; |
| | 1192 | } |
| | 1193 | } |
| | 1194 | if (this.picker.is(':visible') && this._focused_from){ |
| | 1195 | $(this._focused_from).focus(); |
| | 1196 | } |
| | 1197 | delete this._focused_from; |
| | 1198 | }, |
| | 1199 | |
| | 1200 | _toggle_multidate: function(date){ |
| | 1201 | var ix = this.dates.contains(date); |
| | 1202 | if (!date){ |
| | 1203 | this.dates.clear(); |
| | 1204 | } |
| | 1205 | |
| | 1206 | if (ix !== -1){ |
| | 1207 | if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){ |
| | 1208 | this.dates.remove(ix); |
| | 1209 | } |
| | 1210 | } else if (this.o.multidate === false) { |
| | 1211 | this.dates.clear(); |
| | 1212 | this.dates.push(date); |
| | 1213 | } |
| | 1214 | else { |
| | 1215 | this.dates.push(date); |
| | 1216 | } |
| | 1217 | |
| | 1218 | if (typeof this.o.multidate === 'number') |
| | 1219 | while (this.dates.length > this.o.multidate) |
| | 1220 | this.dates.remove(0); |
| | 1221 | }, |
| | 1222 | |
| | 1223 | _setDate: function(date, which){ |
| | 1224 | if (!which || which === 'date') |
| | 1225 | this._toggle_multidate(date && new Date(date)); |
| | 1226 | if (!which || which === 'view') |
| | 1227 | this.viewDate = date && new Date(date); |
| | 1228 | |
| | 1229 | this.fill(); |
| | 1230 | this.setValue(); |
| | 1231 | if (!which || which !== 'view') { |
| | 1232 | this._trigger('changeDate'); |
| | 1233 | } |
| | 1234 | var element; |
| | 1235 | if (this.isInput){ |
| | 1236 | element = this.element; |
| | 1237 | } |
| | 1238 | else if (this.component){ |
| | 1239 | element = this.element.find('input'); |
| | 1240 | } |
| | 1241 | if (element){ |
| | 1242 | element.change(); |
| | 1243 | } |
| | 1244 | if (this.o.autoclose && (!which || which === 'date')){ |
| | 1245 | this.hide(); |
| | 1246 | } |
| | 1247 | }, |
| | 1248 | |
| | 1249 | moveDay: function(date, dir){ |
| | 1250 | var newDate = new Date(date); |
| | 1251 | newDate.setUTCDate(date.getUTCDate() + dir); |
| | 1252 | |
| | 1253 | return newDate; |
| | 1254 | }, |
| | 1255 | |
| | 1256 | moveWeek: function(date, dir){ |
| | 1257 | return this.moveDay(date, dir * 7); |
| | 1258 | }, |
| | 1259 | |
| | 1260 | moveMonth: function(date, dir){ |
| | 1261 | if (!isValidDate(date)) |
| | 1262 | return this.o.defaultViewDate; |
| | 1263 | if (!dir) |
| | 1264 | return date; |
| | 1265 | var new_date = new Date(date.valueOf()), |
| | 1266 | day = new_date.getUTCDate(), |
| | 1267 | month = new_date.getUTCMonth(), |
| | 1268 | mag = Math.abs(dir), |
| | 1269 | new_month, test; |
| | 1270 | dir = dir > 0 ? 1 : -1; |
| | 1271 | if (mag === 1){ |
| | 1272 | test = dir === -1 |
| | 1273 | // If going back one month, make sure month is not current month |
| | 1274 | // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) |
| | 1275 | ? function(){ |
| | 1276 | return new_date.getUTCMonth() === month; |
| | 1277 | } |
| | 1278 | // If going forward one month, make sure month is as expected |
| | 1279 | // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) |
| | 1280 | : function(){ |
| | 1281 | return new_date.getUTCMonth() !== new_month; |
| | 1282 | }; |
| | 1283 | new_month = month + dir; |
| | 1284 | new_date.setUTCMonth(new_month); |
| | 1285 | // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 |
| | 1286 | if (new_month < 0 || new_month > 11) |
| | 1287 | new_month = (new_month + 12) % 12; |
| | 1288 | } |
| | 1289 | else { |
| | 1290 | // For magnitudes >1, move one month at a time... |
| | 1291 | for (var i=0; i < mag; i++) |
| | 1292 | // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)... |
| | 1293 | new_date = this.moveMonth(new_date, dir); |
| | 1294 | // ...then reset the day, keeping it in the new month |
| | 1295 | new_month = new_date.getUTCMonth(); |
| | 1296 | new_date.setUTCDate(day); |
| | 1297 | test = function(){ |
| | 1298 | return new_month !== new_date.getUTCMonth(); |
| | 1299 | }; |
| | 1300 | } |
| | 1301 | // Common date-resetting loop -- if date is beyond end of month, make it |
| | 1302 | // end of month |
| | 1303 | while (test()){ |
| | 1304 | new_date.setUTCDate(--day); |
| | 1305 | new_date.setUTCMonth(new_month); |
| | 1306 | } |
| | 1307 | return new_date; |
| | 1308 | }, |
| | 1309 | |
| | 1310 | moveYear: function(date, dir){ |
| | 1311 | return this.moveMonth(date, dir*12); |
| | 1312 | }, |
| | 1313 | |
| | 1314 | moveAvailableDate: function(date, dir, fn){ |
| | 1315 | do { |
| | 1316 | date = this[fn](date, dir); |
| | 1317 | |
| | 1318 | if (!this.dateWithinRange(date)) |
| | 1319 | return false; |
| | 1320 | |
| | 1321 | fn = 'moveDay'; |
| | 1322 | } |
| | 1323 | while (this.dateIsDisabled(date)); |
| | 1324 | |
| | 1325 | return date; |
| | 1326 | }, |
| | 1327 | |
| | 1328 | weekOfDateIsDisabled: function(date){ |
| | 1329 | return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1; |
| | 1330 | }, |
| | 1331 | |
| | 1332 | dateIsDisabled: function(date){ |
| | 1333 | return ( |
| | 1334 | this.weekOfDateIsDisabled(date) || |
| | 1335 | $.grep(this.o.datesDisabled, function(d){ |
| | 1336 | return isUTCEquals(date, d); |
| | 1337 | }).length > 0 |
| | 1338 | ); |
| | 1339 | }, |
| | 1340 | |
| | 1341 | dateWithinRange: function(date){ |
| | 1342 | return date >= this.o.startDate && date <= this.o.endDate; |
| | 1343 | }, |
| | 1344 | |
| | 1345 | keydown: function(e){ |
| | 1346 | if (!this.picker.is(':visible')){ |
| | 1347 | if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker |
| | 1348 | this.show(); |
| | 1349 | e.stopPropagation(); |
| | 1350 | } |
| | 1351 | return; |
| | 1352 | } |
| | 1353 | var dateChanged = false, |
| | 1354 | dir, newViewDate, |
| | 1355 | focusDate = this.focusDate || this.viewDate; |
| | 1356 | switch (e.keyCode){ |
| | 1357 | case 27: // escape |
| | 1358 | if (this.focusDate){ |
| | 1359 | this.focusDate = null; |
| | 1360 | this.viewDate = this.dates.get(-1) || this.viewDate; |
| | 1361 | this.fill(); |
| | 1362 | } |
| | 1363 | else |
| | 1364 | this.hide(); |
| | 1365 | e.preventDefault(); |
| | 1366 | e.stopPropagation(); |
| | 1367 | break; |
| | 1368 | case 37: // left |
| | 1369 | case 38: // up |
| | 1370 | case 39: // right |
| | 1371 | case 40: // down |
| | 1372 | if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7) |
| | 1373 | break; |
| | 1374 | dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1; |
| | 1375 | if (e.ctrlKey){ |
| | 1376 | newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear'); |
| | 1377 | |
| | 1378 | if (newViewDate) |
| | 1379 | this._trigger('changeYear', this.viewDate); |
| | 1380 | } |
| | 1381 | else if (e.shiftKey){ |
| | 1382 | newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth'); |
| | 1383 | |
| | 1384 | if (newViewDate) |
| | 1385 | this._trigger('changeMonth', this.viewDate); |
| | 1386 | } |
| | 1387 | else if (e.keyCode === 37 || e.keyCode === 39){ |
| | 1388 | newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay'); |
| | 1389 | } |
| | 1390 | else if (!this.weekOfDateIsDisabled(focusDate)){ |
| | 1391 | newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek'); |
| | 1392 | } |
| | 1393 | if (newViewDate){ |
| | 1394 | this.focusDate = this.viewDate = newViewDate; |
| | 1395 | this.setValue(); |
| | 1396 | this.fill(); |
| | 1397 | e.preventDefault(); |
| | 1398 | } |
| | 1399 | break; |
| | 1400 | case 13: // enter |
| | 1401 | if (!this.o.forceParse) |
| | 1402 | break; |
| | 1403 | focusDate = this.focusDate || this.dates.get(-1) || this.viewDate; |
| | 1404 | if (this.o.keyboardNavigation) { |
| | 1405 | this._toggle_multidate(focusDate); |
| | 1406 | dateChanged = true; |
| | 1407 | } |
| | 1408 | this.focusDate = null; |
| | 1409 | this.viewDate = this.dates.get(-1) || this.viewDate; |
| | 1410 | this.setValue(); |
| | 1411 | this.fill(); |
| | 1412 | if (this.picker.is(':visible')){ |
| | 1413 | e.preventDefault(); |
| | 1414 | e.stopPropagation(); |
| | 1415 | if (this.o.autoclose) |
| | 1416 | this.hide(); |
| | 1417 | } |
| | 1418 | break; |
| | 1419 | case 9: // tab |
| | 1420 | this.focusDate = null; |
| | 1421 | this.viewDate = this.dates.get(-1) || this.viewDate; |
| | 1422 | this.fill(); |
| | 1423 | this.hide(); |
| | 1424 | break; |
| | 1425 | } |
| | 1426 | if (dateChanged){ |
| | 1427 | if (this.dates.length) |
| | 1428 | this._trigger('changeDate'); |
| | 1429 | else |
| | 1430 | this._trigger('clearDate'); |
| | 1431 | var element; |
| | 1432 | if (this.isInput){ |
| | 1433 | element = this.element; |
| | 1434 | } |
| | 1435 | else if (this.component){ |
| | 1436 | element = this.element.find('input'); |
| | 1437 | } |
| | 1438 | if (element){ |
| | 1439 | element.change(); |
| | 1440 | } |
| | 1441 | } |
| | 1442 | }, |
| | 1443 | |
| | 1444 | showMode: function(dir){ |
| | 1445 | if (dir){ |
| | 1446 | this.viewMode = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, this.viewMode + dir)); |
| | 1447 | } |
| | 1448 | this.picker |
| | 1449 | .children('div') |
| | 1450 | .hide() |
| | 1451 | .filter('.datepicker-' + DPGlobal.modes[this.viewMode].clsName) |
| | 1452 | .show(); |
| | 1453 | this.updateNavArrows(); |
| | 1454 | } |
| | 1455 | }; |
| | 1456 | |
| | 1457 | var DateRangePicker = function(element, options){ |
| | 1458 | $(element).data('datepicker', this); |
| | 1459 | this.element = $(element); |
| | 1460 | this.inputs = $.map(options.inputs, function(i){ |
| | 1461 | return i.jquery ? i[0] : i; |
| | 1462 | }); |
| | 1463 | delete options.inputs; |
| | 1464 | |
| | 1465 | datepickerPlugin.call($(this.inputs), options) |
| | 1466 | .on('changeDate', $.proxy(this.dateUpdated, this)); |
| | 1467 | |
| | 1468 | this.pickers = $.map(this.inputs, function(i){ |
| | 1469 | return $(i).data('datepicker'); |
| | 1470 | }); |
| | 1471 | this.updateDates(); |
| | 1472 | }; |
| | 1473 | DateRangePicker.prototype = { |
| | 1474 | updateDates: function(){ |
| | 1475 | this.dates = $.map(this.pickers, function(i){ |
| | 1476 | return i.getUTCDate(); |
| | 1477 | }); |
| | 1478 | this.updateRanges(); |
| | 1479 | }, |
| | 1480 | updateRanges: function(){ |
| | 1481 | var range = $.map(this.dates, function(d){ |
| | 1482 | return d.valueOf(); |
| | 1483 | }); |
| | 1484 | $.each(this.pickers, function(i, p){ |
| | 1485 | p.setRange(range); |
| | 1486 | }); |
| | 1487 | }, |
| | 1488 | dateUpdated: function(e){ |
| | 1489 | // `this.updating` is a workaround for preventing infinite recursion |
| | 1490 | // between `changeDate` triggering and `setUTCDate` calling. Until |
| | 1491 | // there is a better mechanism. |
| | 1492 | if (this.updating) |
| | 1493 | return; |
| | 1494 | this.updating = true; |
| | 1495 | |
| | 1496 | var dp = $(e.target).data('datepicker'); |
| | 1497 | |
| | 1498 | if (typeof(dp) === "undefined") { |
| | 1499 | return; |
| | 1500 | } |
| | 1501 | |
| | 1502 | var new_date = dp.getUTCDate(), |
| | 1503 | i = $.inArray(e.target, this.inputs), |
| | 1504 | j = i - 1, |
| | 1505 | k = i + 1, |
| | 1506 | l = this.inputs.length; |
| | 1507 | if (i === -1) |
| | 1508 | return; |
| | 1509 | |
| | 1510 | $.each(this.pickers, function(i, p){ |
| | 1511 | if (!p.getUTCDate()) |
| | 1512 | p.setUTCDate(new_date); |
| | 1513 | }); |
| | 1514 | |
| | 1515 | if (new_date < this.dates[j]){ |
| | 1516 | // Date being moved earlier/left |
| | 1517 | while (j >= 0 && new_date < this.dates[j]){ |
| | 1518 | this.pickers[j--].setUTCDate(new_date); |
| | 1519 | } |
| | 1520 | } |
| | 1521 | else if (new_date > this.dates[k]){ |
| | 1522 | // Date being moved later/right |
| | 1523 | while (k < l && new_date > this.dates[k]){ |
| | 1524 | this.pickers[k++].setUTCDate(new_date); |
| | 1525 | } |
| | 1526 | } |
| | 1527 | this.updateDates(); |
| | 1528 | |
| | 1529 | delete this.updating; |
| | 1530 | }, |
| | 1531 | remove: function(){ |
| | 1532 | $.map(this.pickers, function(p){ p.remove(); }); |
| | 1533 | delete this.element.data().datepicker; |
| | 1534 | } |
| | 1535 | }; |
| | 1536 | |
| | 1537 | function opts_from_el(el, prefix){ |
| | 1538 | // Derive options from element data-attrs |
| | 1539 | var data = $(el).data(), |
| | 1540 | out = {}, inkey, |
| | 1541 | replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'); |
| | 1542 | prefix = new RegExp('^' + prefix.toLowerCase()); |
| | 1543 | function re_lower(_,a){ |
| | 1544 | return a.toLowerCase(); |
| | 1545 | } |
| | 1546 | for (var key in data) |
| | 1547 | if (prefix.test(key)){ |
| | 1548 | inkey = key.replace(replace, re_lower); |
| | 1549 | out[inkey] = data[key]; |
| | 1550 | } |
| | 1551 | return out; |
| | 1552 | } |
| | 1553 | |
| | 1554 | function opts_from_locale(lang){ |
| | 1555 | // Derive options from locale plugins |
| | 1556 | var out = {}; |
| | 1557 | // Check if "de-DE" style date is available, if not language should |
| | 1558 | // fallback to 2 letter code eg "de" |
| | 1559 | if (!dates[lang]){ |
| | 1560 | lang = lang.split('-')[0]; |
| | 1561 | if (!dates[lang]) |
| | 1562 | return; |
| | 1563 | } |
| | 1564 | var d = dates[lang]; |
| | 1565 | $.each(locale_opts, function(i,k){ |
| | 1566 | if (k in d) |
| | 1567 | out[k] = d[k]; |
| | 1568 | }); |
| | 1569 | return out; |
| | 1570 | } |
| | 1571 | |
| | 1572 | var old = $.fn.datepicker; |
| | 1573 | var datepickerPlugin = function(option){ |
| | 1574 | var args = Array.apply(null, arguments); |
| | 1575 | args.shift(); |
| | 1576 | var internal_return; |
| | 1577 | this.each(function(){ |
| | 1578 | var $this = $(this), |
| | 1579 | data = $this.data('datepicker'), |
| | 1580 | options = typeof option === 'object' && option; |
| | 1581 | if (!data){ |
| | 1582 | var elopts = opts_from_el(this, 'date'), |
| | 1583 | // Preliminary otions |
| | 1584 | xopts = $.extend({}, defaults, elopts, options), |
| | 1585 | locopts = opts_from_locale(xopts.language), |
| | 1586 | // Options priority: js args, data-attrs, locales, defaults |
| | 1587 | opts = $.extend({}, defaults, locopts, elopts, options); |
| | 1588 | if ($this.hasClass('input-daterange') || opts.inputs){ |
| | 1589 | $.extend(opts, { |
| | 1590 | inputs: opts.inputs || $this.find('input').toArray() |
| | 1591 | }); |
| | 1592 | data = new DateRangePicker(this, opts); |
| | 1593 | } |
| | 1594 | else { |
| | 1595 | data = new Datepicker(this, opts); |
| | 1596 | } |
| | 1597 | $this.data('datepicker', data); |
| | 1598 | } |
| | 1599 | if (typeof option === 'string' && typeof data[option] === 'function'){ |
| | 1600 | internal_return = data[option].apply(data, args); |
| | 1601 | } |
| | 1602 | }); |
| | 1603 | |
| | 1604 | if ( |
| | 1605 | internal_return === undefined || |
| | 1606 | internal_return instanceof Datepicker || |
| | 1607 | internal_return instanceof DateRangePicker |
| | 1608 | ) |
| | 1609 | return this; |
| | 1610 | |
| | 1611 | if (this.length > 1) |
| | 1612 | throw new Error('Using only allowed for the collection of a single element (' + option + ' function)'); |
| | 1613 | else |
| | 1614 | return internal_return; |
| | 1615 | }; |
| | 1616 | $.fn.datepicker = datepickerPlugin; |
| | 1617 | |
| | 1618 | var defaults = $.fn.datepicker.defaults = { |
| | 1619 | autoclose: false, |
| | 1620 | beforeShowDay: $.noop, |
| | 1621 | beforeShowMonth: $.noop, |
| | 1622 | beforeShowYear: $.noop, |
| | 1623 | calendarWeeks: false, |
| | 1624 | clearBtn: false, |
| | 1625 | toggleActive: false, |
| | 1626 | daysOfWeekDisabled: [], |
| | 1627 | daysOfWeekHighlighted: [], |
| | 1628 | datesDisabled: [], |
| | 1629 | endDate: Infinity, |
| | 1630 | forceParse: true, |
| | 1631 | format: 'mm/dd/yyyy', |
| | 1632 | keyboardNavigation: true, |
| | 1633 | language: 'en', |
| | 1634 | minViewMode: 0, |
| | 1635 | maxViewMode: 2, |
| | 1636 | multidate: false, |
| | 1637 | multidateSeparator: ',', |
| | 1638 | orientation: "auto", |
| | 1639 | rtl: false, |
| | 1640 | startDate: -Infinity, |
| | 1641 | startView: 0, |
| | 1642 | todayBtn: false, |
| | 1643 | todayHighlight: false, |
| | 1644 | weekStart: 0, |
| | 1645 | disableTouchKeyboard: false, |
| | 1646 | enableOnReadonly: true, |
| | 1647 | showOnFocus: true, |
| | 1648 | zIndexOffset: 10, |
| | 1649 | container: 'body', |
| | 1650 | immediateUpdates: false, |
| | 1651 | title: '' |
| | 1652 | }; |
| | 1653 | var locale_opts = $.fn.datepicker.locale_opts = [ |
| | 1654 | 'format', |
| | 1655 | 'rtl', |
| | 1656 | 'weekStart' |
| | 1657 | ]; |
| | 1658 | $.fn.datepicker.Constructor = Datepicker; |
| | 1659 | var dates = $.fn.datepicker.dates = { |
| | 1660 | en: { |
| | 1661 | days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], |
| | 1662 | daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], |
| | 1663 | daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], |
| | 1664 | months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], |
| | 1665 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], |
| | 1666 | today: "Today", |
| | 1667 | clear: "Clear", |
| | 1668 | titleFormat: "MM yyyy" |
| | 1669 | } |
| | 1670 | }; |
| | 1671 | |
| | 1672 | var DPGlobal = { |
| | 1673 | modes: [ |
| | 1674 | { |
| | 1675 | clsName: 'days', |
| | 1676 | navFnc: 'Month', |
| | 1677 | navStep: 1 |
| | 1678 | }, |
| | 1679 | { |
| | 1680 | clsName: 'months', |
| | 1681 | navFnc: 'FullYear', |
| | 1682 | navStep: 1 |
| | 1683 | }, |
| | 1684 | { |
| | 1685 | clsName: 'years', |
| | 1686 | navFnc: 'FullYear', |
| | 1687 | navStep: 10 |
| | 1688 | }], |
| | 1689 | isLeapYear: function(year){ |
| | 1690 | return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); |
| | 1691 | }, |
| | 1692 | getDaysInMonth: function(year, month){ |
| | 1693 | return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; |
| | 1694 | }, |
| | 1695 | validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, |
| | 1696 | nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, |
| | 1697 | parseFormat: function(format){ |
| | 1698 | if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function') |
| | 1699 | return format; |
| | 1700 | // IE treats \0 as a string end in inputs (truncating the value), |
| | 1701 | // so it's a bad format delimiter, anyway |
| | 1702 | var separators = format.replace(this.validParts, '\0').split('\0'), |
| | 1703 | parts = format.match(this.validParts); |
| | 1704 | if (!separators || !separators.length || !parts || parts.length === 0){ |
| | 1705 | throw new Error("Invalid date format."); |
| | 1706 | } |
| | 1707 | return {separators: separators, parts: parts}; |
| | 1708 | }, |
| | 1709 | parseDate: function(date, format, language){ |
| | 1710 | if (!date) |
| | 1711 | return undefined; |
| | 1712 | if (date instanceof Date) |
| | 1713 | return date; |
| | 1714 | if (typeof format === 'string') |
| | 1715 | format = DPGlobal.parseFormat(format); |
| | 1716 | if (format.toValue) |
| | 1717 | return format.toValue(date, format, language); |
| | 1718 | var part_re = /([\-+]\d+)([dmwy])/, |
| | 1719 | parts = date.match(/([\-+]\d+)([dmwy])/g), |
| | 1720 | fn_map = { |
| | 1721 | d: 'moveDay', |
| | 1722 | m: 'moveMonth', |
| | 1723 | w: 'moveWeek', |
| | 1724 | y: 'moveYear' |
| | 1725 | }, |
| | 1726 | part, dir, i, fn; |
| | 1727 | if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){ |
| | 1728 | date = new Date(); |
| | 1729 | for (i=0; i < parts.length; i++){ |
| | 1730 | part = part_re.exec(parts[i]); |
| | 1731 | dir = parseInt(part[1]); |
| | 1732 | fn = fn_map[part[2]]; |
| | 1733 | date = Datepicker.prototype[fn](date, dir); |
| | 1734 | } |
| | 1735 | return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); |
| | 1736 | } |
| | 1737 | parts = date && date.match(this.nonpunctuation) || []; |
| | 1738 | date = new Date(); |
| | 1739 | var parsed = {}, |
| | 1740 | setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'], |
| | 1741 | setters_map = { |
| | 1742 | yyyy: function(d,v){ |
| | 1743 | return d.setUTCFullYear(v); |
| | 1744 | }, |
| | 1745 | yy: function(d,v){ |
| | 1746 | return d.setUTCFullYear(2000+v); |
| | 1747 | }, |
| | 1748 | m: function(d,v){ |
| | 1749 | if (isNaN(d)) |
| | 1750 | return d; |
| | 1751 | v -= 1; |
| | 1752 | while (v < 0) v += 12; |
| | 1753 | v %= 12; |
| | 1754 | d.setUTCMonth(v); |
| | 1755 | while (d.getUTCMonth() !== v) |
| | 1756 | d.setUTCDate(d.getUTCDate()-1); |
| | 1757 | return d; |
| | 1758 | }, |
| | 1759 | d: function(d,v){ |
| | 1760 | return d.setUTCDate(v); |
| | 1761 | } |
| | 1762 | }, |
| | 1763 | val, filtered; |
| | 1764 | setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m']; |
| | 1765 | setters_map['dd'] = setters_map['d']; |
| | 1766 | date = UTCToday(); |
| | 1767 | var fparts = format.parts.slice(); |
| | 1768 | // Remove noop parts |
| | 1769 | if (parts.length !== fparts.length){ |
| | 1770 | fparts = $(fparts).filter(function(i,p){ |
| | 1771 | return $.inArray(p, setters_order) !== -1; |
| | 1772 | }).toArray(); |
| | 1773 | } |
| | 1774 | // Process remainder |
| | 1775 | function match_part(){ |
| | 1776 | var m = this.slice(0, parts[i].length), |
| | 1777 | p = parts[i].slice(0, m.length); |
| | 1778 | return m.toLowerCase() === p.toLowerCase(); |
| | 1779 | } |
| | 1780 | if (parts.length === fparts.length){ |
| | 1781 | var cnt; |
| | 1782 | for (i=0, cnt = fparts.length; i < cnt; i++){ |
| | 1783 | val = parseInt(parts[i], 10); |
| | 1784 | part = fparts[i]; |
| | 1785 | if (isNaN(val)){ |
| | 1786 | switch (part){ |
| | 1787 | case 'MM': |
| | 1788 | filtered = $(dates[language].months).filter(match_part); |
| | 1789 | val = $.inArray(filtered[0], dates[language].months) + 1; |
| | 1790 | break; |
| | 1791 | case 'M': |
| | 1792 | filtered = $(dates[language].monthsShort).filter(match_part); |
| | 1793 | val = $.inArray(filtered[0], dates[language].monthsShort) + 1; |
| | 1794 | break; |
| | 1795 | } |
| | 1796 | } |
| | 1797 | parsed[part] = val; |
| | 1798 | } |
| | 1799 | var _date, s; |
| | 1800 | for (i=0; i < setters_order.length; i++){ |
| | 1801 | s = setters_order[i]; |
| | 1802 | if (s in parsed && !isNaN(parsed[s])){ |
| | 1803 | _date = new Date(date); |
| | 1804 | setters_map[s](_date, parsed[s]); |
| | 1805 | if (!isNaN(_date)) |
| | 1806 | date = _date; |
| | 1807 | } |
| | 1808 | } |
| | 1809 | } |
| | 1810 | return date; |
| | 1811 | }, |
| | 1812 | formatDate: function(date, format, language){ |
| | 1813 | if (!date) |
| | 1814 | return ''; |
| | 1815 | if (typeof format === 'string') |
| | 1816 | format = DPGlobal.parseFormat(format); |
| | 1817 | if (format.toDisplay) |
| | 1818 | return format.toDisplay(date, format, language); |
| | 1819 | var val = { |
| | 1820 | d: date.getUTCDate(), |
| | 1821 | D: dates[language].daysShort[date.getUTCDay()], |
| | 1822 | DD: dates[language].days[date.getUTCDay()], |
| | 1823 | m: date.getUTCMonth() + 1, |
| | 1824 | M: dates[language].monthsShort[date.getUTCMonth()], |
| | 1825 | MM: dates[language].months[date.getUTCMonth()], |
| | 1826 | yy: date.getUTCFullYear().toString().substring(2), |
| | 1827 | yyyy: date.getUTCFullYear() |
| | 1828 | }; |
| | 1829 | val.dd = (val.d < 10 ? '0' : '') + val.d; |
| | 1830 | val.mm = (val.m < 10 ? '0' : '') + val.m; |
| | 1831 | date = []; |
| | 1832 | var seps = $.extend([], format.separators); |
| | 1833 | for (var i=0, cnt = format.parts.length; i <= cnt; i++){ |
| | 1834 | if (seps.length) |
| | 1835 | date.push(seps.shift()); |
| | 1836 | date.push(val[format.parts[i]]); |
| | 1837 | } |
| | 1838 | return date.join(''); |
| | 1839 | }, |
| | 1840 | headTemplate: '<thead>'+ |
| | 1841 | '<tr>'+ |
| | 1842 | '<th colspan="7" class="datepicker-title"></th>'+ |
| | 1843 | '</tr>'+ |
| | 1844 | '<tr>'+ |
| | 1845 | '<th class="prev">«</th>'+ |
| | 1846 | '<th colspan="5" class="datepicker-switch"></th>'+ |
| | 1847 | '<th class="next">»</th>'+ |
| | 1848 | '</tr>'+ |
| | 1849 | '</thead>', |
| | 1850 | contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>', |
| | 1851 | footTemplate: '<tfoot>'+ |
| | 1852 | '<tr>'+ |
| | 1853 | '<th colspan="7" class="today"></th>'+ |
| | 1854 | '</tr>'+ |
| | 1855 | '<tr>'+ |
| | 1856 | '<th colspan="7" class="clear"></th>'+ |
| | 1857 | '</tr>'+ |
| | 1858 | '</tfoot>' |
| | 1859 | }; |
| | 1860 | DPGlobal.template = '<div class="datepicker">'+ |
| | 1861 | '<div class="datepicker-days">'+ |
| | 1862 | '<table class=" table-condensed">'+ |
| | 1863 | DPGlobal.headTemplate+ |
| | 1864 | '<tbody></tbody>'+ |
| | 1865 | DPGlobal.footTemplate+ |
| | 1866 | '</table>'+ |
| | 1867 | '</div>'+ |
| | 1868 | '<div class="datepicker-months">'+ |
| | 1869 | '<table class="table-condensed">'+ |
| | 1870 | DPGlobal.headTemplate+ |
| | 1871 | DPGlobal.contTemplate+ |
| | 1872 | DPGlobal.footTemplate+ |
| | 1873 | '</table>'+ |
| | 1874 | '</div>'+ |
| | 1875 | '<div class="datepicker-years">'+ |
| | 1876 | '<table class="table-condensed">'+ |
| | 1877 | DPGlobal.headTemplate+ |
| | 1878 | DPGlobal.contTemplate+ |
| | 1879 | DPGlobal.footTemplate+ |
| | 1880 | '</table>'+ |
| | 1881 | '</div>'+ |
| | 1882 | '</div>'; |
| | 1883 | |
| | 1884 | $.fn.datepicker.DPGlobal = DPGlobal; |
| | 1885 | |
| | 1886 | |
| | 1887 | /* DATEPICKER NO CONFLICT |
| | 1888 | * =================== */ |
| | 1889 | |
| | 1890 | $.fn.datepicker.noConflict = function(){ |
| | 1891 | $.fn.datepicker = old; |
| | 1892 | return this; |
| | 1893 | }; |
| | 1894 | |
| | 1895 | /* DATEPICKER VERSION |
| | 1896 | * =================== */ |
| | 1897 | $.fn.datepicker.version = '1.5.1'; |
| | 1898 | |
| | 1899 | /* DATEPICKER DATA-API |
| | 1900 | * ================== */ |
| | 1901 | |
| | 1902 | $(document).on( |
| | 1903 | 'focus.datepicker.data-api click.datepicker.data-api', |
| | 1904 | '[data-provide="datepicker"]', |
| | 1905 | function(e){ |
| | 1906 | var $this = $(this); |
| | 1907 | if ($this.data('datepicker')) |
| | 1908 | return; |
| | 1909 | e.preventDefault(); |
| | 1910 | // component click requires us to explicitly show it |
| | 1911 | datepickerPlugin.call($this, 'show'); |
| | 1912 | } |
| | 1913 | ); |
| | 1914 | $(function(){ |
| | 1915 | datepickerPlugin.call($('[data-provide="datepicker-inline"]')); |
| | 1916 | }); |
| | 1917 | |
| | 1918 | })); |