glDatePicker-2.0 日历插件
昨天用的日历插件在绑定数据的时候出现了问题,所以今天换了这个glDatePicker-2.0 日历插件
这是我修改后的样式
默认样式是这样的。
我的代码
index.html
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>glDatePicker</title> 6 <link href="styles/glDatePicker.default.css" rel="stylesheet" type="text/css"> 7 </head> 8 9 <body> 10 <input type="text" id="mydate" style=" visibility: visible;height: 20px;width:300px;" /> 11 <script src="jquery-1.10.2.min.js"></script> 12 <script src="glDatePicker.js"></script> 13 <script> 14 $('input').glDatePicker({ 15 showAlways: true, 16 selectedDate: new Date(), 17 specialDates: [ 18 { 19 date: new Date(2016,05,25), 20 data: { message: 'Happy New Year!' }, 21 repeatYear: true 22 }, 23 { 24 date: new Date(2016,06,01), 25 data: { message: 'Happy New Year!' }, 26 repeatYear: true 27 } 28 ] 29 }); 30 </script> 31 </body> 32 </html>
glDatePicker.default.css
1 .gldp-default{position:absolute;font-family:'helvetica'}.gldp-default .core{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;position:relative;float:left;padding:0;margin:0;font-size:14px;text-align:center;cursor:pointer;color:#777;background:#e1e1e1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#dadada',GradientType=0)}.gldp-default .dow{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;position:relative;float:left;padding:0;margin:0;font-size:14px;text-align:center;cursor:pointer;color:#777;background:#e1e1e1;border:0;border-radius:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#dadada',GradientType=0)}.gldp-default .monyear{box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;position:relative;float:left;padding:0;margin:0;font-size:14px;text-align:center;cursor:pointer;color:#777;background:#e1e1e1;border:0;border-radius:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff',endColorstr='#dadada',GradientType=0)}.gldp-default .border{border:1px solid #e1e1e1}.gldp-default .monyear,.gldp-default .monyear select{font-size:16px!important;font-weight:bold;text-shadow:1px 1px 0 rgba(255,255,255,0.75)}.gldp-default .monyear span{margin:0 5px 0 5px}.gldp-default .prev-arrow,.gldp-default .next-arrow{color:#222;text-shadow:1px 1px 0 rgba(255,255,255,0.75)}.gldp-default .prev-arrow:active,.gldp-default .next-arrow:active{color:#f00}.gldp-default .prev-arrow-off,.gldp-default .next-arrow-off{color:#222;opacity:.15}.gldp-default .dow{color:#363636;font-weight:bold;cursor:wait!important;background:#fff;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000',endColorstr='#880000',GradientType=0)}.gldp-default .mon,.gldp-default .tue,.gldp-default .wed,.gldp-default .thu,.gldp-default .fri{font-weight:bold;text-shadow:1px 1px 0 rgba(255,255,255,0.75)}.gldp-default .sat,.gldp-default .sun{color:#3858a8;font-weight:bold;text-shadow:1px 1px 0 rgba(255,255,255,0.75)}.gldp-default .outday{color:#d9d9d9!important;background:#f2f2f2}.gldp-default .mon:hover,.gldp-default .tue:hover,.gldp-default .wed:hover,.gldp-default .thu:hover,.gldp-default .fri:hover,.gldp-default .sat:hover,.gldp-default .sun:hover{background:#fcfff4;background:-moz-linear-gradient(top,#fcfff4 0,#e9e9ce 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#fcfff4),color-stop(100%,#e9e9ce));background:-webkit-linear-gradient(top,#fcfff4 0,#e9e9ce 100%);background:-o-linear-gradient(top,#fcfff4 0,#e9e9ce 100%);background:-ms-linear-gradient(top,#fcfff4 0,#e9e9ce 100%);background:linear-gradient(to bottom,#fcfff4 0,#e9e9ce 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fcfff4',endColorstr='#e9e9ce',GradientType=0)}.gldp-default .noday{color:#444;font-weight:normal;cursor:wait!important;background:#aaa;background:-moz-linear-gradient(top,#aaa 0,#8a8a8a 98%,#aaa 99%,#8a8a8a 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#aaa),color-stop(98%,#8a8a8a),color-stop(99%,#aaa),color-stop(100%,#8a8a8a));background:-webkit-linear-gradient(top,#aaa 0,#8a8a8a 98%,#aaa 99%,#8a8a8a 100%);background:-o-linear-gradient(top,#aaa 0,#8a8a8a 98%,#aaa 99%,#8a8a8a 100%);background:-ms-linear-gradient(top,#aaa 0,#8a8a8a 98%,#aaa 99%,#8a8a8a 100%);background:linear-gradient(to bottom,#aaa 0,#8a8a8a 98%,#aaa 99%,#8a8a8a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#aaaaaa',endColorstr='#8a8a8a',GradientType=0)}.gldp-default .selected{color:#fff;font-weight:bold;border-color:#3d9fe1;background:#3d9fe1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e8bf88',endColorstr='#ef753f',GradientType=0)}.gldp-default .today{color:#fff;font-weight:bold;border-color:#3d9fe1;background:#3d9fe1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#88bfe8',endColorstr='#3775ef',GradientType=0)}.gldp-default .special{color:#3d9fe1;font-weight:bold;border-color:#dbdbdb;background:#fff;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#88e888',endColorstr='#37ef37',GradientType=0)}
glDatePicker.js
1 /*! 2 * glDatePicker v2.0 3 * http://glad.github.com/glDatePicker/ 4 * 5 * Copyright (c) 2013 Gautam Lad. All rights reserved. 6 * Released under the MIT license. 7 * 8 * Date: Tue Jan 1 2013 9 */ 10 ;(function() { 11 $.fn.glDatePicker = function(options) { 12 var pluginName = 'glDatePicker'; 13 14 // Find the plugin attached to the element 15 var instance = this.data(pluginName); 16 17 // If the instance wasn't found, create it... 18 if(!instance) { 19 // Return the element being bound to 20 return this.each(function() { 21 return $(this).data(pluginName, new glDatePicker(this, options)); 22 }); 23 } 24 25 // ...otherwise if the user passes true to the plugin (on the second call), 26 // then return the instance of the plugin itself 27 return (options === true) ? instance : this; 28 }; 29 30 // Default options 31 $.fn.glDatePicker.defaults = 32 { 33 // Style to use for the calendar. This name must match the name used in 34 // the stylesheet, using the class naming convention "gldp-cssName". 35 cssName: 'default', 36 37 // The z-index for the calendar control. 38 zIndex: 1000, 39 40 // Thickness of border (in pixels) 41 borderSize: 1, 42 43 // The number of pixels to offset the calendar's position on the page. 44 calendarOffset: { x: 0, y: 1 }, 45 46 // Set to true if you want the calendar to be visible at all times. 47 // NOTE: If your target element is hidden, the calendar will be hidden as well. 48 showAlways: false, 49 50 // Hide the calendar when a date is selected (only if showAlways is set to false). 51 hideOnClick: true, 52 53 // Allow selection of months by clicking on the month in the title. 54 allowMonthSelect: true, 55 56 // Allow selection of years by clicking on the year in the title. 57 allowYearSelect: true, 58 59 // The date that will be treated as 'today'. 60 todayDate: new Date(), 61 62 // The date that will appear selected when the calendar renders. 63 // By default it will be set to todayDate. 64 selectedDate: null, 65 66 // Arrows used for the Previous and Next month buttons on the title. 67 // Set these to blank to hide the arrows completely. 68 prevArrow: '\u25c4', 69 nextArrow: '\u25ba', 70 71 // A collection of dates that can be selectable by the user. 72 // The dates can be a one-time selection or made repeatable by setting 73 // the repeatYear or repeatMonth flag to true. 74 // By default repeatYear and repeatMonth are false. 75 // 76 // This example creates 4-individual dates that can be selected; 77 // The first date will repeat every year, the second date will repeat every 78 // month and year, the third date will repeat every month and the fourth date 79 // will only be selectable one-time and not repeat: 80 // 81 // selectableDates: [ 82 // { date: new Date(0, 8, 5), repeatYear: true }, 83 // { date: new Date(0, 0, 14), repeatMonth: true, repeatYear: true }, 84 // { date: new Date(2013, 0, 24), repeatMonth: true }, 85 // { date: new Date(2013, 11, 25) }, 86 // ] 87 selectableDates: null, 88 89 // A collection of date ranges that are selectable by the user. 90 // The ranges can be made to repeat by setting repeatYear to true 91 // (repeatMonth is not supported). 92 // 93 // This example will create 3-sets of selectable date ranges with 94 // specific from and to ranges. The 4th and 5th ranges don't specify 95 // the "to" date in which case the "to" date will be the maximum days for 96 // the month specified in "from". The 4th and 5th ranges also repeat every year: 97 // 98 // selectableDateRange: [ 99 // { from: new Date(2013, 1, 1), to: newDate (2013, 2, 1) }, 100 // { from: new Date(2013, 4, 1), to: newDate (2013, 8, 1) }, 101 // { from: new Date(2013, 7, 10), to: newDate (2013, 9, 10) }, 102 // { from: new Date(0, 8, 10), repeatYear: true } 103 // { from: new Date(0, 9, 1), repeatYear: true } 104 // ] 105 selectableDateRange: null, 106 107 // Mark certain dates as special dates. Similar to selectableDates, this 108 // property supports both repeatYear and repeatMonth flags. 109 // Each special date can be styled using custom style names and can have 110 // data attached to it that will be returned in the onClick callback. 111 // The data field can be any custom (JSON style) object. 112 // 113 // This example creates two (repeatable by year) dates with special data in them. 114 // The first date also assigns a special class (which you will have to define). 115 // specialDates: [ 116 // { 117 // date: new Date(0, 8, 5), 118 // data: { message: 'Happy Birthday!' }, 119 // repeatYear: true, 120 // cssClass: 'special-bday' 121 // }, 122 // { 123 // date: new Date(2013, 0, 8), 124 // data: { message: 'Meeting every day 8 of the month' }, 125 // repeatMonth: true 126 // } 127 // ] 128 specialDates: null, 129 130 // List of months that can be selectable, including when the user clicks 131 // on the title to select from the dropdown. 132 // This example only makes two months visible; September and December: 133 // selectableMonths: [8, 11] 134 selectableMonths : null, 135 136 // List of selectable years. If not provided, will default to 5-years 137 // back and forward. 138 // This example only allows selection of dates that have year 2012, 2013, 2015 139 // selectableYears: [2012, 2013, 2015] 140 selectableYears: null, 141 142 // List of selectable days of the week. 0 is Sunday, 1 is Monday, and so on. 143 // This example allows only Sunday, Tuesday, Thursday: 144 // selectableDOW: [0, 2, 4] 145 selectableDOW : null, 146 147 // Names of the month that will be shown in the title. 148 // Will default to long-form names: 149 // January, February, March, April, May, June, July, 150 // August, September, October, November, December 151 monthNames: null, 152 153 // Names of the days of the Week that will be shown below the title. 154 // Will default to short-form names: 155 // Sun, Mon, Tue, Wed, Thu, Fri, Sat 156 dowNames: null, 157 158 // The day of the week to start the calendar on. 0 is Sunday, 1 is Monday and so on. 159 dowOffset: 0, 160 161 // Callback that will trigger when the user clicks a selectable date. 162 // Parameters that are passed to the callback: 163 // el : The input element the date picker is bound to 164 // cell : The cell on the calendar that triggered this event 165 // date : The date associated with the cell 166 // data : Special data associated with the cell (if available, otherwise, null) 167 onClick: (function(el, cell, date, data) { 168 el.val(date.toLocaleDateString()); 169 }), 170 171 // Callback that will trigger when the user hovers over a selectable date. 172 // This callback receives the same set of parameters as onClick. 173 onHover: function(el, cell, date, data) {}, 174 175 // Callback that will trigger when the calendar needs to show. 176 // You can use this callback to animate the opening of the calendar. 177 onShow: function(calendar) { calendar.show(); }, 178 179 // Callback that will trigger when the calendar needs to hide. 180 // You can use this callback to animate the hiding of the calendar. 181 onHide: function(calendar) { calendar.hide(); }, 182 183 // First date of the month. 184 firstDate: null 185 }; 186 187 // Our plugin object 188 var glDatePicker = (function() { 189 // Main entry point. Initialize the plugin 190 function glDatePicker(element, userOptions) { 191 // Grab handle to this 192 var self = this; 193 194 // Save bound element to el 195 self.el = $(element); 196 var el = self.el; 197 198 // Merge user options into default options 199 self.options = $.extend(true, {}, $.fn.glDatePicker.defaults, userOptions); 200 var options = self.options; 201 202 // Find the calendar element if the user provided one 203 self.calendar = $($.find('[gldp-el=' + el.attr('gldp-id') + ' ]')); 204 205 // Default first date to selected 206 options.selectedDate = options.selectedDate || options.todayDate; 207 options.firstDate = (new Date((options.firstDate || options.selectedDate)))._first(); 208 209 if(!(el.attr('gldp-id') || '').length) { 210 el.attr('gldp-id', 'gldp-' + Math.round(Math.random() * 1e10)) 211 } 212 213 // Show the plugin on focus 214 el 215 .addClass('gldp-el') 216 .bind('click', function(e) { self.show(e); }) 217 .bind('focus', function(e) { self.show(e); }); 218 219 // If the user is defining the container and it exists, hide it on initial creation. 220 // The update function will handle showing if it's showAlways = true 221 if(self.calendar.length && !options.showAlways) { 222 self.calendar.hide(); 223 } 224 225 // Hide the plugin on mouse up outside of the plugin 226 $(document).bind('mouseup', function(e) { 227 var target = e.target; 228 var calendar = self.calendar; 229 230 if(!el.is(target) && !calendar.is(target) && calendar.has(target).length === 0 && calendar.is(':visible')) { 231 self.hide(); 232 } 233 }); 234 235 // Render calendar 236 self.render(); 237 }; 238 239 // Public methods 240 glDatePicker.prototype = 241 { 242 show: function() { 243 // Hide others and show this calendar 244 $.each($('.gldp-el').not(this.el), function(i, o) { 245 if(o.length) { o.options.onHide(o.calendar) ; } 246 }); 247 248 // Show this calendar 249 this.options.onShow(this.calendar); 250 }, 251 252 hide: function() { 253 if(this.options && !this.options.showAlways) { 254 this.options.onHide(this.calendar); 255 } 256 }, 257 258 // Render the calendar 259 render: function(renderCalback) { 260 var self = this; 261 var el = self.el; 262 var options = self.options; 263 var calendar = self.calendar; 264 265 // Build a core class (with border) that every element would have 266 var coreClass = ' core border '; 267 var cssName = 'gldp-' + options.cssName; 268 269 // Get today 270 var todayVal = options.todayDate._val(); 271 var todayTime = todayVal.time; 272 273 // Constants 274 var maxRow = 6; 275 var maxCol = 7; 276 var borderSize = options.borderSize + 'px'; 277 278 // Helper function to build selectable list 279 var getSelectableList = function(min, max, userList) { 280 // Build a default list using min/max 281 var resultList = []; 282 for(var i = min; i <= max; i++) { resultList.push(i); } 283 284 // If user provided a collection, sanitize list by ensuring it's within range and unique 285 if(userList) { 286 var newList = []; 287 $.each(userList, function(i, v) { 288 if(v >= min && v <= max && newList._indexOf(v) < 0) { 289 newList.push(v); 290 } 291 }); 292 293 resultList = newList.length ? newList : resultList; 294 }; 295 296 // Sort the values before returning it 297 resultList.sort(); 298 299 return resultList; 300 }; 301 302 // Selectable (constants) 303 var selectableMonths = getSelectableList(0, 11, options.selectableMonths); 304 var selectableYears = getSelectableList(todayVal.year - 5, todayVal.year + 5, options.selectableYears); 305 var selectableDOW = getSelectableList(0, 6, options.selectableDOW); 306 var dowNames = options.dowNames || [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]; 307 var monthNames = options.monthNames || [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; 308 309 // Create cell width based on el size 310 var containerWidth = el.outerWidth(); 311 var containerHeight = containerWidth; 312 313 // Create cell size based on container size 314 var getCellSize = function(_size, _count) { 315 return (_size / _count) + ((options.borderSize / _count) * (_count - 1)); 316 }; 317 var cellWidth = getCellSize(containerWidth, maxCol); 318 var cellHeight = getCellSize(containerHeight, maxRow + 2); 319 320 // If calendar doesn't exist, create it and re-assign it to self 321 if(!calendar.length) { 322 self.calendar = calendar = $('<div/>') 323 .attr('gldp-el', el.attr('gldp-id')) 324 .data('is', true) 325 .css( 326 { 327 display: (options.showAlways ? undefined : 'none'), 328 zIndex: options.zIndex, 329 width: (cellWidth * maxCol) + 'px' 330 }); 331 332 $('body').append(calendar); 333 } 334 else { 335 if(!eval(calendar.data('is'))) { 336 containerWidth = calendar.outerWidth(); 337 containerHeight = calendar.outerHeight(); 338 339 cellWidth = getCellSize(containerWidth, maxCol); 340 cellHeight = getCellSize(containerHeight, maxRow + 2); 341 } 342 } 343 344 // Hide calendar if the target element isn't visible 345 if(!el.is(':visible')) { calendar.hide(); } 346 347 // Add core classes and remove calendar's children 348 calendar 349 .removeClass() 350 .addClass(cssName) 351 .children().remove(); 352 353 // Bind to resize event to position calendar 354 var onResize = function() { 355 var elPos = el.offset(); 356 calendar.css( 357 { 358 top: (elPos.top + el.outerHeight() + options.calendarOffset.y) + 'px', 359 left: (elPos.left + options.calendarOffset.x) + 'px' 360 }); 361 }; 362 $(window).resize(onResize); 363 onResize(); 364 365 // Create variables for cells 366 var cellCSS = 367 { 368 width: cellWidth + 'px', 369 height: cellHeight + 'px', 370 lineHeight: cellHeight + 'px' 371 }; 372 373 // Helper function to setDate 374 var setFirstDate = function(_date) { 375 if(_date) { 376 // Get first date 377 options.firstDate = _date; 378 379 // Update the calendar 380 self.render(); 381 } 382 }; 383 384 var getFirstDate = function(_offset) { 385 // Create start date as the first date of the month 386 var _date = new Date(options.firstDate); 387 388 // Default to no offset 389 _offset = _offset || 0; 390 391 // Find out which months are selectable 392 while(true) { 393 // Adjust date for month offset 394 _date.setMonth(_date.getMonth() + _offset); 395 _date.setDate(Math.min(1, _date._max())); 396 397 // If not an offset, break out of the loop 398 if(_offset == 0) { break; } 399 400 // Get _date's value 401 var dateVal = _date._val(); 402 403 // Get local vars 404 var dateMonth = dateVal.month; 405 var dateYear = dateVal.year; 406 407 // Find the month first 408 if(selectableMonths._indexOf(dateMonth) != -1) { 409 // If year is in our collection, break... 410 if(selectableYears._indexOf(dateYear) != -1) { 411 break; 412 } 413 else { 414 // ...otherwise, if it's out of bounds, exit loop 415 if(dateYear < selectableYears[0] || dateYear > selectableYears[selectableYears.length - 1]) { 416 return null; 417 } 418 } 419 } 420 } 421 422 return _date; 423 }; 424 425 // Get the previous, next first dates 426 var prevFirstDate = getFirstDate(-1); 427 var nextFirstDate = getFirstDate(1); 428 429 // Get the first date for the current month being rendered 430 var firstDate = (options.firstDate = getFirstDate()); 431 var firstDateVal = firstDate._val(); 432 var firstDateMonth = firstDateVal.month; 433 var firstDateYear = firstDateVal.year; 434 435 // Get the start date in the calendar 436 var startDate = new Date(firstDate); 437 438 // Sanitize days of the week offset 439 var dowOffset = Math.abs(Math.min(6, Math.max(0, options.dowOffset))); 440 441 // Offset weekdays 442 var startOffset = startDate.getDay() - dowOffset; 443 startOffset = startOffset < 1 ? -7 - startOffset : -startOffset; 444 dowNames = (dowNames.concat(dowNames)) 445 .slice(dowOffset, dowOffset + 7); 446 447 // Offset the start date 448 startDate._add(startOffset); 449 450 // Gather flags for prev/next arrows 451 var showPrev = (prevFirstDate); 452 var showNext = (nextFirstDate); 453 454 // Create the arrows and title 455 var monyearClass = coreClass + 'monyear '; 456 457 var prevCell = $('<div/>') 458 .addClass(monyearClass) 459 .css( 460 $.extend({}, cellCSS, 461 { 462 borderWidth: borderSize + ' 0 0 ' + borderSize 463 }) 464 ) 465 .append( 466 $('<a/>') 467 .addClass('prev-arrow' + (showPrev ? '' : '-off')) 468 .html(options.prevArrow) 469 ) 470 .mousedown(function() { return false; }) 471 .click(function(e) { 472 if(options.prevArrow != '' && showPrev) { 473 e.stopPropagation(); 474 setFirstDate(prevFirstDate); 475 } 476 }); 477 478 var titleCellCount = maxCol - 2; 479 var titleWidth = (cellWidth * titleCellCount) - (titleCellCount * options.borderSize) + (options.borderSize); 480 var titleCell = $('<div/>') 481 .addClass(monyearClass + 'title') 482 .css( 483 $.extend({}, cellCSS, 484 { 485 width: titleWidth + 'px', 486 borderTopWidth: borderSize, 487 marginLeft: '-' + (borderSize) 488 }) 489 ); 490 491 var nextCell = $('<div/>') 492 .addClass(monyearClass) 493 .css( 494 $.extend({}, cellCSS, 495 { 496 marginLeft: '-' + (borderSize), 497 borderWidth: borderSize + ' ' + borderSize + ' 0 0' 498 }) 499 ) 500 .append( 501 $('<a/>') 502 .addClass('next-arrow' + (showNext ? '' : '-off')) 503 .html(options.nextArrow) 504 ) 505 .mousedown(function() { return false; }) 506 .click(function(e) { 507 if(options.nextArrow != '' && showNext) { 508 e.stopPropagation(); 509 setFirstDate(nextFirstDate); 510 } 511 }); 512 513 // Add cells for prev/title/next 514 calendar 515 .append(prevCell) 516 .append(titleCell) 517 .append(nextCell); 518 519 // Add all the cells to the calendar 520 for(var row = 0, cellIndex = 0; row < maxRow + 1; row++) { 521 for(var col = 0; col < maxCol; col++, cellIndex++) { 522 var cellDate = new Date(startDate); 523 var cellClass = 'day'; 524 var cellZIndex = options.zIndex + (cellIndex); 525 var cell = $('<div/>') 526 527 if(!row) { 528 cellClass = 'dow'; 529 cell.html(dowNames[col]); 530 cellDate = null; 531 } 532 else { 533 // Get the new date for this cell 534 cellDate._add(col + ((row - 1) * maxCol)); 535 536 // Get value for this date 537 var cellDateVal = cellDate._val(); 538 var cellDateTime = cellDateVal.time; 539 540 // Variable to hold special data 541 var specialData = null; 542 543 // Determine if this date is selectable 544 var isSelectable = true; 545 546 // Helper function to get repeat friendly date against current date 547 var getRepeatDate = function(v, date) { 548 // If repeating, set the date's year and month accordingly 549 if(v.repeatYear === true) { date.setYear(cellDateVal.year); } 550 if(v.repeatMonth === true) { date.setMonth(cellDateVal.month); } 551 552 return date._val(); 553 }; 554 555 // Assign date for the cell 556 cell.html(cellDateVal.date); 557 558 // If we have selectable date ranges 559 if(options.selectableDateRange) { 560 isSelectable = false; 561 $.each(options.selectableDateRange, function(i, v) { 562 var dateFrom = v.from; 563 var dateTo = (v.to || null); 564 565 // If to is not specified, default to max days in the from month 566 dateTo = dateTo || new Date(v.from.getFullYear(), v.from.getMonth(), v.from._max()); 567 568 // If repeating year, set the from and two to the current date's year 569 dateFrom = getRepeatDate(v, dateFrom); 570 dateTo = getRepeatDate(v, dateTo); 571 572 // Test to see if this date is selectable 573 if(cellDateTime >= dateFrom.time && cellDateTime <= dateTo.time) { 574 isSelectable = true; 575 return true; 576 } 577 }); 578 } 579 580 // Handle date ranges and collections 581 if(options.selectableDates) { 582 if((options.selectableDateRange && !isSelectable) || (isSelectable && !options.selectableDateRange)) { 583 isSelectable = false; 584 } 585 $.each(options.selectableDates, function(i, v) { 586 var vDate = getRepeatDate(v, v.date); 587 588 if(vDate.time == cellDateTime) { 589 return (isSelectable = true); 590 } 591 }); 592 } 593 594 // If not active or if not within selectableMonths, set to noday otherwise evaluate accordingly 595 if(!isSelectable || 596 selectableYears._indexOf(cellDateVal.year) < 0 || 597 selectableMonths._indexOf(cellDateVal.month) < 0 || 598 selectableDOW._indexOf(cellDateVal.day) < 0) { 599 cellClass = 'noday'; 600 } 601 else { 602 // Handle active dates and weekends 603 cellClass = ([ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ])[cellDateVal.day]; 604 605 // Handle today or selected dates 606 if(firstDateMonth != cellDateVal.month) { cellClass += ' outday'; } 607 if(todayTime == cellDateTime) { cellClass = 'today'; cellZIndex += 50; } 608 if(options.selectedDate._time() == cellDateTime) { cellClass = 'selected'; cellZIndex += 51; } 609 610 // Handle special dates 611 if(options.specialDates) { 612 $.each(options.specialDates, function(i, v) { 613 var vDate = getRepeatDate(v, v.date); 614 615 if(vDate.time == cellDateTime) { 616 cellClass = (v.cssClass || 'special'); 617 cellZIndex += 52; 618 specialData = v.data; 619 } 620 }); 621 } 622 623 cell 624 .mousedown(function() { return false; }) 625 .hover(function(e) { 626 e.stopPropagation(); 627 628 // Get the data from this cell 629 var hoverData = $(this).data('data'); 630 631 // Call callback 632 options.onHover(el, cell, hoverData.date, hoverData.data); 633 }) 634 .click(function(e) { 635 e.stopPropagation(); 636 637 // Get the data from this cell 638 var clickedData = $(this).data('data'); 639 640 // Save date to selected and first 641 options.selectedDate = options.firstDate = clickedData.date; 642 643 // Update calendar (and auto-hide if necessary) 644 self.render(function() { 645 if(!options.showAlways && options.hideOnClick) { 646 self.hide(); 647 } 648 }); 649 650 // Call callback 651 options.onClick(el, $(this), clickedData.date, clickedData.data); 652 }); 653 } 654 } 655 656 // Update the css for the cell 657 $.extend(cellCSS, 658 { 659 borderTopWidth: borderSize, 660 borderBottomWidth: borderSize, 661 borderLeftWidth: (row > 0 || (!row && !col)) ? borderSize : 0, 662 borderRightWidth: (row > 0 || (!row && col == 6)) ? borderSize : 0, 663 marginLeft: (col > 0) ? '-' + (borderSize) : 0, 664 marginTop: (row > 0) ? '-' + (borderSize) : 0, 665 zIndex: cellZIndex 666 }); 667 668 // Assign other properties to the cell 669 cell 670 .data('data', { date: cellDate, data: specialData}) 671 .addClass(coreClass + cellClass) 672 .css(cellCSS); 673 674 // Add cell to calendar 675 calendar.append(cell); 676 } 677 } 678 679 // Render the month / year title 680 681 // Helper function for toggling select and text 682 var toggleYearMonthSelect = function(showYear) { 683 var show = 'inline-block'; 684 var hide = 'none'; 685 686 if(options.allowMonthSelect) { 687 monthText.css({ display: !showYear ? hide : show }); 688 monthSelect.css({ display: !showYear ? show : hide }); 689 } 690 691 if(options.allowYearSelect) { 692 yearText.css({ display: showYear ? hide : show }); 693 yearSelect.css({ display: showYear ? show : hide }); 694 } 695 }; 696 697 // Helper function when select is updated 698 var onYearMonthSelect = function() { 699 options.firstDate = new Date(yearSelect.val(), monthSelect.val(), 1); 700 self.render(); 701 }; 702 703 // Build month selector 704 var monthSelect = $('<select/>') 705 .hide() 706 .change(onYearMonthSelect); 707 708 // Build year selector 709 var yearSelect = $('<select/>') 710 .hide() 711 .change(onYearMonthSelect); 712 713 // Build month label 714 var monthText = $('<span/>') 715 .html(monthNames[firstDateMonth]) 716 .mousedown(function() { return false; }) 717 .click(function(e) { 718 e.stopPropagation(); 719 toggleYearMonthSelect(false); 720 }); 721 722 // Build year label 723 var yearText = $('<span/>') 724 .html(firstDateYear) 725 .mousedown(function() { return false; }) 726 .click(function(e) { 727 e.stopPropagation(); 728 toggleYearMonthSelect(true); 729 }); 730 731 // Populate month select 732 $.each(monthNames, function(i, v) { 733 if(options.allowMonthSelect && selectableMonths._indexOf(i) != -1) { 734 var o = $('<option/>').html(v).attr('value', i); 735 if(i == firstDateMonth) { o.attr('selected', 'selected');} 736 monthSelect.append(o); 737 } 738 }); 739 740 // Populate year select 741 $.each(selectableYears, function(i, v) { 742 if(options.allowYearSelect) { 743 var o = $('<option/>').html(v).attr('value', v); 744 if(v == firstDateYear) { o.attr('selected', 'selected'); } 745 yearSelect.append(o); 746 } 747 }); 748 749 var titleYearMonth = $('<div/>') 750 .append(monthText) 751 .append(monthSelect) 752 .append(yearText) 753 .append(yearSelect); 754 755 // Add to title 756 titleCell.children().remove(); 757 titleCell.append(titleYearMonth); 758 759 // Run the callback signaling end of the render 760 renderCalback = renderCalback || (function() {}); 761 renderCalback(); 762 } 763 }; 764 765 // Return the plugin 766 return glDatePicker; 767 })(); 768 769 // One time initialization of useful prototypes 770 (function() { 771 Date.prototype._clear = function() { 772 this.setHours(0); 773 this.setMinutes(0); 774 this.setSeconds(0); 775 this.setMilliseconds(0); 776 777 return this; 778 }; 779 780 Date.prototype._time = function() { 781 return this._clear().getTime(); 782 }; 783 784 Date.prototype._max = function() { 785 var isLeapYear = (new Date(this.getYear(), 1, 29).getMonth() == 1) ? 1 : 0; 786 var days = [31, 28 + isLeapYear, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 787 788 return days[this.getMonth()]; 789 }; 790 791 Date.prototype._add = function(days) { 792 this.setDate(this.getDate() + days); 793 }; 794 795 Date.prototype._first = function() { 796 var date = new Date(this); 797 date.setDate(1); 798 799 return date; 800 }; 801 802 Date.prototype._val = function() { 803 this._clear(); 804 805 return { 806 year: this.getFullYear(), 807 month: this.getMonth(), 808 date: this.getDate(), 809 time: this.getTime(), 810 day: this.getDay() 811 }; 812 }; 813 814 Array.prototype._indexOf = function(value) { 815 return $.inArray(value, this); 816 } 817 })(); 818 })();
在线演示地址
http://runjs.cn/detail/bx3qgacr