[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/calendar-base/ -> calendar-base.js (source)

   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("&nbsp;");
 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("&nbsp;").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("&nbsp;").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 = "&nbsp;";
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("&nbsp;");
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("&nbsp;");
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("&nbsp;");
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("&nbsp;");
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("&nbsp;");
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  });


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1