github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/root/js/bootstrap-datepicker.js (about) 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 blur: $.proxy(this.hide, this), 40 keyup: $.proxy(this.update, this) 41 }); 42 } else { 43 if (this.component){ 44 this.component.on('click', $.proxy(this.show, this)); 45 } else { 46 this.element.on('click', $.proxy(this.show, this)); 47 } 48 } 49 this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; 50 if (typeof this.minViewMode === 'string') { 51 switch (this.minViewMode) { 52 case 'months': 53 this.minViewMode = 1; 54 break; 55 case 'years': 56 this.minViewMode = 2; 57 break; 58 default: 59 this.minViewMode = 0; 60 break; 61 } 62 } 63 this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; 64 if (typeof this.viewMode === 'string') { 65 switch (this.viewMode) { 66 case 'months': 67 this.viewMode = 1; 68 break; 69 case 'years': 70 this.viewMode = 2; 71 break; 72 default: 73 this.viewMode = 0; 74 break; 75 } 76 } 77 this.startViewMode = this.viewMode; 78 this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; 79 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; 80 this.fillDow(); 81 this.fillMonths(); 82 this.update(); 83 this.showMode(); 84 }; 85 86 Datepicker.prototype = { 87 constructor: Datepicker, 88 89 show: function(e) { 90 this.picker.show(); 91 this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); 92 this.place(); 93 $(window).on('resize', $.proxy(this.place, this)); 94 if (e ) { 95 e.stopPropagation(); 96 e.preventDefault(); 97 } 98 if (!this.isInput) { 99 $(document).on('mousedown', $.proxy(this.hide, this)); 100 } 101 this.element.trigger({ 102 type: 'show', 103 date: this.date 104 }); 105 }, 106 107 hide: function(){ 108 this.picker.hide(); 109 $(window).off('resize', this.place); 110 this.viewMode = this.startViewMode; 111 this.showMode(); 112 if (!this.isInput) { 113 $(document).off('mousedown', this.hide); 114 } 115 this.set(); 116 this.element.trigger({ 117 type: 'hide', 118 date: this.date 119 }); 120 }, 121 122 set: function() { 123 var formated = DPGlobal.formatDate(this.date, this.format); 124 if (!this.isInput) { 125 if (this.component){ 126 this.element.find('input').prop('value', formated); 127 } 128 this.element.data('date', formated); 129 } else { 130 this.element.prop('value', formated); 131 } 132 }, 133 134 setValue: function(newDate) { 135 if (typeof newDate === 'string') { 136 this.date = DPGlobal.parseDate(newDate, this.format); 137 } else { 138 this.date = new Date(newDate); 139 } 140 this.set(); 141 this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); 142 this.fill(); 143 }, 144 145 place: function(){ 146 var offset = this.component ? this.component.offset() : this.element.offset(); 147 this.picker.css({ 148 top: offset.top + this.height, 149 left: offset.left 150 }); 151 }, 152 153 update: function(newDate){ 154 this.date = DPGlobal.parseDate( 155 typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), 156 this.format 157 ); 158 this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); 159 this.fill(); 160 }, 161 162 fillDow: function(){ 163 var dowCnt = this.weekStart; 164 var html = '<tr>'; 165 while (dowCnt < this.weekStart + 7) { 166 html += '<th class="dow">'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'</th>'; 167 } 168 html += '</tr>'; 169 this.picker.find('.datepicker-days thead').append(html); 170 }, 171 172 fillMonths: function(){ 173 var html = ''; 174 var i = 0 175 while (i < 12) { 176 html += '<span class="month">'+DPGlobal.dates.monthsShort[i++]+'</span>'; 177 } 178 this.picker.find('.datepicker-months td').append(html); 179 }, 180 181 fill: function() { 182 var d = new Date(this.viewDate), 183 year = d.getFullYear(), 184 month = d.getMonth(), 185 currentDate = this.date.valueOf(); 186 this.picker.find('.datepicker-days th:eq(1)') 187 .text(DPGlobal.dates.months[month]+' '+year); 188 var prevMonth = new Date(year, month-1, 28,0,0,0,0), 189 day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); 190 prevMonth.setDate(day); 191 prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); 192 var nextMonth = new Date(prevMonth); 193 nextMonth.setDate(nextMonth.getDate() + 42); 194 nextMonth = nextMonth.valueOf(); 195 html = []; 196 var clsName; 197 while(prevMonth.valueOf() < nextMonth) { 198 if (prevMonth.getDay() === this.weekStart) { 199 html.push('<tr>'); 200 } 201 clsName = ''; 202 if (prevMonth.getMonth() < month) { 203 clsName += ' old'; 204 } else if (prevMonth.getMonth() > month) { 205 clsName += ' new'; 206 } 207 if (prevMonth.valueOf() === currentDate) { 208 clsName += ' active'; 209 } 210 html.push('<td class="day'+clsName+'">'+prevMonth.getDate() + '</td>'); 211 if (prevMonth.getDay() === this.weekEnd) { 212 html.push('</tr>'); 213 } 214 prevMonth.setDate(prevMonth.getDate()+1); 215 } 216 this.picker.find('.datepicker-days tbody').empty().append(html.join('')); 217 var currentYear = this.date.getFullYear(); 218 219 var months = this.picker.find('.datepicker-months') 220 .find('th:eq(1)') 221 .text(year) 222 .end() 223 .find('span').removeClass('active'); 224 if (currentYear === year) { 225 months.eq(this.date.getMonth()).addClass('active'); 226 } 227 228 html = ''; 229 year = parseInt(year/10, 10) * 10; 230 var yearCont = this.picker.find('.datepicker-years') 231 .find('th:eq(1)') 232 .text(year + '-' + (year + 9)) 233 .end() 234 .find('td'); 235 year -= 1; 236 for (var i = -1; i < 11; i++) { 237 html += '<span class="year'+(i === -1 || i === 10 ? ' old' : '')+(currentYear === year ? ' active' : '')+'">'+year+'</span>'; 238 year += 1; 239 } 240 yearCont.html(html); 241 }, 242 243 click: function(e) { 244 e.stopPropagation(); 245 e.preventDefault(); 246 var target = $(e.target).closest('span, td, th'); 247 if (target.length === 1) { 248 switch(target[0].nodeName.toLowerCase()) { 249 case 'th': 250 switch(target[0].className) { 251 case 'switch': 252 this.showMode(1); 253 break; 254 case 'prev': 255 case 'next': 256 this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( 257 this.viewDate, 258 this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + 259 DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) 260 ); 261 this.fill(); 262 this.set(); 263 break; 264 } 265 break; 266 case 'span': 267 if (target.is('.month')) { 268 var month = target.parent().find('span').index(target); 269 this.viewDate.setMonth(month); 270 } else { 271 var year = parseInt(target.text(), 10)||0; 272 this.viewDate.setFullYear(year); 273 } 274 if (this.viewMode !== 0) { 275 this.date = new Date(this.viewDate); 276 this.element.trigger({ 277 type: 'changeDate', 278 date: this.date, 279 viewMode: DPGlobal.modes[this.viewMode].clsName 280 }); 281 } 282 this.showMode(-1); 283 this.fill(); 284 this.set(); 285 break; 286 case 'td': 287 if (target.is('.day')){ 288 var day = parseInt(target.text(), 10)||1; 289 var month = this.viewDate.getMonth(); 290 if (target.is('.old')) { 291 month -= 1; 292 } else if (target.is('.new')) { 293 month += 1; 294 } 295 var year = this.viewDate.getFullYear(); 296 this.date = new Date(year, month, day,0,0,0,0); 297 this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); 298 this.fill(); 299 this.set(); 300 this.element.trigger({ 301 type: 'changeDate', 302 date: this.date, 303 viewMode: DPGlobal.modes[this.viewMode].clsName 304 }); 305 } 306 break; 307 } 308 } 309 }, 310 311 mousedown: function(e){ 312 e.stopPropagation(); 313 e.preventDefault(); 314 }, 315 316 showMode: function(dir) { 317 if (dir) { 318 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); 319 } 320 this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); 321 } 322 }; 323 324 $.fn.datepicker = function ( option, val ) { 325 return this.each(function () { 326 var $this = $(this), 327 data = $this.data('datepicker'), 328 options = typeof option === 'object' && option; 329 if (!data) { 330 $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); 331 } 332 if (typeof option === 'string') data[option](val); 333 }); 334 }; 335 336 $.fn.datepicker.defaults = { 337 }; 338 $.fn.datepicker.Constructor = Datepicker; 339 340 var DPGlobal = { 341 modes: [ 342 { 343 clsName: 'days', 344 navFnc: 'Month', 345 navStep: 1 346 }, 347 { 348 clsName: 'months', 349 navFnc: 'FullYear', 350 navStep: 1 351 }, 352 { 353 clsName: 'years', 354 navFnc: 'FullYear', 355 navStep: 10 356 }], 357 dates:{ 358 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], 359 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], 360 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], 361 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], 362 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] 363 }, 364 isLeapYear: function (year) { 365 return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) 366 }, 367 getDaysInMonth: function (year, month) { 368 return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] 369 }, 370 parseFormat: function(format){ 371 var separator = format.match(/[.\/\-\s].*?/), 372 parts = format.split(/\W+/); 373 if (!separator || !parts || parts.length === 0){ 374 throw new Error("Invalid date format."); 375 } 376 return {separator: separator, parts: parts}; 377 }, 378 parseDate: function(date, format) { 379 var parts = date.split(format.separator), 380 date = new Date(), 381 val; 382 date.setHours(0); 383 date.setMinutes(0); 384 date.setSeconds(0); 385 date.setMilliseconds(0); 386 if (parts.length === format.parts.length) { 387 for (var i=0, cnt = format.parts.length; i < cnt; i++) { 388 val = parseInt(parts[i], 10)||1; 389 switch(format.parts[i]) { 390 case 'dd': 391 case 'd': 392 date.setDate(val); 393 break; 394 case 'mm': 395 case 'm': 396 date.setMonth(val - 1); 397 break; 398 case 'yy': 399 date.setFullYear(2000 + val); 400 break; 401 case 'yyyy': 402 date.setFullYear(val); 403 break; 404 } 405 } 406 } 407 return date; 408 }, 409 formatDate: function(date, format){ 410 var val = { 411 d: date.getDate(), 412 m: date.getMonth() + 1, 413 yy: date.getFullYear().toString().substring(2), 414 yyyy: date.getFullYear() 415 }; 416 val.dd = (val.d < 10 ? '0' : '') + val.d; 417 val.mm = (val.m < 10 ? '0' : '') + val.m; 418 var date = []; 419 for (var i=0, cnt = format.parts.length; i < cnt; i++) { 420 date.push(val[format.parts[i]]); 421 } 422 return date.join(format.separator); 423 }, 424 headTemplate: '<thead>'+ 425 '<tr>'+ 426 '<th class="prev">‹</th>'+ 427 '<th colspan="5" class="switch"></th>'+ 428 '<th class="next">›</th>'+ 429 '</tr>'+ 430 '</thead>', 431 contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>' 432 }; 433 DPGlobal.template = '<div class="datepicker dropdown-menu">'+ 434 '<div class="datepicker-days">'+ 435 '<table class=" table-condensed">'+ 436 DPGlobal.headTemplate+ 437 '<tbody></tbody>'+ 438 '</table>'+ 439 '</div>'+ 440 '<div class="datepicker-months">'+ 441 '<table class="table-condensed">'+ 442 DPGlobal.headTemplate+ 443 DPGlobal.contTemplate+ 444 '</table>'+ 445 '</div>'+ 446 '<div class="datepicker-years">'+ 447 '<table class="table-condensed">'+ 448 DPGlobal.headTemplate+ 449 DPGlobal.contTemplate+ 450 '</table>'+ 451 '</div>'+ 452 '</div>'; 453 454 }( window.jQuery )