1/* ========================================================= 2 * bootstrap-datepicker.js 3 * http://www.eyecon.ro/bootstrap-datepicker 4 * ========================================================= 5 * Copyright 2012 Stefan Petre 6 * 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 at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * 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 and 17 * limitations under the License. 18 * ========================================================= */ 19 20!function( $ ) { 21 22 // Picker object 23 24 var Datepicker = function(element, options){ 25 this.element = $(element); 26 this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); 27 this.picker = $(DPGlobal.template) 28 .appendTo('body') 29 .on({ 30 click: $.proxy(this.click, this)//, 31 //mousedown: $.proxy(this.mousedown, this) 32 }); 33 this.isInput = this.element.is('input'); 34 this.component = this.element.is('.date') ? this.element.find('.add-on') : false; 35 36 if (this.isInput) { 37 this.element.on({ 38 focus: $.proxy(this.show, this), 39 click: $.proxy(this.show, this), 40 //blur: $.proxy(this.hide, this), 41 keyup: $.proxy(this.update, this) 42 }); 43 } else { 44 if (this.component){ 45 this.component.on('click', $.proxy(this.show, this)); 46 } else { 47 this.element.on('click', $.proxy(this.show, this)); 48 } 49 } 50 51 this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; 52 if (typeof this.minViewMode === 'string') { 53 switch (this.minViewMode) { 54 case 'months': 55 this.minViewMode = 1; 56 break; 57 case 'years': 58 this.minViewMode = 2; 59 break; 60 default: 61 this.minViewMode = 0; 62 break; 63 } 64 } 65 this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; 66 if (typeof this.viewMode === 'string') { 67 switch (this.viewMode) { 68 case 'months': 69 this.viewMode = 1; 70 break; 71 case 'years': 72 this.viewMode = 2; 73 break; 74 default: 75 this.viewMode = 0; 76 break; 77 } 78 } 79 this.startViewMode = this.viewMode; 80 this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; 81 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; 82 this.onRender = options.onRender; 83 this.fillDow(); 84 this.fillMonths(); 85 this.update(); 86 this.showMode(); 87 }; 88 89 Datepicker.prototype = { 90 constructor: Datepicker, 91 92 show: function(e) { 93 this.picker.show(); 94 this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); 95 this.place(); 96 $(window).on('resize', $.proxy(this.place, this)); 97 if (e ) { 98 e.stopPropagation(); 99 e.preventDefault(); 100 } 101 if (!this.isInput) { 102 } 103 var that = this; 104 $(document).on('mousedown', function(ev){ 105 if ($(ev.target).closest('.datepicker').length == 0) { 106 that.hide(); 107 } 108 }); 109 this.element.trigger({ 110 type: 'show', 111 date: this.date 112 }); 113 }, 114 115 hide: function(){ 116 this.picker.hide(); 117 $(window).off('resize', this.place); 118 this.viewMode = this.startViewMode; 119 this.showMode(); 120 if (!this.isInput) { 121 $(document).off('mousedown', this.hide); 122 } 123 //this.set(); 124 this.element.trigger({ 125 type: 'hide', 126 date: this.date 127 }); 128 }, 129 130 set: function() { 131 var formated = DPGlobal.formatDate(this.date, this.format); 132 if (!this.isInput) { 133 if (this.component){ 134 this.element.find('input').prop('value', formated); 135 } 136 this.element.data('date', formated); 137 } else { 138 this.element.prop('value', formated); 139 } 140 }, 141 142 setValue: function(newDate) { 143 if (typeof newDate === 'string') { 144 this.date = DPGlobal.parseDate(newDate, this.format); 145 } else { 146 this.date = new Date(newDate); 147 } 148 this.set(); 149 this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); 150 this.fill(); 151 }, 152 153 place: function(){ 154 var offset = this.component ? this.component.offset() : this.element.offset(); 155 this.picker.css({ 156 top: offset.top + this.height,// - 30, //Author - Vadim 157 left: offset.left 158 }); 159 }, 160 161 update: function(newDate){ 162 this.date = DPGlobal.parseDate( 163 typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), 164 this.format 165 ); 166 this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); 167 this.fill(); 168 }, 169 170 fillDow: function(){ 171 var dowCnt = this.weekStart; 172 var html = '<tr>'; 173 while (dowCnt < this.weekStart + 7) { 174 html += '<th class="dow">'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'</th>'; 175 } 176 html += '</tr>'; 177 this.picker.find('.datepicker-days thead').append(html); 178 }, 179 180 fillMonths: function(){ 181 var html = ''; 182 var i = 0 183 while (i < 12) { 184 html += '<span class="month">'+DPGlobal.dates.monthsShort[i++]+'</span>'; 185 } 186 this.picker.find('.datepicker-months td').append(html); 187 }, 188 189 fill: function() { 190 var d = new Date(this.viewDate), 191 year = d.getFullYear(),
192 month = d.getMonth(), 193 currentDate = this.date.valueOf(); 194 this.picker.find('.datepicker-days th:eq(1)') 195 .text(DPGlobal.dates.months[month]+' '+year); 196 var prevMonth = new Date(year, month-1, 28,0,0,0,0), 197 day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); 198 prevMonth.setDate(day); 199 prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); 200 var nextMonth = new Date(prevMonth); 201 nextMonth.setDate(nextMonth.getDate() + 42); 202 nextMonth = nextMonth.valueOf(); 203 var html = []; 204 var clsName, 205 prevY, 206 prevM; 207 while(prevMonth.valueOf() < nextMonth) { 208 if (prevMonth.getDay() === this.weekStart) { 209 html.push('<tr>'); 210 } 211 clsName = this.onRender(prevMonth); 212 prevY = prevMonth.getFullYear(); 213 prevM = prevMonth.getMonth(); 214 if ((prevM < month && prevY === year) || prevY < year) { 215 clsName += ' old'; 216 } else if ((prevM > month && prevY === year) || prevY > year) { 217 clsName += ' new'; 218 } 219 if (prevMonth.valueOf() === currentDate) { 220 clsName += ' active'; 221 } 222 html.push('<td class="day '+clsName+'">'+prevMonth.getDate() + '</td>'); 223 if (prevMonth.getDay() === this.weekEnd) { 224 html.push('</tr>'); 225 } 226 prevMonth.setDate(prevMonth.getDate()+1); 227 } 228 this.picker.find('.datepicker-days tbody').empty().append(html.join('')); 229 230 if (this.picker.find('.datepicker-days tbody tr:first td:last').is('.old')) 231 this.picker.find('.datepicker-days tbody tr:first').hide(); 232 233 if (this.picker.find('.datepicker-days tbody tr:last td:first').is('.new')) 234 this.picker.find('.datepicker-days tbody tr:last').hide(); 235 236 var currentYear = this.date.getFullYear(); 237 238 var months = this.picker.find('.datepicker-months') 239 .find('th:eq(1)') 240 .text(year) 241 .end() 242 .find('span').removeClass('active'); 243 if (currentYear === year) { 244 months.eq(this.date.getMonth()).addClass('active'); 245 } 246 247 html = ''; 248 year = parseInt(year/10, 10) * 10; 249 var yearCont = this.picker.find('.datepicker-years') 250 .find('th:eq(1)') 251 .text(year + '-' + (year + 9)) 252 .end() 253 .find('td'); 254 year -= 1; 255 for (var i = -1; i < 11; i++) { 256 html += '<span class="year'+(i === -1 || i === 10 ? ' old' : '')+(currentYear === year ? ' active' : '')+'">'+year+'</span>'; 257 year += 1; 258 } 259 yearCont.html(html); 260 }, 261 262 click: function(e) { 263 e.stopPropagation(); 264 e.preventDefault(); 265 var target = $(e.target).closest('span, td, th'); 266 if (target.length === 1) { 267 switch(target[0].nodeName.toLowerCase()) { 268 case 'th': 269 switch(target[0].className) { 270 case 'switch': 271 this.showMode(1); 272 break; 273 case 'prev': 274 case 'next': 275 this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( 276 this.viewDate, 277 this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + 278 DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) 279 ); 280 this.fill(); 281 this.set(); 282 break; 283 } 284 break; 285 case 'span': 286 if (target.is('.month')) { 287 var month = target.parent().find('span').index(target); 288 this.viewDate.setMonth(month); 289 } else { 290 var year = parseInt(target.text(), 10)||0; 291 this.viewDate.setFullYear(year); 292 } 293 if (this.viewMode !== 0) { 294 this.date = new Date(this.viewDate); 295 this.element.trigger({ 296 type: 'changeDate', 297 date: this.date, 298 viewMode: DPGlobal.modes[this.viewMode].clsName 299 }); 300 } 301 this.showMode(-1); 302 this.fill(); 303 this.set(); 304 break; 305 case 'td': 306 if (target.is('.day') && !target.is('.disabled')){ 307 var day = parseInt(target.text(), 10)||1; 308 var month = this.viewDate.getMonth(); 309 if (target.is('.old')) { 310 month -= 1; 311 } else if (target.is('.new')) { 312 month += 1; 313 } 314 var year = this.viewDate.getFullYear(); 315 this.date = new Date(year, month, day,0,0,0,0); 316 this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); 317 this.fill(); 318 this.set(); 319 this.element.trigger({ 320 type: 'changeDate', 321 date: this.date, 322 viewMode: DPGlobal.modes[this.viewMode].clsName 323 });
324 } 325 break; 326 } 327 } 328 }, 329 330 mousedown: function(e){ 331 e.stopPropagation(); 332 e.preventDefault(); 333 }, 334 335 showMode: function(dir) { 336 if (dir) { 337 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); 338 } 339 this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); 340 } 341 }; 342 343 $.fn.datepicker = function ( option, val ) { 344 return this.each(function () { 345 var $this = $(this), 346 data = $this.data('datepicker'), 347 options = typeof option === 'object' && option; 348 if (!data) { 349 $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); 350 } 351 if (typeof option === 'string') data[option](val); 352 }); 353 }; 354 355 $.fn.datepicker.defaults = { 356 onRender: function(date) { 357 return ''; 358 } 359 }; 360 $.fn.datepicker.Constructor = Datepicker; 361 362 var DPGlobal = { 363 modes: [ 364 { 365 clsName: 'days', 366 navFnc: 'Month', 367 navStep: 1 368 }, 369 { 370 clsName: 'months', 371 navFnc: 'FullYear', 372 navStep: 1 373 }, 374 { 375 clsName: 'years', 376 navFnc: 'FullYear', 377 navStep: 10 378 }], 379 dates:{ 380 days: ['ÐоÑкÑеÑенÑе','ÐонеделÑник','ÐÑоÑник','СÑеда','ЧеÑвеÑг','ÐÑÑниÑа','СÑббоÑа'], 381 daysShort: ['вÑк','пнд','вÑÑ','ÑÑд','ÑÑв','пÑн','ÑбÑ'], 382 daysMin: ['ÐС', 'ÐÐ', 'ÐТ', 'СР', 'ЧТ', 'ÐТ', 'СÐ'], 383 months: ['ЯнваÑÑ', 'ФевÑалÑ', 'ÐаÑÑ', 'ÐпÑелÑ', 'Ðай', 'ÐÑнÑ', 'ÐÑлÑ', 'ÐвгÑÑÑ', 'СенÑÑбÑÑ', 'ÐкÑÑбÑÑ', 'ÐоÑбÑÑ', 'ÐекабÑÑ'], 384 monthsShort: ['Янв','Фев','ÐаÑ','ÐпÑ','Ðай','ÐÑн','ÐÑл','Ðвг','Сен','ÐкÑ','ÐоÑ','Ðек'] 385 }, 386 isLeapYear: function (year) { 387 return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) 388 }, 389 getDaysInMonth: function (year, month) { 390 return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] 391 }, 392 parseFormat: function(format){ 393 var separator = format.match(/[.\/\-\s].*?/), 394 parts = format.split(/\W+/); 395 if (!separator || !parts || parts.length === 0){ 396 throw new Error("Invalid date format."); 397 } 398 return {separator: separator, parts: parts}; 399 }, 400 parseDate: function(date, format) { 401 var parts = date.split(format.separator), 402 date = new Date(), 403 val; 404 date.setHours(0); 405 date.setMinutes(0); 406 date.setSeconds(0); 407 date.setMilliseconds(0); 408 if (parts.length === format.parts.length) { 409 var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); 410 for (var i=0, cnt = format.parts.length; i < cnt; i++) { 411 val = parseInt(parts[i], 10)||1; 412 switch(format.parts[i]) { 413 case 'dd': 414 case 'd': 415 day = val; 416 date.setDate(val); 417 break; 418 case 'mm': 419 case 'm': 420 month = val - 1; 421 date.setMonth(val - 1); 422 break; 423 case 'yy': 424 year = 2000 + val; 425 date.setFullYear(2000 + val); 426 break; 427 case 'yyyy': 428 year = val; 429 date.setFullYear(val); 430 break; 431 } 432 } 433 date = new Date(year, month, day, 0 ,0 ,0); 434 } 435 return date; 436 }, 437 formatDate: function(date, format){ 438 var val = { 439 d: date.getDate(), 440 m: date.getMonth() + 1, 441 yy: date.getFullYear().toString().substring(2), 442 yyyy: date.getFullYear() 443 }; 444 val.dd = (val.d < 10 ? '0' : '') + val.d; 445 val.mm = (val.m < 10 ? '0' : '') + val.m; 446 var date = []; 447 for (var i=0, cnt = format.parts.length; i < cnt; i++) { 448 date.push(val[format.parts[i]]); 449 } 450 return date.join(format.separator); 451 }, 452 headTemplate: '<thead>'+ 453 '<tr>'+ 454 '<th class="prev">‹</th>' + 455 '<th colspan="5" class="switch"></th>'+ 456 '<th class="next">›</th>' + 457 '</tr>'+ 458 '</thead>', 459 contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>' 460 }; 461 DPGlobal.template = '<div class="datepicker dropdown-menu">'+ 462 '<div class="datepicker-days">'+ 463 '<table class=" table-condensed">'+ 464 DPGlobal.headTemplate+ 465 '<tbody></tbody>'+ 466 '</table>'+ 467 '</div>'+ 468 '<div class="datepicker-months">'+ 469 '<table class="table-condensed">'+ 470 DPGlobal.headTemplate+ 471 DPGlobal.contTemplate+ 472 '</table>'+ 473 '</div>'+ 474 '<div class="datepicker-years">'+ 475 '<table class="table-condensed">'+ 476 DPGlobal.headTemplate+ 477 DPGlobal.contTemplate+ 478 '</table>'+ 479 '</div>'+ 480 '</div>'; 481 482}( window.jQuery );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.