Path: blob/master/web-gui/buildyourownbotnet/assets/js/bootstrap-datepicker.js
1292 views
/* =========================================================1* bootstrap-datepicker.js2* http://www.eyecon.ro/bootstrap-datepicker3* =========================================================4* Copyright 2012 Stefan Petre5* Improvements by Andrew Rowls6*7* Licensed under the Apache License, Version 2.0 (the "License");8* you may not use this file except in compliance with the License.9* You may obtain a copy of the License at10*11* http://www.apache.org/licenses/LICENSE-2.012*13* Unless required by applicable law or agreed to in writing, software14* distributed under the License is distributed on an "AS IS" BASIS,15* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.16* See the License for the specific language governing permissions and17* limitations under the License.18* ========================================================= */1920(function( $ ) {2122var $window = $(window);2324function UTCDate(){25return new Date(Date.UTC.apply(Date, arguments));26}27function UTCToday(){28var today = new Date();29return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());30}313233// Picker object3435var Datepicker = function(element, options) {36var that = this;3738this._process_options(options);3940this.element = $(element);41this.isInline = false;42this.isInput = this.element.is('input');43this.component = this.element.is('.date') ? this.element.find('.add-on, .btn') : false;44this.hasInput = this.component && this.element.find('input').length;45if(this.component && this.component.length === 0)46this.component = false;4748this.picker = $(DPGlobal.template);49this._buildEvents();50this._attachEvents();5152if(this.isInline) {53this.picker.addClass('datepicker-inline').appendTo(this.element);54} else {55this.picker.addClass('datepicker-dropdown dropdown-menu');56}5758if (this.o.rtl){59this.picker.addClass('datepicker-rtl');60this.picker.find('.prev i, .next i')61.toggleClass('icon-arrow-left icon-arrow-right');62}636465this.viewMode = this.o.startView;6667if (this.o.calendarWeeks)68this.picker.find('tfoot th.today')69.attr('colspan', function(i, val){70return parseInt(val) + 1;71});7273this._allow_update = false;7475this.setStartDate(this._o.startDate);76this.setEndDate(this._o.endDate);77this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);7879this.fillDow();80this.fillMonths();8182this._allow_update = true;8384this.update();85this.showMode();8687if(this.isInline) {88this.show();89}90};9192Datepicker.prototype = {93constructor: Datepicker,9495_process_options: function(opts){96// Store raw options for reference97this._o = $.extend({}, this._o, opts);98// Processed options99var o = this.o = $.extend({}, this._o);100101// Check if "de-DE" style date is available, if not language should102// fallback to 2 letter code eg "de"103var lang = o.language;104if (!dates[lang]) {105lang = lang.split('-')[0];106if (!dates[lang])107lang = defaults.language;108}109o.language = lang;110111switch(o.startView){112case 2:113case 'decade':114o.startView = 2;115break;116case 1:117case 'year':118o.startView = 1;119break;120default:121o.startView = 0;122}123124switch (o.minViewMode) {125case 1:126case 'months':127o.minViewMode = 1;128break;129case 2:130case 'years':131o.minViewMode = 2;132break;133default:134o.minViewMode = 0;135}136137o.startView = Math.max(o.startView, o.minViewMode);138139o.weekStart %= 7;140o.weekEnd = ((o.weekStart + 6) % 7);141142var format = DPGlobal.parseFormat(o.format);143if (o.startDate !== -Infinity) {144if (!!o.startDate) {145if (o.startDate instanceof Date)146o.startDate = this._local_to_utc(this._zero_time(o.startDate));147else148o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);149} else {150o.startDate = -Infinity;151}152}153if (o.endDate !== Infinity) {154if (!!o.endDate) {155if (o.endDate instanceof Date)156o.endDate = this._local_to_utc(this._zero_time(o.endDate));157else158o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);159} else {160o.endDate = Infinity;161}162}163164o.daysOfWeekDisabled = o.daysOfWeekDisabled||[];165if (!$.isArray(o.daysOfWeekDisabled))166o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);167o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function (d) {168return parseInt(d, 10);169});170171var plc = String(o.orientation).toLowerCase().split(/\s+/g),172_plc = o.orientation.toLowerCase();173plc = $.grep(plc, function(word){174return (/^auto|left|right|top|bottom$/).test(word);175});176o.orientation = {x: 'auto', y: 'auto'};177if (!_plc || _plc === 'auto')178; // no action179else if (plc.length === 1){180switch(plc[0]){181case 'top':182case 'bottom':183o.orientation.y = plc[0];184break;185case 'left':186case 'right':187o.orientation.x = plc[0];188break;189}190}191else {192_plc = $.grep(plc, function(word){193return (/^left|right$/).test(word);194});195o.orientation.x = _plc[0] || 'auto';196197_plc = $.grep(plc, function(word){198return (/^top|bottom$/).test(word);199});200o.orientation.y = _plc[0] || 'auto';201}202},203_events: [],204_secondaryEvents: [],205_applyEvents: function(evs){206for (var i=0, el, ev; i<evs.length; i++){207el = evs[i][0];208ev = evs[i][1];209el.on(ev);210}211},212_unapplyEvents: function(evs){213for (var i=0, el, ev; i<evs.length; i++){214el = evs[i][0];215ev = evs[i][1];216el.off(ev);217}218},219_buildEvents: function(){220if (this.isInput) { // single input221this._events = [222[this.element, {223focus: $.proxy(this.show, this),224keyup: $.proxy(this.update, this),225keydown: $.proxy(this.keydown, this)226}]227];228}229else if (this.component && this.hasInput){ // component: input + button230this._events = [231// For components that are not readonly, allow keyboard nav232[this.element.find('input'), {233focus: $.proxy(this.show, this),234keyup: $.proxy(this.update, this),235keydown: $.proxy(this.keydown, this)236}],237[this.component, {238click: $.proxy(this.show, this)239}]240];241}242else if (this.element.is('div')) { // inline datepicker243this.isInline = true;244}245else {246this._events = [247[this.element, {248click: $.proxy(this.show, this)249}]250];251}252253this._secondaryEvents = [254[this.picker, {255click: $.proxy(this.click, this)256}],257[$(window), {258resize: $.proxy(this.place, this)259}],260[$(document), {261mousedown: $.proxy(function (e) {262// Clicked outside the datepicker, hide it263if (!(264this.element.is(e.target) ||265this.element.find(e.target).length ||266this.picker.is(e.target) ||267this.picker.find(e.target).length268)) {269this.hide();270}271}, this)272}]273];274},275_attachEvents: function(){276this._detachEvents();277this._applyEvents(this._events);278},279_detachEvents: function(){280this._unapplyEvents(this._events);281},282_attachSecondaryEvents: function(){283this._detachSecondaryEvents();284this._applyEvents(this._secondaryEvents);285},286_detachSecondaryEvents: function(){287this._unapplyEvents(this._secondaryEvents);288},289_trigger: function(event, altdate){290var date = altdate || this.date,291local_date = this._utc_to_local(date);292293this.element.trigger({294type: event,295date: local_date,296format: $.proxy(function(altformat){297var format = altformat || this.o.format;298return DPGlobal.formatDate(date, format, this.o.language);299}, this)300});301},302303show: function(e) {304if (!this.isInline)305this.picker.appendTo('body');306this.picker.show();307this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();308this.place();309this._attachSecondaryEvents();310if (e) {311e.preventDefault();312}313this._trigger('show');314},315316hide: function(e){317if(this.isInline) return;318if (!this.picker.is(':visible')) return;319this.picker.hide().detach();320this._detachSecondaryEvents();321this.viewMode = this.o.startView;322this.showMode();323324if (325this.o.forceParse &&326(327this.isInput && this.element.val() ||328this.hasInput && this.element.find('input').val()329)330)331this.setValue();332this._trigger('hide');333},334335remove: function() {336this.hide();337this._detachEvents();338this._detachSecondaryEvents();339this.picker.remove();340delete this.element.data().datepicker;341if (!this.isInput) {342delete this.element.data().date;343}344},345346_utc_to_local: function(utc){347return new Date(utc.getTime() + (utc.getTimezoneOffset()*60000));348},349_local_to_utc: function(local){350return new Date(local.getTime() - (local.getTimezoneOffset()*60000));351},352_zero_time: function(local){353return new Date(local.getFullYear(), local.getMonth(), local.getDate());354},355_zero_utc_time: function(utc){356return new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));357},358359getDate: function() {360return this._utc_to_local(this.getUTCDate());361},362363getUTCDate: function() {364return this.date;365},366367setDate: function(d) {368this.setUTCDate(this._local_to_utc(d));369},370371setUTCDate: function(d) {372this.date = d;373this.setValue();374},375376setValue: function() {377var formatted = this.getFormattedDate();378if (!this.isInput) {379if (this.component){380this.element.find('input').val(formatted).change();381}382} else {383this.element.val(formatted).change();384}385},386387getFormattedDate: function(format) {388if (format === undefined)389format = this.o.format;390return DPGlobal.formatDate(this.date, format, this.o.language);391},392393setStartDate: function(startDate){394this._process_options({startDate: startDate});395this.update();396this.updateNavArrows();397},398399setEndDate: function(endDate){400this._process_options({endDate: endDate});401this.update();402this.updateNavArrows();403},404405setDaysOfWeekDisabled: function(daysOfWeekDisabled){406this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});407this.update();408this.updateNavArrows();409},410411place: function(){412if(this.isInline) return;413var calendarWidth = this.picker.outerWidth(),414calendarHeight = this.picker.outerHeight(),415visualPadding = 10,416windowWidth = $window.width(),417windowHeight = $window.height(),418scrollTop = $window.scrollTop();419420var zIndex = parseInt(this.element.parents().filter(function() {421return $(this).css('z-index') != 'auto';422}).first().css('z-index'))+10;423var offset = this.component ? this.component.parent().offset() : this.element.offset();424var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);425var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);426var left = offset.left,427top = offset.top;428429this.picker.removeClass(430'datepicker-orient-top datepicker-orient-bottom '+431'datepicker-orient-right datepicker-orient-left'432);433434if (this.o.orientation.x !== 'auto') {435this.picker.addClass('datepicker-orient-' + this.o.orientation.x);436if (this.o.orientation.x === 'right')437left -= calendarWidth - width;438}439// auto x orientation is best-placement: if it crosses a window440// edge, fudge it sideways441else {442// Default to left443this.picker.addClass('datepicker-orient-left');444if (offset.left < 0)445left -= offset.left - visualPadding;446else if (offset.left + calendarWidth > windowWidth)447left = windowWidth - calendarWidth - visualPadding;448}449450// auto y orientation is best-situation: top or bottom, no fudging,451// decision based on which shows more of the calendar452var yorient = this.o.orientation.y,453top_overflow, bottom_overflow;454if (yorient === 'auto') {455top_overflow = -scrollTop + offset.top - calendarHeight;456bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight);457if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)458yorient = 'top';459else460yorient = 'bottom';461}462this.picker.addClass('datepicker-orient-' + yorient);463if (yorient === 'top')464top += height;465else466top -= calendarHeight + parseInt(this.picker.css('padding-top'));467468this.picker.css({469top: top,470left: left,471zIndex: zIndex472});473},474475_allow_update: true,476update: function(){477if (!this._allow_update) return;478479var oldDate = new Date(this.date),480date, fromArgs = false;481if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {482date = arguments[0];483if (date instanceof Date)484date = this._local_to_utc(date);485fromArgs = true;486} else {487date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val();488delete this.element.data().date;489}490491this.date = DPGlobal.parseDate(date, this.o.format, this.o.language);492493if (fromArgs) {494// setting date by clicking495this.setValue();496} else if (date) {497// setting date by typing498if (oldDate.getTime() !== this.date.getTime())499this._trigger('changeDate');500} else {501// clearing date502this._trigger('clearDate');503}504505if (this.date < this.o.startDate) {506this.viewDate = new Date(this.o.startDate);507this.date = new Date(this.o.startDate);508} else if (this.date > this.o.endDate) {509this.viewDate = new Date(this.o.endDate);510this.date = new Date(this.o.endDate);511} else {512this.viewDate = new Date(this.date);513this.date = new Date(this.date);514}515this.fill();516},517518fillDow: function(){519var dowCnt = this.o.weekStart,520html = '<tr>';521if(this.o.calendarWeeks){522var cell = '<th class="cw"> </th>';523html += cell;524this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);525}526while (dowCnt < this.o.weekStart + 7) {527html += '<th class="dow">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';528}529html += '</tr>';530this.picker.find('.datepicker-days thead').append(html);531},532533fillMonths: function(){534var html = '',535i = 0;536while (i < 12) {537html += '<span class="month">'+dates[this.o.language].monthsShort[i++]+'</span>';538}539this.picker.find('.datepicker-months td').html(html);540},541542setRange: function(range){543if (!range || !range.length)544delete this.range;545else546this.range = $.map(range, function(d){ return d.valueOf(); });547this.fill();548},549550getClassNames: function(date){551var cls = [],552year = this.viewDate.getUTCFullYear(),553month = this.viewDate.getUTCMonth(),554currentDate = this.date.valueOf(),555today = new Date();556if (date.getUTCFullYear() < year || (date.getUTCFullYear() == year && date.getUTCMonth() < month)) {557cls.push('old');558} else if (date.getUTCFullYear() > year || (date.getUTCFullYear() == year && date.getUTCMonth() > month)) {559cls.push('new');560}561// Compare internal UTC date with local today, not UTC today562if (this.o.todayHighlight &&563date.getUTCFullYear() == today.getFullYear() &&564date.getUTCMonth() == today.getMonth() &&565date.getUTCDate() == today.getDate()) {566cls.push('today');567}568if (currentDate && date.valueOf() == currentDate) {569cls.push('active');570}571if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||572$.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1) {573cls.push('disabled');574}575if (this.range){576if (date > this.range[0] && date < this.range[this.range.length-1]){577cls.push('range');578}579if ($.inArray(date.valueOf(), this.range) != -1){580cls.push('selected');581}582}583return cls;584},585586fill: function() {587var d = new Date(this.viewDate),588year = d.getUTCFullYear(),589month = d.getUTCMonth(),590startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,591startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,592endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,593endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,594currentDate = this.date && this.date.valueOf(),595tooltip;596this.picker.find('.datepicker-days thead th.datepicker-switch')597.text(dates[this.o.language].months[month]+' '+year);598this.picker.find('tfoot th.today')599.text(dates[this.o.language].today)600.toggle(this.o.todayBtn !== false);601this.picker.find('tfoot th.clear')602.text(dates[this.o.language].clear)603.toggle(this.o.clearBtn !== false);604this.updateNavArrows();605this.fillMonths();606var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),607day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());608prevMonth.setUTCDate(day);609prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);610var nextMonth = new Date(prevMonth);611nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);612nextMonth = nextMonth.valueOf();613var html = [];614var clsName;615while(prevMonth.valueOf() < nextMonth) {616if (prevMonth.getUTCDay() == this.o.weekStart) {617html.push('<tr>');618if(this.o.calendarWeeks){619// ISO 8601: First week contains first thursday.620// ISO also states week starts on Monday, but we can be more abstract here.621var622// Start of current week: based on weekstart/current date623ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),624// Thursday of this week625th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),626// First Thursday of year, year from thursday627yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),628// Calendar week: ms between thursdays, div ms per day, div 7 days629calWeek = (th - yth) / 864e5 / 7 + 1;630html.push('<td class="cw">'+ calWeek +'</td>');631632}633}634clsName = this.getClassNames(prevMonth);635clsName.push('day');636637if (this.o.beforeShowDay !== $.noop){638var before = this.o.beforeShowDay(this._utc_to_local(prevMonth));639if (before === undefined)640before = {};641else if (typeof(before) === 'boolean')642before = {enabled: before};643else if (typeof(before) === 'string')644before = {classes: before};645if (before.enabled === false)646clsName.push('disabled');647if (before.classes)648clsName = clsName.concat(before.classes.split(/\s+/));649if (before.tooltip)650tooltip = before.tooltip;651}652653clsName = $.unique(clsName);654html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>');655if (prevMonth.getUTCDay() == this.o.weekEnd) {656html.push('</tr>');657}658prevMonth.setUTCDate(prevMonth.getUTCDate()+1);659}660this.picker.find('.datepicker-days tbody').empty().append(html.join(''));661var currentYear = this.date && this.date.getUTCFullYear();662663var months = this.picker.find('.datepicker-months')664.find('th:eq(1)')665.text(year)666.end()667.find('span').removeClass('active');668if (currentYear && currentYear == year) {669months.eq(this.date.getUTCMonth()).addClass('active');670}671if (year < startYear || year > endYear) {672months.addClass('disabled');673}674if (year == startYear) {675months.slice(0, startMonth).addClass('disabled');676}677if (year == endYear) {678months.slice(endMonth+1).addClass('disabled');679}680681html = '';682year = parseInt(year/10, 10) * 10;683var yearCont = this.picker.find('.datepicker-years')684.find('th:eq(1)')685.text(year + '-' + (year + 9))686.end()687.find('td');688year -= 1;689for (var i = -1; i < 11; i++) {690html += '<span class="year'+(i == -1 ? ' old' : i == 10 ? ' new' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>';691year += 1;692}693yearCont.html(html);694},695696updateNavArrows: function() {697if (!this._allow_update) return;698699var d = new Date(this.viewDate),700year = d.getUTCFullYear(),701month = d.getUTCMonth();702switch (this.viewMode) {703case 0:704if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()) {705this.picker.find('.prev').css({visibility: 'hidden'});706} else {707this.picker.find('.prev').css({visibility: 'visible'});708}709if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()) {710this.picker.find('.next').css({visibility: 'hidden'});711} else {712this.picker.find('.next').css({visibility: 'visible'});713}714break;715case 1:716case 2:717if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()) {718this.picker.find('.prev').css({visibility: 'hidden'});719} else {720this.picker.find('.prev').css({visibility: 'visible'});721}722if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()) {723this.picker.find('.next').css({visibility: 'hidden'});724} else {725this.picker.find('.next').css({visibility: 'visible'});726}727break;728}729},730731click: function(e) {732e.preventDefault();733var target = $(e.target).closest('span, td, th');734if (target.length == 1) {735switch(target[0].nodeName.toLowerCase()) {736case 'th':737switch(target[0].className) {738case 'datepicker-switch':739this.showMode(1);740break;741case 'prev':742case 'next':743var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);744switch(this.viewMode){745case 0:746this.viewDate = this.moveMonth(this.viewDate, dir);747this._trigger('changeMonth', this.viewDate);748break;749case 1:750case 2:751this.viewDate = this.moveYear(this.viewDate, dir);752if (this.viewMode === 1)753this._trigger('changeYear', this.viewDate);754break;755}756this.fill();757break;758case 'today':759var date = new Date();760date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);761762this.showMode(-2);763var which = this.o.todayBtn == 'linked' ? null : 'view';764this._setDate(date, which);765break;766case 'clear':767var element;768if (this.isInput)769element = this.element;770else if (this.component)771element = this.element.find('input');772if (element)773element.val("").change();774this._trigger('changeDate');775this.update();776if (this.o.autoclose)777this.hide();778break;779}780break;781case 'span':782if (!target.is('.disabled')) {783this.viewDate.setUTCDate(1);784if (target.is('.month')) {785var day = 1;786var month = target.parent().find('span').index(target);787var year = this.viewDate.getUTCFullYear();788this.viewDate.setUTCMonth(month);789this._trigger('changeMonth', this.viewDate);790if (this.o.minViewMode === 1) {791this._setDate(UTCDate(year, month, day,0,0,0,0));792}793} else {794var year = parseInt(target.text(), 10)||0;795var day = 1;796var month = 0;797this.viewDate.setUTCFullYear(year);798this._trigger('changeYear', this.viewDate);799if (this.o.minViewMode === 2) {800this._setDate(UTCDate(year, month, day,0,0,0,0));801}802}803this.showMode(-1);804this.fill();805}806break;807case 'td':808if (target.is('.day') && !target.is('.disabled')){809var day = parseInt(target.text(), 10)||1;810var year = this.viewDate.getUTCFullYear(),811month = this.viewDate.getUTCMonth();812if (target.is('.old')) {813if (month === 0) {814month = 11;815year -= 1;816} else {817month -= 1;818}819} else if (target.is('.new')) {820if (month == 11) {821month = 0;822year += 1;823} else {824month += 1;825}826}827this._setDate(UTCDate(year, month, day,0,0,0,0));828}829break;830}831}832},833834_setDate: function(date, which){835if (!which || which == 'date')836this.date = new Date(date);837if (!which || which == 'view')838this.viewDate = new Date(date);839this.fill();840this.setValue();841this._trigger('changeDate');842var element;843if (this.isInput) {844element = this.element;845} else if (this.component){846element = this.element.find('input');847}848if (element) {849element.change();850}851if (this.o.autoclose && (!which || which == 'date')) {852this.hide();853}854},855856moveMonth: function(date, dir){857if (!dir) return date;858var new_date = new Date(date.valueOf()),859day = new_date.getUTCDate(),860month = new_date.getUTCMonth(),861mag = Math.abs(dir),862new_month, test;863dir = dir > 0 ? 1 : -1;864if (mag == 1){865test = dir == -1866// If going back one month, make sure month is not current month867// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)868? function(){ return new_date.getUTCMonth() == month; }869// If going forward one month, make sure month is as expected870// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)871: function(){ return new_date.getUTCMonth() != new_month; };872new_month = month + dir;873new_date.setUTCMonth(new_month);874// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11875if (new_month < 0 || new_month > 11)876new_month = (new_month + 12) % 12;877} else {878// For magnitudes >1, move one month at a time...879for (var i=0; i<mag; i++)880// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...881new_date = this.moveMonth(new_date, dir);882// ...then reset the day, keeping it in the new month883new_month = new_date.getUTCMonth();884new_date.setUTCDate(day);885test = function(){ return new_month != new_date.getUTCMonth(); };886}887// Common date-resetting loop -- if date is beyond end of month, make it888// end of month889while (test()){890new_date.setUTCDate(--day);891new_date.setUTCMonth(new_month);892}893return new_date;894},895896moveYear: function(date, dir){897return this.moveMonth(date, dir*12);898},899900dateWithinRange: function(date){901return date >= this.o.startDate && date <= this.o.endDate;902},903904keydown: function(e){905if (this.picker.is(':not(:visible)')){906if (e.keyCode == 27) // allow escape to hide and re-show picker907this.show();908return;909}910var dateChanged = false,911dir, day, month,912newDate, newViewDate;913switch(e.keyCode){914case 27: // escape915this.hide();916e.preventDefault();917break;918case 37: // left919case 39: // right920if (!this.o.keyboardNavigation) break;921dir = e.keyCode == 37 ? -1 : 1;922if (e.ctrlKey){923newDate = this.moveYear(this.date, dir);924newViewDate = this.moveYear(this.viewDate, dir);925this._trigger('changeYear', this.viewDate);926} else if (e.shiftKey){927newDate = this.moveMonth(this.date, dir);928newViewDate = this.moveMonth(this.viewDate, dir);929this._trigger('changeMonth', this.viewDate);930} else {931newDate = new Date(this.date);932newDate.setUTCDate(this.date.getUTCDate() + dir);933newViewDate = new Date(this.viewDate);934newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);935}936if (this.dateWithinRange(newDate)){937this.date = newDate;938this.viewDate = newViewDate;939this.setValue();940this.update();941e.preventDefault();942dateChanged = true;943}944break;945case 38: // up946case 40: // down947if (!this.o.keyboardNavigation) break;948dir = e.keyCode == 38 ? -1 : 1;949if (e.ctrlKey){950newDate = this.moveYear(this.date, dir);951newViewDate = this.moveYear(this.viewDate, dir);952this._trigger('changeYear', this.viewDate);953} else if (e.shiftKey){954newDate = this.moveMonth(this.date, dir);955newViewDate = this.moveMonth(this.viewDate, dir);956this._trigger('changeMonth', this.viewDate);957} else {958newDate = new Date(this.date);959newDate.setUTCDate(this.date.getUTCDate() + dir * 7);960newViewDate = new Date(this.viewDate);961newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);962}963if (this.dateWithinRange(newDate)){964this.date = newDate;965this.viewDate = newViewDate;966this.setValue();967this.update();968e.preventDefault();969dateChanged = true;970}971break;972case 13: // enter973this.hide();974e.preventDefault();975break;976case 9: // tab977this.hide();978break;979}980if (dateChanged){981this._trigger('changeDate');982var element;983if (this.isInput) {984element = this.element;985} else if (this.component){986element = this.element.find('input');987}988if (element) {989element.change();990}991}992},993994showMode: function(dir) {995if (dir) {996this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));997}998/*999vitalets: fixing bug of very special conditions:1000jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.1001Method show() does not set display css correctly and datepicker is not shown.1002Changed to .css('display', 'block') solve the problem.1003See https://github.com/vitalets/x-editable/issues/3710041005In jquery 1.7.2+ everything works fine.1006*/1007//this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();1008this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');1009this.updateNavArrows();1010}1011};10121013var DateRangePicker = function(element, options){1014this.element = $(element);1015this.inputs = $.map(options.inputs, function(i){ return i.jquery ? i[0] : i; });1016delete options.inputs;10171018$(this.inputs)1019.datepicker(options)1020.bind('changeDate', $.proxy(this.dateUpdated, this));10211022this.pickers = $.map(this.inputs, function(i){ return $(i).data('datepicker'); });1023this.updateDates();1024};1025DateRangePicker.prototype = {1026updateDates: function(){1027this.dates = $.map(this.pickers, function(i){ return i.date; });1028this.updateRanges();1029},1030updateRanges: function(){1031var range = $.map(this.dates, function(d){ return d.valueOf(); });1032$.each(this.pickers, function(i, p){1033p.setRange(range);1034});1035},1036dateUpdated: function(e){1037var dp = $(e.target).data('datepicker'),1038new_date = dp.getUTCDate(),1039i = $.inArray(e.target, this.inputs),1040l = this.inputs.length;1041if (i == -1) return;10421043if (new_date < this.dates[i]){1044// Date being moved earlier/left1045while (i>=0 && new_date < this.dates[i]){1046this.pickers[i--].setUTCDate(new_date);1047}1048}1049else if (new_date > this.dates[i]){1050// Date being moved later/right1051while (i<l && new_date > this.dates[i]){1052this.pickers[i++].setUTCDate(new_date);1053}1054}1055this.updateDates();1056},1057remove: function(){1058$.map(this.pickers, function(p){ p.remove(); });1059delete this.element.data().datepicker;1060}1061};10621063function opts_from_el(el, prefix){1064// Derive options from element data-attrs1065var data = $(el).data(),1066out = {}, inkey,1067replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'),1068prefix = new RegExp('^' + prefix.toLowerCase());1069for (var key in data)1070if (prefix.test(key)){1071inkey = key.replace(replace, function(_,a){ return a.toLowerCase(); });1072out[inkey] = data[key];1073}1074return out;1075}10761077function opts_from_locale(lang){1078// Derive options from locale plugins1079var out = {};1080// Check if "de-DE" style date is available, if not language should1081// fallback to 2 letter code eg "de"1082if (!dates[lang]) {1083lang = lang.split('-')[0]1084if (!dates[lang])1085return;1086}1087var d = dates[lang];1088$.each(locale_opts, function(i,k){1089if (k in d)1090out[k] = d[k];1091});1092return out;1093}10941095var old = $.fn.datepicker;1096$.fn.datepicker = function ( option ) {1097var args = Array.apply(null, arguments);1098args.shift();1099var internal_return,1100this_return;1101this.each(function () {1102var $this = $(this),1103data = $this.data('datepicker'),1104options = typeof option == 'object' && option;1105if (!data) {1106var elopts = opts_from_el(this, 'date'),1107// Preliminary otions1108xopts = $.extend({}, defaults, elopts, options),1109locopts = opts_from_locale(xopts.language),1110// Options priority: js args, data-attrs, locales, defaults1111opts = $.extend({}, defaults, locopts, elopts, options);1112if ($this.is('.input-daterange') || opts.inputs){1113var ropts = {1114inputs: opts.inputs || $this.find('input').toArray()1115};1116$this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts))));1117}1118else{1119$this.data('datepicker', (data = new Datepicker(this, opts)));1120}1121}1122if (typeof option == 'string' && typeof data[option] == 'function') {1123internal_return = data[option].apply(data, args);1124if (internal_return !== undefined)1125return false;1126}1127});1128if (internal_return !== undefined)1129return internal_return;1130else1131return this;1132};11331134var defaults = $.fn.datepicker.defaults = {1135autoclose: false,1136beforeShowDay: $.noop,1137calendarWeeks: false,1138clearBtn: false,1139daysOfWeekDisabled: [],1140endDate: Infinity,1141forceParse: true,1142format: 'mm/dd/yyyy',1143keyboardNavigation: true,1144language: 'en',1145minViewMode: 0,1146orientation: "auto",1147rtl: false,1148startDate: -Infinity,1149startView: 0,1150todayBtn: false,1151todayHighlight: false,1152weekStart: 01153};1154var locale_opts = $.fn.datepicker.locale_opts = [1155'format',1156'rtl',1157'weekStart'1158];1159$.fn.datepicker.Constructor = Datepicker;1160var dates = $.fn.datepicker.dates = {1161en: {1162days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],1163daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],1164daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],1165months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],1166monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],1167today: "Today",1168clear: "Clear"1169}1170};11711172var DPGlobal = {1173modes: [1174{1175clsName: 'days',1176navFnc: 'Month',1177navStep: 11178},1179{1180clsName: 'months',1181navFnc: 'FullYear',1182navStep: 11183},1184{1185clsName: 'years',1186navFnc: 'FullYear',1187navStep: 101188}],1189isLeapYear: function (year) {1190return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));1191},1192getDaysInMonth: function (year, month) {1193return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];1194},1195validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,1196nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,1197parseFormat: function(format){1198// IE treats \0 as a string end in inputs (truncating the value),1199// so it's a bad format delimiter, anyway1200var separators = format.replace(this.validParts, '\0').split('\0'),1201parts = format.match(this.validParts);1202if (!separators || !separators.length || !parts || parts.length === 0){1203throw new Error("Invalid date format.");1204}1205return {separators: separators, parts: parts};1206},1207parseDate: function(date, format, language) {1208if (date instanceof Date) return date;1209if (typeof format === 'string')1210format = DPGlobal.parseFormat(format);1211if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {1212var part_re = /([\-+]\d+)([dmwy])/,1213parts = date.match(/([\-+]\d+)([dmwy])/g),1214part, dir;1215date = new Date();1216for (var i=0; i<parts.length; i++) {1217part = part_re.exec(parts[i]);1218dir = parseInt(part[1]);1219switch(part[2]){1220case 'd':1221date.setUTCDate(date.getUTCDate() + dir);1222break;1223case 'm':1224date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);1225break;1226case 'w':1227date.setUTCDate(date.getUTCDate() + dir * 7);1228break;1229case 'y':1230date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);1231break;1232}1233}1234return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);1235}1236var parts = date && date.match(this.nonpunctuation) || [],1237date = new Date(),1238parsed = {},1239setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],1240setters_map = {1241yyyy: function(d,v){ return d.setUTCFullYear(v); },1242yy: function(d,v){ return d.setUTCFullYear(2000+v); },1243m: function(d,v){1244if (isNaN(d))1245return d;1246v -= 1;1247while (v<0) v += 12;1248v %= 12;1249d.setUTCMonth(v);1250while (d.getUTCMonth() != v)1251d.setUTCDate(d.getUTCDate()-1);1252return d;1253},1254d: function(d,v){ return d.setUTCDate(v); }1255},1256val, filtered, part;1257setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];1258setters_map['dd'] = setters_map['d'];1259date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);1260var fparts = format.parts.slice();1261// Remove noop parts1262if (parts.length != fparts.length) {1263fparts = $(fparts).filter(function(i,p){1264return $.inArray(p, setters_order) !== -1;1265}).toArray();1266}1267// Process remainder1268if (parts.length == fparts.length) {1269for (var i=0, cnt = fparts.length; i < cnt; i++) {1270val = parseInt(parts[i], 10);1271part = fparts[i];1272if (isNaN(val)) {1273switch(part) {1274case 'MM':1275filtered = $(dates[language].months).filter(function(){1276var m = this.slice(0, parts[i].length),1277p = parts[i].slice(0, m.length);1278return m == p;1279});1280val = $.inArray(filtered[0], dates[language].months) + 1;1281break;1282case 'M':1283filtered = $(dates[language].monthsShort).filter(function(){1284var m = this.slice(0, parts[i].length),1285p = parts[i].slice(0, m.length);1286return m == p;1287});1288val = $.inArray(filtered[0], dates[language].monthsShort) + 1;1289break;1290}1291}1292parsed[part] = val;1293}1294for (var i=0, _date, s; i<setters_order.length; i++){1295s = setters_order[i];1296if (s in parsed && !isNaN(parsed[s])){1297_date = new Date(date);1298setters_map[s](_date, parsed[s]);1299if (!isNaN(_date))1300date = _date;1301}1302}1303}1304return date;1305},1306formatDate: function(date, format, language){1307if (typeof format === 'string')1308format = DPGlobal.parseFormat(format);1309var val = {1310d: date.getUTCDate(),1311D: dates[language].daysShort[date.getUTCDay()],1312DD: dates[language].days[date.getUTCDay()],1313m: date.getUTCMonth() + 1,1314M: dates[language].monthsShort[date.getUTCMonth()],1315MM: dates[language].months[date.getUTCMonth()],1316yy: date.getUTCFullYear().toString().substring(2),1317yyyy: date.getUTCFullYear()1318};1319val.dd = (val.d < 10 ? '0' : '') + val.d;1320val.mm = (val.m < 10 ? '0' : '') + val.m;1321var date = [],1322seps = $.extend([], format.separators);1323for (var i=0, cnt = format.parts.length; i <= cnt; i++) {1324if (seps.length)1325date.push(seps.shift());1326date.push(val[format.parts[i]]);1327}1328return date.join('');1329},1330headTemplate: '<thead>'+1331'<tr>'+1332'<th class="prev">«</th>'+1333'<th colspan="5" class="datepicker-switch"></th>'+1334'<th class="next">»</th>'+1335'</tr>'+1336'</thead>',1337contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',1338footTemplate: '<tfoot><tr><th colspan="7" class="today"></th></tr><tr><th colspan="7" class="clear"></th></tr></tfoot>'1339};1340DPGlobal.template = '<div class="datepicker">'+1341'<div class="datepicker-days">'+1342'<table class=" table-condensed">'+1343DPGlobal.headTemplate+1344'<tbody></tbody>'+1345DPGlobal.footTemplate+1346'</table>'+1347'</div>'+1348'<div class="datepicker-months">'+1349'<table class="table-condensed">'+1350DPGlobal.headTemplate+1351DPGlobal.contTemplate+1352DPGlobal.footTemplate+1353'</table>'+1354'</div>'+1355'<div class="datepicker-years">'+1356'<table class="table-condensed">'+1357DPGlobal.headTemplate+1358DPGlobal.contTemplate+1359DPGlobal.footTemplate+1360'</table>'+1361'</div>'+1362'</div>';13631364$.fn.datepicker.DPGlobal = DPGlobal;136513661367/* DATEPICKER NO CONFLICT1368* =================== */13691370$.fn.datepicker.noConflict = function(){1371$.fn.datepicker = old;1372return this;1373};137413751376/* DATEPICKER DATA-API1377* ================== */13781379$(document).on(1380'focus.datepicker.data-api click.datepicker.data-api',1381'[data-provide="datepicker"]',1382function(e){1383var $this = $(this);1384if ($this.data('datepicker')) return;1385e.preventDefault();1386// component click requires us to explicitly show it1387$this.datepicker('show');1388}1389);1390$(function(){1391$('[data-provide="datepicker-inline"]').datepicker();1392});13931394}( window.jQuery ));139513961397