[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('calendar-base', function (Y, NAME) { 9 10 /** 11 * The CalendarBase submodule is a basic UI calendar view that displays 12 * a range of dates in a two-dimensional month grid, with one or more 13 * months visible at a single time. CalendarBase supports custom date 14 * rendering, multiple calendar panes, and selection. 15 * @module calendar 16 * @submodule calendar-base 17 */ 18 19 var getCN = Y.ClassNameManager.getClassName, 20 CALENDAR = 'calendar', 21 CAL_GRID = getCN(CALENDAR, 'grid'), 22 CAL_LEFT_GRID = getCN(CALENDAR, 'left-grid'), 23 CAL_RIGHT_GRID = getCN(CALENDAR, 'right-grid'), 24 CAL_BODY = getCN(CALENDAR, 'body'), 25 CAL_HD = getCN(CALENDAR, 'header'), 26 CAL_HD_LABEL = getCN(CALENDAR, 'header-label'), 27 CAL_WDAYROW = getCN(CALENDAR, 'weekdayrow'), 28 CAL_WDAY = getCN(CALENDAR, 'weekday'), 29 CAL_COL_HIDDEN = getCN(CALENDAR, 'column-hidden'), 30 CAL_DAY_SELECTED = getCN(CALENDAR, 'day-selected'), 31 SELECTION_DISABLED = getCN(CALENDAR, 'selection-disabled'), 32 CAL_ROW = getCN(CALENDAR, 'row'), 33 CAL_DAY = getCN(CALENDAR, 'day'), 34 CAL_PREVMONTH_DAY = getCN(CALENDAR, 'prevmonth-day'), 35 CAL_NEXTMONTH_DAY = getCN(CALENDAR, 'nextmonth-day'), 36 CAL_ANCHOR = getCN(CALENDAR, 'anchor'), 37 CAL_PANE = getCN(CALENDAR, 'pane'), 38 CAL_STATUS = getCN(CALENDAR, 'status'), 39 L = Y.Lang, 40 substitute = L.sub, 41 arrayEach = Y.Array.each, 42 objEach = Y.Object.each, 43 iOf = Y.Array.indexOf, 44 hasKey = Y.Object.hasKey, 45 setVal = Y.Object.setValue, 46 isEmpty = Y.Object.isEmpty, 47 ydate = Y.DataType.Date; 48 49 /** Create a calendar view to represent a single or multiple 50 * month range of dates, rendered as a grid with date and 51 * weekday labels. 52 * 53 * @class CalendarBase 54 * @extends Widget 55 * @param config {Object} Configuration object (see Configuration 56 * attributes) 57 * @constructor 58 */ 59 function CalendarBase() { 60 CalendarBase.superclass.constructor.apply ( this, arguments ); 61 } 62 63 64 65 Y.CalendarBase = Y.extend( CalendarBase, Y.Widget, { 66 67 /** 68 * A storage for various properties of individual month 69 * panes. 70 * 71 * @property _paneProperties 72 * @type Object 73 * @private 74 */ 75 _paneProperties : {}, 76 77 /** 78 * The number of month panes in the calendar, deduced 79 * from the CONTENT_TEMPLATE's number of {calendar_grid} 80 * tokens. 81 * 82 * @property _paneNumber 83 * @type Number 84 * @private 85 */ 86 _paneNumber : 1, 87 88 /** 89 * The unique id used to prefix various elements of this 90 * calendar instance. 91 * 92 * @property _calendarId 93 * @type String 94 * @private 95 */ 96 _calendarId : null, 97 98 /** 99 * The hash map of selected dates, populated with 100 * selectDates() and deselectDates() methods 101 * 102 * @property _selectedDates 103 * @type Object 104 * @private 105 */ 106 _selectedDates : {}, 107 108 /** 109 * A private copy of the rules object, populated 110 * by setting the customRenderer attribute. 111 * 112 * @property _rules 113 * @type Object 114 * @private 115 */ 116 _rules : {}, 117 118 /** 119 * A private copy of the filterFunction, populated 120 * by setting the customRenderer attribute. 121 * 122 * @property _filterFunction 123 * @type Function 124 * @private 125 */ 126 _filterFunction : null, 127 128 /** 129 * Storage for calendar cells modified by any custom 130 * formatting. The storage is cleared, used to restore 131 * cells to the original state, and repopulated accordingly 132 * when the calendar is rerendered. 133 * 134 * @property _storedDateCells 135 * @type Object 136 * @private 137 */ 138 _storedDateCells : {}, 139 140 /** 141 * Designated initializer 142 * Initializes instance-level properties of 143 * calendar. 144 * 145 * @method initializer 146 */ 147 initializer : function () { 148 this._paneProperties = {}; 149 this._calendarId = Y.guid('calendar'); 150 this._selectedDates = {}; 151 if (isEmpty(this._rules)) { 152 this._rules = {}; 153 } 154 this._storedDateCells = {}; 155 }, 156 157 /** 158 * renderUI implementation 159 * 160 * Creates a visual representation of the calendar based on existing parameters. 161 * @method renderUI 162 */ 163 renderUI : function () { 164 165 var contentBox = this.get('contentBox'); 166 contentBox.appendChild(this._initCalendarHTML(this.get('date'))); 167 168 if (this.get('showPrevMonth')) { 169 this._afterShowPrevMonthChange(); 170 } 171 if (this.get('showNextMonth')) { 172 this._afterShowNextMonthChange(); 173 } 174 175 this._renderCustomRules(); 176 this._renderSelectedDates(); 177 178 this.get("boundingBox").setAttribute("aria-labelledby", this._calendarId + "_header"); 179 180 }, 181 182 /** 183 * bindUI implementation 184 * 185 * Assigns listeners to relevant events that change the state 186 * of the calendar. 187 * @method bindUI 188 */ 189 bindUI : function () { 190 this.after('dateChange', this._afterDateChange); 191 this.after('showPrevMonthChange', this._afterShowPrevMonthChange); 192 this.after('showNextMonthChange', this._afterShowNextMonthChange); 193 this.after('headerRendererChange', this._afterHeaderRendererChange); 194 this.after('customRendererChange', this._afterCustomRendererChange); 195 this.after('enabledDatesRuleChange', this._afterCustomRendererChange); 196 this.after('disabledDatesRuleChange', this._afterCustomRendererChange); 197 this.after('focusedChange', this._afterFocusedChange); 198 this.after('selectionChange', this._renderSelectedDates); 199 this._bindCalendarEvents(); 200 }, 201 202 203 /** 204 * An internal utility method that generates a list of selected dates 205 * from the hash storage. 206 * 207 * @method _getSelectedDatesList 208 * @protected 209 * @return {Array} The array of `Date`s that are currently selected. 210 */ 211 _getSelectedDatesList : function () { 212 var output = []; 213 214 objEach (this._selectedDates, function (year) { 215 objEach (year, function (month) { 216 objEach (month, function (day) { 217 output.push (day); 218 }, this); 219 }, this); 220 }, this); 221 222 return output; 223 }, 224 225 /** 226 * A utility method that returns all dates selected in a specific month. 227 * 228 * @method _getSelectedDatesInMonth 229 * @param {Date} oDate corresponding to the month for which selected dates 230 * are requested. 231 * @protected 232 * @return {Array} The array of `Date`s in a given month that are currently selected. 233 */ 234 _getSelectedDatesInMonth : function (oDate) { 235 var year = oDate.getFullYear(), 236 month = oDate.getMonth(); 237 238 if (hasKey(this._selectedDates, year) && hasKey(this._selectedDates[year], month)) { 239 return Y.Object.values(this._selectedDates[year][month]); 240 } else { 241 return []; 242 } 243 }, 244 245 246 /** 247 * An internal parsing method that receives a String list of numbers 248 * and number ranges (of the form "1,2,3,4-6,7-9,10,11" etc.) and checks 249 * whether a specific number is included in this list. Used for looking 250 * up dates in the customRenderer rule set. 251 * 252 * @method _isNumInList 253 * @param {Number} num The number to look for in a list. 254 * @param {String} strList The list of numbers of the form "1,2,3,4-6,7-8,9", etc. 255 * @private 256 * @return {boolean} Returns true if the given number is in the given list. 257 */ 258 _isNumInList : function (num, strList) { 259 if (strList === "all") { 260 return true; 261 } else { 262 var elements = strList.split(","), 263 i = elements.length, 264 range; 265 266 while (i--) { 267 range = elements[i].split("-"); 268 if (range.length === 2 && num >= parseInt(range[0], 10) && num <= parseInt(range[1], 10)) { 269 return true; 270 } 271 else if (range.length === 1 && (parseInt(elements[i], 10) === num)) { 272 return true; 273 } 274 } 275 return false; 276 } 277 }, 278 279 /** 280 * Given a specific date, returns an array of rules (from the customRenderer rule set) 281 * that the given date matches. 282 * 283 * @method _getRulesForDate 284 * @param {Date} oDate The date for which an array of rules is needed 285 * @private 286 * @return {Array} Returns an array of `String`s, each containg the name of 287 * a rule that the given date matches. 288 */ 289 _getRulesForDate : function (oDate) { 290 var year = oDate.getFullYear(), 291 month = oDate.getMonth(), 292 date = oDate.getDate(), 293 wday = oDate.getDay(), 294 rules = this._rules, 295 outputRules = [], 296 years, months, dates, days; 297 298 for (years in rules) { 299 if (this._isNumInList(year, years)) { 300 if (L.isString(rules[years])) { 301 outputRules.push(rules[years]); 302 } 303 else { 304 for (months in rules[years]) { 305 if (this._isNumInList(month, months)) { 306 if (L.isString(rules[years][months])) { 307 outputRules.push(rules[years][months]); 308 } 309 else { 310 for (dates in rules[years][months]) { 311 if (this._isNumInList(date, dates)) { 312 if (L.isString(rules[years][months][dates])) { 313 outputRules.push(rules[years][months][dates]); 314 } 315 else { 316 for (days in rules[years][months][dates]) { 317 if (this._isNumInList(wday, days)) { 318 if (L.isString(rules[years][months][dates][days])) { 319 outputRules.push(rules[years][months][dates][days]); 320 } 321 } 322 } 323 } 324 } 325 } 326 } 327 } 328 } 329 } 330 } 331 } 332 return outputRules; 333 }, 334 335 /** 336 * A utility method which, given a specific date and a name of the rule, 337 * checks whether the date matches the given rule. 338 * 339 * @method _matchesRule 340 * @param {Date} oDate The date to check 341 * @param {String} rule The name of the rule that the date should match. 342 * @private 343 * @return {boolean} Returns true if the date matches the given rule. 344 * 345 */ 346 _matchesRule : function (oDate, rule) { 347 return (iOf(this._getRulesForDate(oDate), rule) >= 0); 348 }, 349 350 /** 351 * A utility method which checks whether a given date matches the `enabledDatesRule` 352 * or does not match the `disabledDatesRule` and therefore whether it can be selected. 353 * @method _canBeSelected 354 * @param {Date} oDate The date to check 355 * @private 356 * @return {boolean} Returns true if the date can be selected; false otherwise. 357 */ 358 _canBeSelected : function (oDate) { 359 360 var enabledDatesRule = this.get("enabledDatesRule"), 361 disabledDatesRule = this.get("disabledDatesRule"); 362 363 if (enabledDatesRule) { 364 return this._matchesRule(oDate, enabledDatesRule); 365 } else if (disabledDatesRule) { 366 return !this._matchesRule(oDate, disabledDatesRule); 367 } else { 368 return true; 369 } 370 }, 371 372 /** 373 * Selects a given date or array of dates. 374 * @method selectDates 375 * @param {Date|Array} dates A `Date` or `Array` of `Date`s. 376 * @return {CalendarBase} A reference to this object 377 * @chainable 378 */ 379 selectDates : function (dates) { 380 if (ydate.isValidDate(dates)) { 381 this._addDateToSelection(dates); 382 } 383 else if (L.isArray(dates)) { 384 this._addDatesToSelection(dates); 385 } 386 return this; 387 }, 388 389 /** 390 * Deselects a given date or array of dates, or deselects 391 * all dates if no argument is specified. 392 * @method deselectDates 393 * @param {Date|Array} [dates] A `Date` or `Array` of `Date`s, or no 394 * argument if all dates should be deselected. 395 * @return {CalendarBase} A reference to this object 396 * @chainable 397 */ 398 deselectDates : function (dates) { 399 if (!dates) { 400 this._clearSelection(); 401 } 402 else if (ydate.isValidDate(dates)) { 403 this._removeDateFromSelection(dates); 404 } 405 else if (L.isArray(dates)) { 406 this._removeDatesFromSelection(dates); 407 } 408 return this; 409 }, 410 411 /** 412 * A utility method that adds a given date to selection.. 413 * @method _addDateToSelection 414 * @param {Date} oDate The date to add to selection. 415 * @param {Number} [index] An optional parameter that is used 416 * to differentiate between individual date selections and multiple 417 * date selections. 418 * @private 419 */ 420 _addDateToSelection : function (oDate, index) { 421 oDate = this._normalizeTime(oDate); 422 423 if (this._canBeSelected(oDate)) { 424 425 var year = oDate.getFullYear(), 426 month = oDate.getMonth(), 427 day = oDate.getDate(); 428 429 if (hasKey(this._selectedDates, year)) { 430 if (hasKey(this._selectedDates[year], month)) { 431 this._selectedDates[year][month][day] = oDate; 432 } else { 433 this._selectedDates[year][month] = {}; 434 this._selectedDates[year][month][day] = oDate; 435 } 436 } else { 437 this._selectedDates[year] = {}; 438 this._selectedDates[year][month] = {}; 439 this._selectedDates[year][month][day] = oDate; 440 } 441 442 this._selectedDates = setVal(this._selectedDates, [year, month, day], oDate); 443 444 if (!index) { 445 this._fireSelectionChange(); 446 } 447 } 448 }, 449 450 /** 451 * A utility method that adds a given list of dates to selection. 452 * @method _addDatesToSelection 453 * @param {Array} datesArray The list of dates to add to selection. 454 * @private 455 */ 456 _addDatesToSelection : function (datesArray) { 457 arrayEach(datesArray, this._addDateToSelection, this); 458 this._fireSelectionChange(); 459 }, 460 461 /** 462 * A utility method that adds a given range of dates to selection. 463 * @method _addDateRangeToSelection 464 * @param {Date} startDate The first date of the given range. 465 * @param {Date} endDate The last date of the given range. 466 * @private 467 */ 468 _addDateRangeToSelection : function (startDate, endDate) { 469 470 var timezoneDifference = (endDate.getTimezoneOffset() - startDate.getTimezoneOffset())*60000, 471 startTime = startDate.getTime(), 472 endTime = endDate.getTime(), 473 tempTime, 474 time, 475 addedDate; 476 477 if (startTime > endTime) { 478 tempTime = startTime; 479 startTime = endTime; 480 endTime = tempTime + timezoneDifference; 481 } else { 482 endTime = endTime - timezoneDifference; 483 } 484 485 486 for (time = startTime; time <= endTime; time += 86400000) { 487 addedDate = new Date(time); 488 addedDate.setHours(12); 489 this._addDateToSelection(addedDate, time); 490 } 491 this._fireSelectionChange(); 492 }, 493 494 /** 495 * A utility method that removes a given date from selection.. 496 * @method _removeDateFromSelection 497 * @param {Date} oDate The date to remove from selection. 498 * @param {Number} [index] An optional parameter that is used 499 * to differentiate between individual date selections and multiple 500 * date selections. 501 * @private 502 */ 503 _removeDateFromSelection : function (oDate, index) { 504 var year = oDate.getFullYear(), 505 month = oDate.getMonth(), 506 day = oDate.getDate(); 507 508 if (hasKey(this._selectedDates, year) && 509 hasKey(this._selectedDates[year], month) && 510 hasKey(this._selectedDates[year][month], day) 511 ) { 512 delete this._selectedDates[year][month][day]; 513 if (!index) { 514 this._fireSelectionChange(); 515 } 516 } 517 }, 518 519 /** 520 * A utility method that removes a given list of dates from selection. 521 * @method _removeDatesFromSelection 522 * @param {Array} datesArray The list of dates to remove from selection. 523 * @private 524 */ 525 _removeDatesFromSelection : function (datesArray) { 526 arrayEach(datesArray, this._removeDateFromSelection, this); 527 this._fireSelectionChange(); 528 }, 529 530 /** 531 * A utility method that removes a given range of dates from selection. 532 * @method _removeDateRangeFromSelection 533 * @param {Date} startDate The first date of the given range. 534 * @param {Date} endDate The last date of the given range. 535 * @private 536 */ 537 _removeDateRangeFromSelection : function (startDate, endDate) { 538 var startTime = startDate.getTime(), 539 endTime = endDate.getTime(), 540 time; 541 542 for (time = startTime; time <= endTime; time += 86400000) { 543 this._removeDateFromSelection(new Date(time), time); 544 } 545 546 this._fireSelectionChange(); 547 }, 548 549 /** 550 * A utility method that removes all dates from selection. 551 * @method _clearSelection 552 * @param {boolean} noevent A Boolean specifying whether a selectionChange 553 * event should be fired. If true, the event is not fired. 554 * @private 555 */ 556 _clearSelection : function (noevent) { 557 this._selectedDates = {}; 558 this.get("contentBox").all("." + CAL_DAY_SELECTED).removeClass(CAL_DAY_SELECTED).setAttribute("aria-selected", false); 559 if (!noevent) { 560 this._fireSelectionChange(); 561 } 562 }, 563 564 /** 565 * A utility method that fires a selectionChange event. 566 * @method _fireSelectionChange 567 * @private 568 */ 569 _fireSelectionChange : function () { 570 571 /** 572 * Fired when the set of selected dates changes. Contains a payload with 573 * a `newSelection` property with an array of selected dates. 574 * 575 * @event selectionChange 576 */ 577 this.fire("selectionChange", {newSelection: this._getSelectedDatesList()}); 578 }, 579 580 /** 581 * A utility method that restores cells modified by custom formatting. 582 * @method _restoreModifiedCells 583 * @private 584 */ 585 _restoreModifiedCells : function () { 586 var contentbox = this.get("contentBox"), 587 id; 588 for (id in this._storedDateCells) { 589 contentbox.one("#" + id).replace(this._storedDateCells[id]); 590 delete this._storedDateCells[id]; 591 } 592 }, 593 594 /** 595 * A rendering assist method that renders all cells modified by the customRenderer 596 * rules, as well as the enabledDatesRule and disabledDatesRule. 597 * @method _renderCustomRules 598 * @private 599 */ 600 _renderCustomRules : function () { 601 602 this.get("contentBox").all("." + CAL_DAY + ",." + CAL_NEXTMONTH_DAY).removeClass(SELECTION_DISABLED).setAttribute("aria-disabled", false); 603 604 if (!isEmpty(this._rules)) { 605 var paneNum, 606 paneDate, 607 dateArray; 608 609 for (paneNum = 0; paneNum < this._paneNumber; paneNum++) { 610 paneDate = ydate.addMonths(this.get("date"), paneNum); 611 dateArray = ydate.listOfDatesInMonth(paneDate); 612 arrayEach(dateArray, Y.bind(this._renderCustomRulesHelper, this)); 613 } 614 } 615 }, 616 617 /** 618 * A handler for a date selection event (either a click or a keyboard 619 * selection) that adds the appropriate CSS class to a specific DOM 620 * node corresponding to the date and sets its aria-selected 621 * attribute to true. 622 * 623 * @method _renderCustomRulesHelper 624 * @private 625 */ 626 _renderCustomRulesHelper: function (date) { 627 var enRule = this.get("enabledDatesRule"), 628 disRule = this.get("disabledDatesRule"), 629 matchingRules, 630 dateNode; 631 632 matchingRules = this._getRulesForDate(date); 633 if (matchingRules.length > 0) { 634 if ((enRule && iOf(matchingRules, enRule) < 0) || (!enRule && disRule && iOf(matchingRules, disRule) >= 0)) { 635 this._disableDate(date); 636 } 637 638 if (L.isFunction(this._filterFunction)) { 639 dateNode = this._dateToNode(date); 640 this._storedDateCells[dateNode.get("id")] = dateNode.cloneNode(true); 641 this._filterFunction (date, dateNode, matchingRules); 642 } 643 } else if (enRule) { 644 this._disableDate(date); 645 } 646 }, 647 648 /** 649 * A rendering assist method that renders all cells that are currently selected. 650 * @method _renderSelectedDates 651 * @private 652 */ 653 _renderSelectedDates : function () { 654 this.get("contentBox").all("." + CAL_DAY_SELECTED).removeClass(CAL_DAY_SELECTED).setAttribute("aria-selected", false); 655 656 var paneNum, 657 paneDate, 658 dateArray; 659 660 for (paneNum = 0; paneNum < this._paneNumber; paneNum++) { 661 paneDate = ydate.addMonths(this.get("date"), paneNum); 662 dateArray = this._getSelectedDatesInMonth(paneDate); 663 664 arrayEach(dateArray, Y.bind(this._renderSelectedDatesHelper, this)); 665 } 666 }, 667 668 /** 669 * Takes in a date and determines whether that date has any rules 670 * matching it in the customRenderer; then calls the specified 671 * filterFunction if that's the case and/or disables the date 672 * if the rule is specified as a disabledDatesRule. 673 * 674 * @method _renderSelectedDatesHelper 675 * @private 676 */ 677 _renderSelectedDatesHelper: function (date) { 678 this._dateToNode(date).addClass(CAL_DAY_SELECTED).setAttribute("aria-selected", true); 679 }, 680 681 /** 682 * Add the selection-disabled class and aria-disabled attribute to a node corresponding 683 * to a given date. 684 * 685 * @method _disableDate 686 * @param {Date} date The date to disable 687 * @private 688 */ 689 _disableDate: function (date) { 690 this._dateToNode(date).addClass(SELECTION_DISABLED).setAttribute("aria-disabled", true); 691 }, 692 693 /** 694 * A utility method that converts a date to the node wrapping the calendar cell 695 * the date corresponds to.. 696 * @method _dateToNode 697 * @param {Date} oDate The date to convert to Node 698 * @protected 699 * @return {Node} The node wrapping the DOM element of the cell the date 700 * corresponds to. 701 */ 702 _dateToNode : function (oDate) { 703 var day = oDate.getDate(), 704 col = 0, 705 daymod = day%7, 706 paneNum = (12 + oDate.getMonth() - this.get("date").getMonth()) % 12, 707 paneId = this._calendarId + "_pane_" + paneNum, 708 cutoffCol = this._paneProperties[paneId].cutoffCol; 709 710 switch (daymod) { 711 case (0): 712 if (cutoffCol >= 6) { 713 col = 12; 714 } else { 715 col = 5; 716 } 717 break; 718 case (1): 719 col = 6; 720 break; 721 case (2): 722 if (cutoffCol > 0) { 723 col = 7; 724 } else { 725 col = 0; 726 } 727 break; 728 case (3): 729 if (cutoffCol > 1) { 730 col = 8; 731 } else { 732 col = 1; 733 } 734 break; 735 case (4): 736 if (cutoffCol > 2) { 737 col = 9; 738 } else { 739 col = 2; 740 } 741 break; 742 case (5): 743 if (cutoffCol > 3) { 744 col = 10; 745 } else { 746 col = 3; 747 } 748 break; 749 case (6): 750 if (cutoffCol > 4) { 751 col = 11; 752 } else { 753 col = 4; 754 } 755 break; 756 } 757 return(this.get("contentBox").one("#" + this._calendarId + "_pane_" + paneNum + "_" + col + "_" + day)); 758 759 }, 760 761 /** 762 * A utility method that converts a node corresponding to the DOM element of 763 * the cell for a particular date to that date. 764 * @method _nodeToDate 765 * @param {Node} oNode The Node wrapping the DOM element of a particular date cell. 766 * @protected 767 * @return {Date} The date corresponding to the DOM element that the given node wraps. 768 */ 769 _nodeToDate : function (oNode) { 770 771 var idParts = oNode.get("id").split("_").reverse(), 772 paneNum = parseInt(idParts[2], 10), 773 day = parseInt(idParts[0], 10), 774 shiftedDate = ydate.addMonths(this.get("date"), paneNum), 775 year = shiftedDate.getFullYear(), 776 month = shiftedDate.getMonth(); 777 778 return new Date(year, month, day, 12, 0, 0, 0); 779 }, 780 781 /** 782 * A placeholder method, called from bindUI, to bind the Calendar events. 783 * @method _bindCalendarEvents 784 * @protected 785 */ 786 _bindCalendarEvents : function () {}, 787 788 /** 789 * A utility method that normalizes a given date by converting it to the 1st 790 * day of the month the date is in, with the time set to noon. 791 * @method _normalizeDate 792 * @param {Date} oDate The date to normalize 793 * @protected 794 * @return {Date} The normalized date, set to the first of the month, with time 795 * set to noon. 796 */ 797 _normalizeDate : function (date) { 798 if (date) { 799 return new Date(date.getFullYear(), date.getMonth(), 1, 12, 0, 0, 0); 800 } else { 801 return null; 802 } 803 }, 804 805 /** 806 * A utility method that normalizes a given date by setting its time to noon. 807 * @method _normalizeTime 808 * @param {Date} oDate The date to normalize 809 * @protected 810 * @return {Date} The normalized date 811 * set to noon. 812 */ 813 _normalizeTime : function (date) { 814 if (date) { 815 return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 12, 0, 0, 0); 816 } else { 817 return null; 818 } 819 }, 820 821 822 /** 823 * A render assist utility method that computes the cutoff column for the calendar 824 * rendering mask. 825 * @method _getCutoffColumn 826 * @param {Date} date The date of the month grid to compute the cutoff column for. 827 * @param {Number} firstday The first day of the week (modified by internationalized calendars) 828 * @private 829 * @return {Number} The number of the cutoff column. 830 */ 831 _getCutoffColumn : function (date, firstday) { 832 var distance = this._normalizeDate(date).getDay() - firstday, 833 cutOffColumn = 6 - (distance + 7) % 7; 834 return cutOffColumn; 835 }, 836 837 /** 838 * A render assist method that turns on the view of the previous month's dates 839 * in a given calendar pane. 840 * @method _turnPrevMonthOn 841 * @param {Node} pane The calendar pane that needs its previous month's dates view 842 * modified. 843 * @protected 844 */ 845 _turnPrevMonthOn : function (pane) { 846 var pane_id = pane.get("id"), 847 pane_date = this._paneProperties[pane_id].paneDate, 848 daysInPrevMonth = ydate.daysInMonth(ydate.addMonths(pane_date, -1)), 849 cell; 850 851 if (!this._paneProperties[pane_id].hasOwnProperty("daysInPrevMonth")) { 852 this._paneProperties[pane_id].daysInPrevMonth = 0; 853 } 854 855 if (daysInPrevMonth !== this._paneProperties[pane_id].daysInPrevMonth) { 856 857 this._paneProperties[pane_id].daysInPrevMonth = daysInPrevMonth; 858 859 for (cell = 5; cell >= 0; cell--) { 860 pane.one("#" + pane_id + "_" + cell + "_" + (cell-5)).set('text', daysInPrevMonth--); 861 } 862 } 863 }, 864 865 /** 866 * A render assist method that turns off the view of the previous month's dates 867 * in a given calendar pane. 868 * @method _turnPrevMonthOff 869 * @param {Node} pane The calendar pane that needs its previous month's dates view 870 * modified. 871 * @protected 872 */ 873 _turnPrevMonthOff : function (pane) { 874 var pane_id = pane.get("id"), 875 cell; 876 877 this._paneProperties[pane_id].daysInPrevMonth = 0; 878 879 for (cell = 5; cell >= 0; cell--) { 880 pane.one("#" + pane_id + "_" + cell + "_" + (cell-5)).setContent(" "); 881 } 882 }, 883 884 /** 885 * A render assist method that cleans up the last few cells in the month grid 886 * when the number of days in the month changes. 887 * @method _cleanUpNextMonthCells 888 * @param {Node} pane The calendar pane that needs the last date cells cleaned up. 889 * @private 890 */ 891 _cleanUpNextMonthCells : function (pane) { 892 var pane_id = pane.get("id"); 893 pane.one("#" + pane_id + "_6_29").removeClass(CAL_NEXTMONTH_DAY); 894 pane.one("#" + pane_id + "_7_30").removeClass(CAL_NEXTMONTH_DAY); 895 pane.one("#" + pane_id + "_8_31").removeClass(CAL_NEXTMONTH_DAY); 896 pane.one("#" + pane_id + "_0_30").removeClass(CAL_NEXTMONTH_DAY); 897 pane.one("#" + pane_id + "_1_31").removeClass(CAL_NEXTMONTH_DAY); 898 }, 899 900 /** 901 * A render assist method that turns on the view of the next month's dates 902 * in a given calendar pane. 903 * @method _turnNextMonthOn 904 * @param {Node} pane The calendar pane that needs its next month's dates view 905 * modified. 906 * @protected 907 */ 908 _turnNextMonthOn : function (pane) { 909 var dayCounter = 1, 910 pane_id = pane.get("id"), 911 daysInMonth = this._paneProperties[pane_id].daysInMonth, 912 cutoffCol = this._paneProperties[pane_id].cutoffCol, 913 cell, 914 startingCell; 915 916 for (cell = daysInMonth - 22; cell < cutoffCol + 7; cell++) { 917 pane.one("#" + pane_id + "_" + cell + "_" + (cell+23)).set("text", dayCounter++).addClass(CAL_NEXTMONTH_DAY); 918 } 919 920 startingCell = cutoffCol; 921 922 if (daysInMonth === 31 && (cutoffCol <= 1)) { 923 startingCell = 2; 924 } else if (daysInMonth === 30 && cutoffCol === 0) { 925 startingCell = 1; 926 } 927 928 for (cell = startingCell ; cell < cutoffCol + 7; cell++) { 929 pane.one("#" + pane_id + "_" + cell + "_" + (cell+30)).set("text", dayCounter++).addClass(CAL_NEXTMONTH_DAY); 930 } 931 }, 932 933 /** 934 * A render assist method that turns off the view of the next month's dates 935 * in a given calendar pane. 936 * @method _turnNextMonthOff 937 * @param {Node} pane The calendar pane that needs its next month's dates view 938 * modified. 939 * @protected 940 */ 941 _turnNextMonthOff : function (pane) { 942 var pane_id = pane.get("id"), 943 daysInMonth = this._paneProperties[pane_id].daysInMonth, 944 cutoffCol = this._paneProperties[pane_id].cutoffCol, 945 cell, 946 startingCell; 947 948 for (cell = daysInMonth - 22; cell <= 12; cell++) { 949 pane.one("#" + pane_id + "_" + cell + "_" + (cell+23)).setContent(" ").addClass(CAL_NEXTMONTH_DAY); 950 } 951 952 startingCell = 0; 953 954 if (daysInMonth === 31 && (cutoffCol <= 1)) { 955 startingCell = 2; 956 } else if (daysInMonth === 30 && cutoffCol === 0) { 957 startingCell = 1; 958 } 959 960 for (cell = startingCell ; cell <= 12; cell++) { 961 pane.one("#" + pane_id + "_" + cell + "_" + (cell+30)).setContent(" ").addClass(CAL_NEXTMONTH_DAY); 962 } 963 }, 964 965 /** 966 * The handler for the change in the showNextMonth attribute. 967 * @method _afterShowNextMonthChange 968 * @private 969 */ 970 _afterShowNextMonthChange : function () { 971 972 var contentBox = this.get('contentBox'), 973 lastPane = contentBox.one("#" + this._calendarId + "_pane_" + (this._paneNumber - 1)); 974 975 this._cleanUpNextMonthCells(lastPane); 976 977 if (this.get('showNextMonth')) { 978 this._turnNextMonthOn(lastPane); 979 } else { 980 this._turnNextMonthOff(lastPane); 981 } 982 983 }, 984 985 /** 986 * The handler for the change in the showPrevMonth attribute. 987 * @method _afterShowPrevMonthChange 988 * @private 989 */ 990 _afterShowPrevMonthChange : function () { 991 var contentBox = this.get('contentBox'), 992 firstPane = contentBox.one("#" + this._calendarId + "_pane_" + 0); 993 994 if (this.get('showPrevMonth')) { 995 this._turnPrevMonthOn(firstPane); 996 } else { 997 this._turnPrevMonthOff(firstPane); 998 } 999 1000 }, 1001 1002 /** 1003 * The handler for the change in the headerRenderer attribute. 1004 * @method _afterHeaderRendererChange 1005 * @private 1006 */ 1007 _afterHeaderRendererChange : function () { 1008 var headerCell = this.get("contentBox").one("." + CAL_HD_LABEL); 1009 headerCell.setContent(this._updateCalendarHeader(this.get('date'))); 1010 }, 1011 1012 /** 1013 * The handler for the change in the customRenderer attribute. 1014 * @method _afterCustomRendererChange 1015 * @private 1016 */ 1017 _afterCustomRendererChange : function () { 1018 this._restoreModifiedCells(); 1019 this._renderCustomRules(); 1020 }, 1021 1022 /** 1023 * The handler for the change in the date attribute. Modifies the calendar 1024 * view by shifting the calendar grid mask and running custom rendering and 1025 * selection rendering as necessary. 1026 * @method _afterDateChange 1027 * @private 1028 */ 1029 _afterDateChange : function () { 1030 1031 var contentBox = this.get('contentBox'), 1032 headerCell = contentBox.one("." + CAL_HD).one("." + CAL_HD_LABEL), 1033 calendarPanes = contentBox.all("." + CAL_GRID), 1034 currentDate = this.get("date"), 1035 counter = 0; 1036 1037 contentBox.setStyle("visibility", "hidden"); 1038 headerCell.setContent(this._updateCalendarHeader(currentDate)); 1039 1040 this._restoreModifiedCells(); 1041 1042 calendarPanes.each(function (curNode) { 1043 this._rerenderCalendarPane(ydate.addMonths(currentDate, counter++), curNode); 1044 }, this); 1045 1046 this._afterShowPrevMonthChange(); 1047 this._afterShowNextMonthChange(); 1048 1049 this._renderCustomRules(); 1050 this._renderSelectedDates(); 1051 1052 contentBox.setStyle("visibility", "inherit"); 1053 }, 1054 1055 1056 /** 1057 * A rendering assist method that initializes the HTML for a single 1058 * calendar pane. 1059 * @method _initCalendarPane 1060 * @param {Date} baseDate The date corresponding to the month of the given 1061 * calendar pane. 1062 * @param {String} pane_id The id of the pane, to be used as a prefix for 1063 * element ids in the given pane. 1064 * @private 1065 */ 1066 _initCalendarPane : function (baseDate, pane_id) { 1067 // Get a list of short weekdays from the internationalization package, or else use default English ones. 1068 var shortWeekDays = this.get('strings.very_short_weekdays') || ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], 1069 weekDays = Y.Intl.get('datatype-date-format').A, 1070 // Get the first day of the week from the internationalization package, or else use Sunday as default. 1071 firstday = this.get('strings.first_weekday') || 0, 1072 // Compute the cutoff column of the masked calendar table, based on the start date and the first day of week. 1073 cutoffCol = this._getCutoffColumn(baseDate, firstday), 1074 // Compute the number of days in the month based on starting date 1075 daysInMonth = ydate.daysInMonth(baseDate), 1076 // Initialize the array of individual row HTML strings 1077 row_array = ['','','','','',''], 1078 // Initialize the partial templates object 1079 partials = {}, 1080 1081 day, 1082 row, 1083 column, 1084 date, 1085 id_date, 1086 calendar_day_class, 1087 column_visibility, 1088 output; 1089 1090 // Initialize the partial template for the weekday row cells. 1091 partials.weekday_row = ''; 1092 1093 // Populate the partial template for the weekday row cells with weekday names 1094 for (day = firstday; day <= firstday + 6; day++) { 1095 partials.weekday_row += 1096 substitute(CalendarBase.WEEKDAY_TEMPLATE, { 1097 short_weekdayname: shortWeekDays[day%7], 1098 weekdayname: weekDays[day%7] 1099 }); 1100 } 1101 1102 // Populate the partial template for the weekday row container with the weekday row cells 1103 partials.weekday_row_template = substitute(CalendarBase.WEEKDAY_ROW_TEMPLATE, partials); 1104 1105 // Populate the array of individual row HTML strings 1106 for (row = 0; row <= 5; row++) { 1107 1108 for (column = 0; column <= 12; column++) { 1109 1110 // Compute the value of the date that needs to populate the cell 1111 date = 7*row - 5 + column; 1112 1113 // Compose the value of the unique id of the current calendar cell 1114 id_date = pane_id + "_" + column + "_" + date; 1115 1116 // Set the calendar day class to one of three possible values 1117 calendar_day_class = CAL_DAY; 1118 1119 if (date < 1) { 1120 calendar_day_class = CAL_PREVMONTH_DAY; 1121 } else if (date > daysInMonth) { 1122 calendar_day_class = CAL_NEXTMONTH_DAY; 1123 } 1124 1125 // Cut off dates that fall before the first and after the last date of the month 1126 if (date < 1 || date > daysInMonth) { 1127 date = " "; 1128 } 1129 1130 // Decide on whether a column in the masked table is visible or not based on the value of the cutoff column. 1131 column_visibility = (column >= cutoffCol && column < (cutoffCol + 7)) ? '' : CAL_COL_HIDDEN; 1132 1133 // Substitute the values into the partial calendar day template and add it to the current row HTML string 1134 row_array[row] += substitute (CalendarBase.CALDAY_TEMPLATE, { 1135 day_content: date, 1136 calendar_col_class: "calendar_col" + column, 1137 calendar_col_visibility_class: column_visibility, 1138 calendar_day_class: calendar_day_class, 1139 calendar_day_id: id_date 1140 }); 1141 } 1142 } 1143 1144 // Instantiate the partial calendar pane body template 1145 partials.body_template = ''; 1146 1147 // Populate the body template with the rows templates 1148 arrayEach (row_array, function (v) { 1149 partials.body_template += substitute(CalendarBase.CALDAY_ROW_TEMPLATE, {calday_row: v}); 1150 }); 1151 1152 // Populate the calendar grid id 1153 partials.calendar_pane_id = pane_id; 1154 1155 // Populate the calendar pane tabindex 1156 partials.calendar_pane_tabindex = this.get("tabIndex"); 1157 partials.pane_arialabel = ydate.format(baseDate, { format: "%B %Y" }); 1158 1159 1160 // Generate final output by substituting class names. 1161 output = substitute(substitute (CalendarBase.CALENDAR_GRID_TEMPLATE, partials), 1162 CalendarBase.CALENDAR_STRINGS); 1163 1164 // Store the initialized pane information 1165 this._paneProperties[pane_id] = {cutoffCol: cutoffCol, daysInMonth: daysInMonth, paneDate: baseDate}; 1166 1167 return output; 1168 }, 1169 1170 /** 1171 * A rendering assist method that rerenders a specified calendar pane, based 1172 * on a new Date. 1173 * @method _rerenderCalendarPane 1174 * @param {Date} newDate The date corresponding to the month of the given 1175 * calendar pane. 1176 * @param {Node} pane The node corresponding to the calendar pane to be rerenders. 1177 * @private 1178 */ 1179 _rerenderCalendarPane : function (newDate, pane) { 1180 1181 // Get the first day of the week from the internationalization package, or else use Sunday as default. 1182 var firstday = this.get('strings.first_weekday') || 0, 1183 // Compute the cutoff column of the masked calendar table, based on the start date and the first day of week. 1184 cutoffCol = this._getCutoffColumn(newDate, firstday), 1185 // Compute the number of days in the month based on starting date 1186 daysInMonth = ydate.daysInMonth(newDate), 1187 // Get pane id for easier reference 1188 paneId = pane.get("id"), 1189 column, 1190 currentColumn, 1191 curCell; 1192 1193 // Hide the pane before making DOM changes to speed them up 1194 pane.setStyle("visibility", "hidden"); 1195 pane.setAttribute("aria-label", ydate.format(newDate, {format:"%B %Y"})); 1196 1197 // Go through all columns, and flip their visibility setting based on whether they are within the unmasked range. 1198 for (column = 0; column <= 12; column++) { 1199 currentColumn = pane.all("." + "calendar_col" + column); 1200 currentColumn.removeClass(CAL_COL_HIDDEN); 1201 1202 if (column < cutoffCol || column >= (cutoffCol + 7)) { 1203 currentColumn.addClass(CAL_COL_HIDDEN); 1204 } else { 1205 // Clean up dates in visible columns to account for the correct number of days in a month 1206 switch(column) { 1207 case 0: 1208 curCell = pane.one("#" + paneId + "_0_30"); 1209 if (daysInMonth >= 30) { 1210 curCell.set("text", "30"); 1211 curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY); 1212 } else { 1213 curCell.setContent(" "); 1214 curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY); 1215 } 1216 break; 1217 case 1: 1218 curCell = pane.one("#" + paneId + "_1_31"); 1219 if (daysInMonth >= 31) { 1220 curCell.set("text", "31"); 1221 curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY); 1222 } else { 1223 curCell.setContent(" "); 1224 curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY); 1225 } 1226 break; 1227 case 6: 1228 curCell = pane.one("#" + paneId + "_6_29"); 1229 if (daysInMonth >= 29) { 1230 curCell.set("text", "29"); 1231 curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY); 1232 } else { 1233 curCell.setContent(" "); 1234 curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY); 1235 } 1236 break; 1237 case 7: 1238 curCell = pane.one("#" + paneId + "_7_30"); 1239 if (daysInMonth >= 30) { 1240 curCell.set("text", "30"); 1241 curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY); 1242 } else { 1243 curCell.setContent(" "); 1244 curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY); 1245 } 1246 break; 1247 case 8: 1248 curCell = pane.one("#" + paneId + "_8_31"); 1249 if (daysInMonth >= 31) { 1250 curCell.set("text", "31"); 1251 curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY); 1252 } else { 1253 curCell.setContent(" "); 1254 curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY); 1255 } 1256 break; 1257 } 1258 } 1259 } 1260 1261 // Update stored pane properties 1262 this._paneProperties[paneId].cutoffCol = cutoffCol; 1263 this._paneProperties[paneId].daysInMonth = daysInMonth; 1264 this._paneProperties[paneId].paneDate = newDate; 1265 1266 // Bring the pane visibility back after all DOM changes are done 1267 pane.setStyle("visibility", "inherit"); 1268 1269 }, 1270 1271 /** 1272 * A rendering assist method that updates the calendar header based 1273 * on a given date and potentially the provided headerRenderer. 1274 * @method _updateCalendarHeader 1275 * @param {Date} baseDate The date with which to update the calendar header. 1276 * @private 1277 */ 1278 _updateCalendarHeader : function (baseDate) { 1279 var headerString = "", 1280 headerRenderer = this.get("headerRenderer"); 1281 1282 if (Y.Lang.isString(headerRenderer)) { 1283 headerString = ydate.format(baseDate, {format:headerRenderer}); 1284 } else if (headerRenderer instanceof Function) { 1285 headerString = headerRenderer.call(this, baseDate); 1286 } 1287 1288 return headerString; 1289 }, 1290 1291 /** 1292 * A rendering assist method that initializes the calendar header HTML 1293 * based on a given date and potentially the provided headerRenderer. 1294 * @method _initCalendarHeader 1295 * @param {Date} baseDate The date with which to initialize the calendar header. 1296 * @private 1297 */ 1298 _initCalendarHeader : function (baseDate) { 1299 return substitute(substitute(CalendarBase.HEADER_TEMPLATE, { 1300 calheader: this._updateCalendarHeader(baseDate), 1301 calendar_id: this._calendarId 1302 }), CalendarBase.CALENDAR_STRINGS ); 1303 }, 1304 1305 /** 1306 * A rendering assist method that initializes the calendar HTML 1307 * based on a given date. 1308 * @method _initCalendarHTML 1309 * @param {Date} baseDate The date with which to initialize the calendar. 1310 * @private 1311 */ 1312 _initCalendarHTML : function (baseDate) { 1313 // Instantiate the partials holder 1314 var partials = {}, 1315 // Counter for iterative template replacement. 1316 counter = 0, 1317 singlePane, 1318 output; 1319 1320 // Generate the template for the header 1321 partials.header_template = this._initCalendarHeader(baseDate); 1322 partials.calendar_id = this._calendarId; 1323 1324 partials.body_template = substitute(substitute (CalendarBase.CONTENT_TEMPLATE, partials), 1325 CalendarBase.CALENDAR_STRINGS); 1326 1327 // Instantiate the iterative template replacer function 1328 function paneReplacer () { 1329 singlePane = this._initCalendarPane(ydate.addMonths(baseDate, counter), partials.calendar_id + "_pane_" + counter); 1330 counter++; 1331 return singlePane; 1332 } 1333 1334 // Go through all occurrences of the calendar_grid_template token and replace it with an appropriate calendar grid. 1335 output = partials.body_template.replace(/\{calendar_grid_template\}/g, Y.bind(paneReplacer, this)); 1336 1337 // Update the paneNumber count 1338 this._paneNumber = counter; 1339 1340 return output; 1341 } 1342 }, { 1343 1344 /** 1345 * The CSS classnames for the calendar templates. 1346 * @property CALENDAR_STRINGS 1347 * @type Object 1348 * @readOnly 1349 * @protected 1350 * @static 1351 */ 1352 CALENDAR_STRINGS: { 1353 calendar_grid_class : CAL_GRID, 1354 calendar_body_class : CAL_BODY, 1355 calendar_hd_class : CAL_HD, 1356 calendar_hd_label_class : CAL_HD_LABEL, 1357 calendar_weekdayrow_class : CAL_WDAYROW, 1358 calendar_weekday_class : CAL_WDAY, 1359 calendar_row_class : CAL_ROW, 1360 calendar_day_class : CAL_DAY, 1361 calendar_dayanchor_class : CAL_ANCHOR, 1362 calendar_pane_class : CAL_PANE, 1363 calendar_right_grid_class : CAL_RIGHT_GRID, 1364 calendar_left_grid_class : CAL_LEFT_GRID, 1365 calendar_status_class : CAL_STATUS 1366 }, 1367 1368 /* 1369 1370 ARIA_STATUS_TEMPLATE: '<div role="status" aria-atomic="true" class="{calendar_status_class}"></div>', 1371 1372 AriaStatus : null, 1373 1374 updateStatus : function (statusString) { 1375 1376 if (!CalendarBase.AriaStatus) { 1377 CalendarBase.AriaStatus = create( 1378 substitute (CalendarBase.ARIA_STATUS_TEMPLATE, 1379 CalendarBase.CALENDAR_STRINGS)); 1380 Y.one("body").append(CalendarBase.AriaStatus); 1381 } 1382 1383 CalendarBase.AriaStatus.set("text", statusString); 1384 }, 1385 1386 */ 1387 1388 /** 1389 * The main content template for calendar. 1390 * @property CONTENT_TEMPLATE 1391 * @type String 1392 * @protected 1393 * @static 1394 */ 1395 CONTENT_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' + 1396 '{header_template}' + 1397 '<div class="yui3-u-1">' + 1398 '{calendar_grid_template}' + 1399 '</div>' + 1400 '</div>', 1401 1402 /** 1403 * A single pane template for calendar (same as default CONTENT_TEMPLATE) 1404 * @property ONE_PANE_TEMPLATE 1405 * @type String 1406 * @protected 1407 * @readOnly 1408 * @static 1409 */ 1410 ONE_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' + 1411 '{header_template}' + 1412 '<div class="yui3-u-1">' + 1413 '{calendar_grid_template}' + 1414 '</div>' + 1415 '</div>', 1416 1417 /** 1418 * A two pane template for calendar. 1419 * @property TWO_PANE_TEMPLATE 1420 * @type String 1421 * @protected 1422 * @readOnly 1423 * @static 1424 */ 1425 TWO_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' + 1426 '{header_template}' + 1427 '<div class="yui3-u-1-2">'+ 1428 '<div class = "{calendar_left_grid_class}">' + 1429 '{calendar_grid_template}' + 1430 '</div>' + 1431 '</div>' + 1432 '<div class="yui3-u-1-2">' + 1433 '<div class = "{calendar_right_grid_class}">' + 1434 '{calendar_grid_template}' + 1435 '</div>' + 1436 '</div>' + 1437 '</div>', 1438 /** 1439 * A three pane template for calendar. 1440 * @property THREE_PANE_TEMPLATE 1441 * @type String 1442 * @protected 1443 * @readOnly 1444 * @static 1445 */ 1446 THREE_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' + 1447 '{header_template}' + 1448 '<div class="yui3-u-1-3">' + 1449 '<div class="{calendar_left_grid_class}">' + 1450 '{calendar_grid_template}' + 1451 '</div>' + 1452 '</div>' + 1453 '<div class="yui3-u-1-3">' + 1454 '{calendar_grid_template}' + 1455 '</div>' + 1456 '<div class="yui3-u-1-3">' + 1457 '<div class="{calendar_right_grid_class}">' + 1458 '{calendar_grid_template}' + 1459 '</div>' + 1460 '</div>' + 1461 '</div>', 1462 /** 1463 * A template for the calendar grid. 1464 * @property CALENDAR_GRID_TEMPLATE 1465 * @type String 1466 * @protected 1467 * @static 1468 */ 1469 CALENDAR_GRID_TEMPLATE: '<table class="{calendar_grid_class}" id="{calendar_pane_id}" role="grid" aria-readonly="true" ' + 1470 'aria-label="{pane_arialabel}" tabindex="{calendar_pane_tabindex}">' + 1471 '<thead>' + 1472 '{weekday_row_template}' + 1473 '</thead>' + 1474 '<tbody>' + 1475 '{body_template}' + 1476 '</tbody>' + 1477 '</table>', 1478 1479 /** 1480 * A template for the calendar header. 1481 * @property HEADER_TEMPLATE 1482 * @type String 1483 * @protected 1484 * @static 1485 */ 1486 HEADER_TEMPLATE: '<div class="yui3-g {calendar_hd_class}">' + 1487 '<div class="yui3-u {calendar_hd_label_class}" id="{calendar_id}_header" aria-role="heading">' + 1488 '{calheader}' + 1489 '</div>' + 1490 '</div>', 1491 1492 /** 1493 * A template for the row of weekday names. 1494 * @property WEEKDAY_ROW_TEMPLATE 1495 * @type String 1496 * @protected 1497 * @static 1498 */ 1499 WEEKDAY_ROW_TEMPLATE: '<tr class="{calendar_weekdayrow_class}" role="row">' + 1500 '{weekday_row}' + 1501 '</tr>', 1502 1503 /** 1504 * A template for a single row of calendar days. 1505 * @property CALDAY_ROW_TEMPLATE 1506 * @type String 1507 * @protected 1508 * @static 1509 */ 1510 CALDAY_ROW_TEMPLATE: '<tr class="{calendar_row_class}" role="row">' + 1511 '{calday_row}' + 1512 '</tr>', 1513 1514 /** 1515 * A template for a single cell with a weekday name. 1516 * @property WEEKDAY_TEMPLATE 1517 * @type String 1518 * @protected 1519 * @static 1520 */ 1521 WEEKDAY_TEMPLATE: '<th class="{calendar_weekday_class}" role="columnheader" aria-label="{weekdayname}">{short_weekdayname}</th>', 1522 1523 /** 1524 * A template for a single cell with a calendar day. 1525 * @property CALDAY_TEMPLATE 1526 * @type String 1527 * @protected 1528 * @static 1529 */ 1530 CALDAY_TEMPLATE: '<td class="{calendar_col_class} {calendar_day_class} {calendar_col_visibility_class}" id="{calendar_day_id}" ' + 1531 'role="gridcell" tabindex="-1">' + 1532 '{day_content}' + 1533 '</td>', 1534 1535 /** 1536 * The identity of the widget. 1537 * 1538 * @property NAME 1539 * @type String 1540 * @default 'calendarBase' 1541 * @readOnly 1542 * @protected 1543 * @static 1544 */ 1545 NAME: 'calendarBase', 1546 1547 /** 1548 * Static property used to define the default attribute configuration of 1549 * the Widget. 1550 * 1551 * @property ATTRS 1552 * @type {Object} 1553 * @protected 1554 * @static 1555 */ 1556 ATTRS: { 1557 tabIndex: { 1558 value: 1 1559 }, 1560 /** 1561 * The date corresponding to the current calendar view. Always 1562 * normalized to the first of the month that contains the date 1563 * at assignment time. Used as the first date visible in the 1564 * calendar. 1565 * 1566 * @attribute date 1567 * @type Date 1568 * @default The first of the month containing today's date, as 1569 * set on the end user's system. 1570 */ 1571 date: { 1572 value: new Date(), 1573 setter: function (val) { 1574 var newDate = this._normalizeDate(val); 1575 if (ydate.areEqual(newDate, this.get('date'))) { 1576 return this.get('date'); 1577 } else { 1578 return newDate; 1579 } 1580 } 1581 }, 1582 1583 /** 1584 * A setting specifying whether to shows days from the previous 1585 * month in the visible month's grid, if there are empty preceding 1586 * cells available. 1587 * 1588 * @attribute showPrevMonth 1589 * @type boolean 1590 * @default false 1591 */ 1592 showPrevMonth: { 1593 value: false 1594 }, 1595 1596 /** 1597 * A setting specifying whether to shows days from the next 1598 * month in the visible month's grid, if there are empty 1599 * cells available at the end. 1600 * 1601 * @attribute showNextMonth 1602 * @type boolean 1603 * @default false 1604 */ 1605 showNextMonth: { 1606 value: false 1607 }, 1608 1609 /** 1610 * Strings and properties derived from the internationalization packages 1611 * for the calendar. 1612 * 1613 * @attribute strings 1614 * @type Object 1615 * @protected 1616 */ 1617 strings : { 1618 valueFn: function() { return Y.Intl.get("calendar-base"); } 1619 }, 1620 1621 /** 1622 * Custom header renderer for the calendar. 1623 * 1624 * @attribute headerRenderer 1625 * @type String | Function 1626 */ 1627 headerRenderer: { 1628 value: "%B %Y" 1629 }, 1630 1631 /** 1632 * The name of the rule which all enabled dates should match. 1633 * Either disabledDatesRule or enabledDatesRule should be specified, 1634 * or neither, but not both. 1635 * 1636 * @attribute enabledDatesRule 1637 * @type String 1638 * @default null 1639 */ 1640 enabledDatesRule: { 1641 value: null 1642 }, 1643 1644 /** 1645 * The name of the rule which all disabled dates should match. 1646 * Either disabledDatesRule or enabledDatesRule should be specified, 1647 * or neither, but not both. 1648 * 1649 * @attribute disabledDatesRule 1650 * @type String 1651 * @default null 1652 */ 1653 disabledDatesRule: { 1654 value: null 1655 }, 1656 1657 /** 1658 * A read-only attribute providing a list of currently selected dates. 1659 * 1660 * @attribute selectedDates 1661 * @readOnly 1662 * @type Array 1663 */ 1664 selectedDates : { 1665 readOnly: true, 1666 getter: function () { 1667 return (this._getSelectedDatesList()); 1668 } 1669 }, 1670 1671 /** 1672 * An object of the form {rules:Object, filterFunction:Function}, 1673 * providing set of rules and a custom rendering function for 1674 * customizing specific calendar cells. 1675 * 1676 * @attribute customRenderer 1677 * @type Object 1678 * @default {} 1679 */ 1680 customRenderer : { 1681 lazyAdd: false, 1682 value: {}, 1683 setter: function (val) { 1684 this._rules = val.rules; 1685 this._filterFunction = val.filterFunction; 1686 } 1687 } 1688 } 1689 1690 }); 1691 1692 1693 }, '3.17.2', { 1694 "requires": [ 1695 "widget", 1696 "datatype-date", 1697 "datatype-date-math", 1698 "cssgrids" 1699 ], 1700 "lang": [ 1701 "de", 1702 "en", 1703 "es", 1704 "es-AR", 1705 "fr", 1706 "hu", 1707 "it", 1708 "ja", 1709 "nb-NO", 1710 "nl", 1711 "pt-BR", 1712 "ru", 1713 "zh-Hans", 1714 "zh-Hans-CN", 1715 "zh-Hant", 1716 "zh-Hant-HK", 1717 "zh-HANT-TW" 1718 ], 1719 "skinnable": true 1720 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |