PageRenderTime 81ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/resources/org/apache/struts2/static/calendar/calendar.js

http://struts2yuiplugin.googlecode.com/
JavaScript | 7148 lines | 3010 code | 916 blank | 3222 comment | 553 complexity | c1f4fbc5d520aed1d29fc19fd4378d7a MD5 | raw file
  1. /*
  2. Copyright (c) 2009, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.net/yui/license.txt
  5. version: 2.7.0
  6. */
  7. (function () {
  8. /**
  9. * Config is a utility used within an Object to allow the implementer to
  10. * maintain a list of local configuration properties and listen for changes
  11. * to those properties dynamically using CustomEvent. The initial values are
  12. * also maintained so that the configuration can be reset at any given point
  13. * to its initial state.
  14. * @namespace YAHOO.util
  15. * @class Config
  16. * @constructor
  17. * @param {Object} owner The owner Object to which this Config Object belongs
  18. */
  19. YAHOO.util.Config = function (owner) {
  20. if (owner) {
  21. this.init(owner);
  22. }
  23. };
  24. var Lang = YAHOO.lang,
  25. CustomEvent = YAHOO.util.CustomEvent,
  26. Config = YAHOO.util.Config;
  27. /**
  28. * Constant representing the CustomEvent type for the config changed event.
  29. * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
  30. * @private
  31. * @static
  32. * @final
  33. */
  34. Config.CONFIG_CHANGED_EVENT = "configChanged";
  35. /**
  36. * Constant representing the boolean type string
  37. * @property YAHOO.util.Config.BOOLEAN_TYPE
  38. * @private
  39. * @static
  40. * @final
  41. */
  42. Config.BOOLEAN_TYPE = "boolean";
  43. Config.prototype = {
  44. /**
  45. * Object reference to the owner of this Config Object
  46. * @property owner
  47. * @type Object
  48. */
  49. owner: null,
  50. /**
  51. * Boolean flag that specifies whether a queue is currently
  52. * being executed
  53. * @property queueInProgress
  54. * @type Boolean
  55. */
  56. queueInProgress: false,
  57. /**
  58. * Maintains the local collection of configuration property objects and
  59. * their specified values
  60. * @property config
  61. * @private
  62. * @type Object
  63. */
  64. config: null,
  65. /**
  66. * Maintains the local collection of configuration property objects as
  67. * they were initially applied.
  68. * This object is used when resetting a property.
  69. * @property initialConfig
  70. * @private
  71. * @type Object
  72. */
  73. initialConfig: null,
  74. /**
  75. * Maintains the local, normalized CustomEvent queue
  76. * @property eventQueue
  77. * @private
  78. * @type Object
  79. */
  80. eventQueue: null,
  81. /**
  82. * Custom Event, notifying subscribers when Config properties are set
  83. * (setProperty is called without the silent flag
  84. * @event configChangedEvent
  85. */
  86. configChangedEvent: null,
  87. /**
  88. * Initializes the configuration Object and all of its local members.
  89. * @method init
  90. * @param {Object} owner The owner Object to which this Config
  91. * Object belongs
  92. */
  93. init: function (owner) {
  94. this.owner = owner;
  95. this.configChangedEvent =
  96. this.createEvent(Config.CONFIG_CHANGED_EVENT);
  97. this.configChangedEvent.signature = CustomEvent.LIST;
  98. this.queueInProgress = false;
  99. this.config = {};
  100. this.initialConfig = {};
  101. this.eventQueue = [];
  102. },
  103. /**
  104. * Validates that the value passed in is a Boolean.
  105. * @method checkBoolean
  106. * @param {Object} val The value to validate
  107. * @return {Boolean} true, if the value is valid
  108. */
  109. checkBoolean: function (val) {
  110. return (typeof val == Config.BOOLEAN_TYPE);
  111. },
  112. /**
  113. * Validates that the value passed in is a number.
  114. * @method checkNumber
  115. * @param {Object} val The value to validate
  116. * @return {Boolean} true, if the value is valid
  117. */
  118. checkNumber: function (val) {
  119. return (!isNaN(val));
  120. },
  121. /**
  122. * Fires a configuration property event using the specified value.
  123. * @method fireEvent
  124. * @private
  125. * @param {String} key The configuration property's name
  126. * @param {value} Object The value of the correct type for the property
  127. */
  128. fireEvent: function ( key, value ) {
  129. var property = this.config[key];
  130. if (property && property.event) {
  131. property.event.fire(value);
  132. }
  133. },
  134. /**
  135. * Adds a property to the Config Object's private config hash.
  136. * @method addProperty
  137. * @param {String} key The configuration property's name
  138. * @param {Object} propertyObject The Object containing all of this
  139. * property's arguments
  140. */
  141. addProperty: function ( key, propertyObject ) {
  142. key = key.toLowerCase();
  143. this.config[key] = propertyObject;
  144. propertyObject.event = this.createEvent(key, { scope: this.owner });
  145. propertyObject.event.signature = CustomEvent.LIST;
  146. propertyObject.key = key;
  147. if (propertyObject.handler) {
  148. propertyObject.event.subscribe(propertyObject.handler,
  149. this.owner);
  150. }
  151. this.setProperty(key, propertyObject.value, true);
  152. if (! propertyObject.suppressEvent) {
  153. this.queueProperty(key, propertyObject.value);
  154. }
  155. },
  156. /**
  157. * Returns a key-value configuration map of the values currently set in
  158. * the Config Object.
  159. * @method getConfig
  160. * @return {Object} The current config, represented in a key-value map
  161. */
  162. getConfig: function () {
  163. var cfg = {},
  164. currCfg = this.config,
  165. prop,
  166. property;
  167. for (prop in currCfg) {
  168. if (Lang.hasOwnProperty(currCfg, prop)) {
  169. property = currCfg[prop];
  170. if (property && property.event) {
  171. cfg[prop] = property.value;
  172. }
  173. }
  174. }
  175. return cfg;
  176. },
  177. /**
  178. * Returns the value of specified property.
  179. * @method getProperty
  180. * @param {String} key The name of the property
  181. * @return {Object} The value of the specified property
  182. */
  183. getProperty: function (key) {
  184. var property = this.config[key.toLowerCase()];
  185. if (property && property.event) {
  186. return property.value;
  187. } else {
  188. return undefined;
  189. }
  190. },
  191. /**
  192. * Resets the specified property's value to its initial value.
  193. * @method resetProperty
  194. * @param {String} key The name of the property
  195. * @return {Boolean} True is the property was reset, false if not
  196. */
  197. resetProperty: function (key) {
  198. key = key.toLowerCase();
  199. var property = this.config[key];
  200. if (property && property.event) {
  201. if (this.initialConfig[key] &&
  202. !Lang.isUndefined(this.initialConfig[key])) {
  203. this.setProperty(key, this.initialConfig[key]);
  204. return true;
  205. }
  206. } else {
  207. return false;
  208. }
  209. },
  210. /**
  211. * Sets the value of a property. If the silent property is passed as
  212. * true, the property's event will not be fired.
  213. * @method setProperty
  214. * @param {String} key The name of the property
  215. * @param {String} value The value to set the property to
  216. * @param {Boolean} silent Whether the value should be set silently,
  217. * without firing the property event.
  218. * @return {Boolean} True, if the set was successful, false if it failed.
  219. */
  220. setProperty: function (key, value, silent) {
  221. var property;
  222. key = key.toLowerCase();
  223. if (this.queueInProgress && ! silent) {
  224. // Currently running through a queue...
  225. this.queueProperty(key,value);
  226. return true;
  227. } else {
  228. property = this.config[key];
  229. if (property && property.event) {
  230. if (property.validator && !property.validator(value)) {
  231. return false;
  232. } else {
  233. property.value = value;
  234. if (! silent) {
  235. this.fireEvent(key, value);
  236. this.configChangedEvent.fire([key, value]);
  237. }
  238. return true;
  239. }
  240. } else {
  241. return false;
  242. }
  243. }
  244. },
  245. /**
  246. * Sets the value of a property and queues its event to execute. If the
  247. * event is already scheduled to execute, it is
  248. * moved from its current position to the end of the queue.
  249. * @method queueProperty
  250. * @param {String} key The name of the property
  251. * @param {String} value The value to set the property to
  252. * @return {Boolean} true, if the set was successful, false if
  253. * it failed.
  254. */
  255. queueProperty: function (key, value) {
  256. key = key.toLowerCase();
  257. var property = this.config[key],
  258. foundDuplicate = false,
  259. iLen,
  260. queueItem,
  261. queueItemKey,
  262. queueItemValue,
  263. sLen,
  264. supercedesCheck,
  265. qLen,
  266. queueItemCheck,
  267. queueItemCheckKey,
  268. queueItemCheckValue,
  269. i,
  270. s,
  271. q;
  272. if (property && property.event) {
  273. if (!Lang.isUndefined(value) && property.validator &&
  274. !property.validator(value)) { // validator
  275. return false;
  276. } else {
  277. if (!Lang.isUndefined(value)) {
  278. property.value = value;
  279. } else {
  280. value = property.value;
  281. }
  282. foundDuplicate = false;
  283. iLen = this.eventQueue.length;
  284. for (i = 0; i < iLen; i++) {
  285. queueItem = this.eventQueue[i];
  286. if (queueItem) {
  287. queueItemKey = queueItem[0];
  288. queueItemValue = queueItem[1];
  289. if (queueItemKey == key) {
  290. /*
  291. found a dupe... push to end of queue, null
  292. current item, and break
  293. */
  294. this.eventQueue[i] = null;
  295. this.eventQueue.push(
  296. [key, (!Lang.isUndefined(value) ?
  297. value : queueItemValue)]);
  298. foundDuplicate = true;
  299. break;
  300. }
  301. }
  302. }
  303. // this is a refire, or a new property in the queue
  304. if (! foundDuplicate && !Lang.isUndefined(value)) {
  305. this.eventQueue.push([key, value]);
  306. }
  307. }
  308. if (property.supercedes) {
  309. sLen = property.supercedes.length;
  310. for (s = 0; s < sLen; s++) {
  311. supercedesCheck = property.supercedes[s];
  312. qLen = this.eventQueue.length;
  313. for (q = 0; q < qLen; q++) {
  314. queueItemCheck = this.eventQueue[q];
  315. if (queueItemCheck) {
  316. queueItemCheckKey = queueItemCheck[0];
  317. queueItemCheckValue = queueItemCheck[1];
  318. if (queueItemCheckKey ==
  319. supercedesCheck.toLowerCase() ) {
  320. this.eventQueue.push([queueItemCheckKey,
  321. queueItemCheckValue]);
  322. this.eventQueue[q] = null;
  323. break;
  324. }
  325. }
  326. }
  327. }
  328. }
  329. return true;
  330. } else {
  331. return false;
  332. }
  333. },
  334. /**
  335. * Fires the event for a property using the property's current value.
  336. * @method refireEvent
  337. * @param {String} key The name of the property
  338. */
  339. refireEvent: function (key) {
  340. key = key.toLowerCase();
  341. var property = this.config[key];
  342. if (property && property.event &&
  343. !Lang.isUndefined(property.value)) {
  344. if (this.queueInProgress) {
  345. this.queueProperty(key);
  346. } else {
  347. this.fireEvent(key, property.value);
  348. }
  349. }
  350. },
  351. /**
  352. * Applies a key-value Object literal to the configuration, replacing
  353. * any existing values, and queueing the property events.
  354. * Although the values will be set, fireQueue() must be called for their
  355. * associated events to execute.
  356. * @method applyConfig
  357. * @param {Object} userConfig The configuration Object literal
  358. * @param {Boolean} init When set to true, the initialConfig will
  359. * be set to the userConfig passed in, so that calling a reset will
  360. * reset the properties to the passed values.
  361. */
  362. applyConfig: function (userConfig, init) {
  363. var sKey,
  364. oConfig;
  365. if (init) {
  366. oConfig = {};
  367. for (sKey in userConfig) {
  368. if (Lang.hasOwnProperty(userConfig, sKey)) {
  369. oConfig[sKey.toLowerCase()] = userConfig[sKey];
  370. }
  371. }
  372. this.initialConfig = oConfig;
  373. }
  374. for (sKey in userConfig) {
  375. if (Lang.hasOwnProperty(userConfig, sKey)) {
  376. this.queueProperty(sKey, userConfig[sKey]);
  377. }
  378. }
  379. },
  380. /**
  381. * Refires the events for all configuration properties using their
  382. * current values.
  383. * @method refresh
  384. */
  385. refresh: function () {
  386. var prop;
  387. for (prop in this.config) {
  388. if (Lang.hasOwnProperty(this.config, prop)) {
  389. this.refireEvent(prop);
  390. }
  391. }
  392. },
  393. /**
  394. * Fires the normalized list of queued property change events
  395. * @method fireQueue
  396. */
  397. fireQueue: function () {
  398. var i,
  399. queueItem,
  400. key,
  401. value,
  402. property;
  403. this.queueInProgress = true;
  404. for (i = 0;i < this.eventQueue.length; i++) {
  405. queueItem = this.eventQueue[i];
  406. if (queueItem) {
  407. key = queueItem[0];
  408. value = queueItem[1];
  409. property = this.config[key];
  410. property.value = value;
  411. // Clear out queue entry, to avoid it being
  412. // re-added to the queue by any queueProperty/supercedes
  413. // calls which are invoked during fireEvent
  414. this.eventQueue[i] = null;
  415. this.fireEvent(key,value);
  416. }
  417. }
  418. this.queueInProgress = false;
  419. this.eventQueue = [];
  420. },
  421. /**
  422. * Subscribes an external handler to the change event for any
  423. * given property.
  424. * @method subscribeToConfigEvent
  425. * @param {String} key The property name
  426. * @param {Function} handler The handler function to use subscribe to
  427. * the property's event
  428. * @param {Object} obj The Object to use for scoping the event handler
  429. * (see CustomEvent documentation)
  430. * @param {Boolean} override Optional. If true, will override "this"
  431. * within the handler to map to the scope Object passed into the method.
  432. * @return {Boolean} True, if the subscription was successful,
  433. * otherwise false.
  434. */
  435. subscribeToConfigEvent: function (key, handler, obj, override) {
  436. var property = this.config[key.toLowerCase()];
  437. if (property && property.event) {
  438. if (!Config.alreadySubscribed(property.event, handler, obj)) {
  439. property.event.subscribe(handler, obj, override);
  440. }
  441. return true;
  442. } else {
  443. return false;
  444. }
  445. },
  446. /**
  447. * Unsubscribes an external handler from the change event for any
  448. * given property.
  449. * @method unsubscribeFromConfigEvent
  450. * @param {String} key The property name
  451. * @param {Function} handler The handler function to use subscribe to
  452. * the property's event
  453. * @param {Object} obj The Object to use for scoping the event
  454. * handler (see CustomEvent documentation)
  455. * @return {Boolean} True, if the unsubscription was successful,
  456. * otherwise false.
  457. */
  458. unsubscribeFromConfigEvent: function (key, handler, obj) {
  459. var property = this.config[key.toLowerCase()];
  460. if (property && property.event) {
  461. return property.event.unsubscribe(handler, obj);
  462. } else {
  463. return false;
  464. }
  465. },
  466. /**
  467. * Returns a string representation of the Config object
  468. * @method toString
  469. * @return {String} The Config object in string format.
  470. */
  471. toString: function () {
  472. var output = "Config";
  473. if (this.owner) {
  474. output += " [" + this.owner.toString() + "]";
  475. }
  476. return output;
  477. },
  478. /**
  479. * Returns a string representation of the Config object's current
  480. * CustomEvent queue
  481. * @method outputEventQueue
  482. * @return {String} The string list of CustomEvents currently queued
  483. * for execution
  484. */
  485. outputEventQueue: function () {
  486. var output = "",
  487. queueItem,
  488. q,
  489. nQueue = this.eventQueue.length;
  490. for (q = 0; q < nQueue; q++) {
  491. queueItem = this.eventQueue[q];
  492. if (queueItem) {
  493. output += queueItem[0] + "=" + queueItem[1] + ", ";
  494. }
  495. }
  496. return output;
  497. },
  498. /**
  499. * Sets all properties to null, unsubscribes all listeners from each
  500. * property's change event and all listeners from the configChangedEvent.
  501. * @method destroy
  502. */
  503. destroy: function () {
  504. var oConfig = this.config,
  505. sProperty,
  506. oProperty;
  507. for (sProperty in oConfig) {
  508. if (Lang.hasOwnProperty(oConfig, sProperty)) {
  509. oProperty = oConfig[sProperty];
  510. oProperty.event.unsubscribeAll();
  511. oProperty.event = null;
  512. }
  513. }
  514. this.configChangedEvent.unsubscribeAll();
  515. this.configChangedEvent = null;
  516. this.owner = null;
  517. this.config = null;
  518. this.initialConfig = null;
  519. this.eventQueue = null;
  520. }
  521. };
  522. /**
  523. * Checks to determine if a particular function/Object pair are already
  524. * subscribed to the specified CustomEvent
  525. * @method YAHOO.util.Config.alreadySubscribed
  526. * @static
  527. * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
  528. * the subscriptions
  529. * @param {Function} fn The function to look for in the subscribers list
  530. * @param {Object} obj The execution scope Object for the subscription
  531. * @return {Boolean} true, if the function/Object pair is already subscribed
  532. * to the CustomEvent passed in
  533. */
  534. Config.alreadySubscribed = function (evt, fn, obj) {
  535. var nSubscribers = evt.subscribers.length,
  536. subsc,
  537. i;
  538. if (nSubscribers > 0) {
  539. i = nSubscribers - 1;
  540. do {
  541. subsc = evt.subscribers[i];
  542. if (subsc && subsc.obj == obj && subsc.fn == fn) {
  543. return true;
  544. }
  545. }
  546. while (i--);
  547. }
  548. return false;
  549. };
  550. YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
  551. }());
  552. /**
  553. * YAHOO.widget.DateMath is used for simple date manipulation. The class is a static utility
  554. * used for adding, subtracting, and comparing dates.
  555. * @namespace YAHOO.widget
  556. * @class DateMath
  557. */
  558. YAHOO.widget.DateMath = {
  559. /**
  560. * Constant field representing Day
  561. * @property DAY
  562. * @static
  563. * @final
  564. * @type String
  565. */
  566. DAY : "D",
  567. /**
  568. * Constant field representing Week
  569. * @property WEEK
  570. * @static
  571. * @final
  572. * @type String
  573. */
  574. WEEK : "W",
  575. /**
  576. * Constant field representing Year
  577. * @property YEAR
  578. * @static
  579. * @final
  580. * @type String
  581. */
  582. YEAR : "Y",
  583. /**
  584. * Constant field representing Month
  585. * @property MONTH
  586. * @static
  587. * @final
  588. * @type String
  589. */
  590. MONTH : "M",
  591. /**
  592. * Constant field representing one day, in milliseconds
  593. * @property ONE_DAY_MS
  594. * @static
  595. * @final
  596. * @type Number
  597. */
  598. ONE_DAY_MS : 1000*60*60*24,
  599. /**
  600. * Constant field representing the date in first week of January
  601. * which identifies the first week of the year.
  602. * <p>
  603. * In the U.S, Jan 1st is normally used based on a Sunday start of week.
  604. * ISO 8601, used widely throughout Europe, uses Jan 4th, based on a Monday start of week.
  605. * </p>
  606. * @property WEEK_ONE_JAN_DATE
  607. * @static
  608. * @type Number
  609. */
  610. WEEK_ONE_JAN_DATE : 1,
  611. /**
  612. * Adds the specified amount of time to the this instance.
  613. * @method add
  614. * @param {Date} date The JavaScript Date object to perform addition on
  615. * @param {String} field The field constant to be used for performing addition.
  616. * @param {Number} amount The number of units (measured in the field constant) to add to the date.
  617. * @return {Date} The resulting Date object
  618. */
  619. add : function(date, field, amount) {
  620. var d = new Date(date.getTime());
  621. switch (field) {
  622. case this.MONTH:
  623. var newMonth = date.getMonth() + amount;
  624. var years = 0;
  625. if (newMonth < 0) {
  626. while (newMonth < 0) {
  627. newMonth += 12;
  628. years -= 1;
  629. }
  630. } else if (newMonth > 11) {
  631. while (newMonth > 11) {
  632. newMonth -= 12;
  633. years += 1;
  634. }
  635. }
  636. d.setMonth(newMonth);
  637. d.setFullYear(date.getFullYear() + years);
  638. break;
  639. case this.DAY:
  640. this._addDays(d, amount);
  641. // d.setDate(date.getDate() + amount);
  642. break;
  643. case this.YEAR:
  644. d.setFullYear(date.getFullYear() + amount);
  645. break;
  646. case this.WEEK:
  647. this._addDays(d, (amount * 7));
  648. // d.setDate(date.getDate() + (amount * 7));
  649. break;
  650. }
  651. return d;
  652. },
  653. /**
  654. * Private helper method to account for bug in Safari 2 (webkit < 420)
  655. * when Date.setDate(n) is called with n less than -128 or greater than 127.
  656. * <p>
  657. * Fix approach and original findings are available here:
  658. * http://brianary.blogspot.com/2006/03/safari-date-bug.html
  659. * </p>
  660. * @method _addDays
  661. * @param {Date} d JavaScript date object
  662. * @param {Number} nDays The number of days to add to the date object (can be negative)
  663. * @private
  664. */
  665. _addDays : function(d, nDays) {
  666. if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420) {
  667. if (nDays < 0) {
  668. // Ensure we don't go below -128 (getDate() is always 1 to 31, so we won't go above 127)
  669. for(var min = -128; nDays < min; nDays -= min) {
  670. d.setDate(d.getDate() + min);
  671. }
  672. } else {
  673. // Ensure we don't go above 96 + 31 = 127
  674. for(var max = 96; nDays > max; nDays -= max) {
  675. d.setDate(d.getDate() + max);
  676. }
  677. }
  678. // nDays should be remainder between -128 and 96
  679. }
  680. d.setDate(d.getDate() + nDays);
  681. },
  682. /**
  683. * Subtracts the specified amount of time from the this instance.
  684. * @method subtract
  685. * @param {Date} date The JavaScript Date object to perform subtraction on
  686. * @param {Number} field The this field constant to be used for performing subtraction.
  687. * @param {Number} amount The number of units (measured in the field constant) to subtract from the date.
  688. * @return {Date} The resulting Date object
  689. */
  690. subtract : function(date, field, amount) {
  691. return this.add(date, field, (amount*-1));
  692. },
  693. /**
  694. * Determines whether a given date is before another date on the calendar.
  695. * @method before
  696. * @param {Date} date The Date object to compare with the compare argument
  697. * @param {Date} compareTo The Date object to use for the comparison
  698. * @return {Boolean} true if the date occurs before the compared date; false if not.
  699. */
  700. before : function(date, compareTo) {
  701. var ms = compareTo.getTime();
  702. if (date.getTime() < ms) {
  703. return true;
  704. } else {
  705. return false;
  706. }
  707. },
  708. /**
  709. * Determines whether a given date is after another date on the calendar.
  710. * @method after
  711. * @param {Date} date The Date object to compare with the compare argument
  712. * @param {Date} compareTo The Date object to use for the comparison
  713. * @return {Boolean} true if the date occurs after the compared date; false if not.
  714. */
  715. after : function(date, compareTo) {
  716. var ms = compareTo.getTime();
  717. if (date.getTime() > ms) {
  718. return true;
  719. } else {
  720. return false;
  721. }
  722. },
  723. /**
  724. * Determines whether a given date is between two other dates on the calendar.
  725. * @method between
  726. * @param {Date} date The date to check for
  727. * @param {Date} dateBegin The start of the range
  728. * @param {Date} dateEnd The end of the range
  729. * @return {Boolean} true if the date occurs between the compared dates; false if not.
  730. */
  731. between : function(date, dateBegin, dateEnd) {
  732. if (this.after(date, dateBegin) && this.before(date, dateEnd)) {
  733. return true;
  734. } else {
  735. return false;
  736. }
  737. },
  738. /**
  739. * Retrieves a JavaScript Date object representing January 1 of any given year.
  740. * @method getJan1
  741. * @param {Number} calendarYear The calendar year for which to retrieve January 1
  742. * @return {Date} January 1 of the calendar year specified.
  743. */
  744. getJan1 : function(calendarYear) {
  745. return this.getDate(calendarYear,0,1);
  746. },
  747. /**
  748. * Calculates the number of days the specified date is from January 1 of the specified calendar year.
  749. * Passing January 1 to this function would return an offset value of zero.
  750. * @method getDayOffset
  751. * @param {Date} date The JavaScript date for which to find the offset
  752. * @param {Number} calendarYear The calendar year to use for determining the offset
  753. * @return {Number} The number of days since January 1 of the given year
  754. */
  755. getDayOffset : function(date, calendarYear) {
  756. var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
  757. // Find the number of days the passed in date is away from the calendar year start
  758. var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
  759. return dayOffset;
  760. },
  761. /**
  762. * Calculates the week number for the given date. Can currently support standard
  763. * U.S. week numbers, based on Jan 1st defining the 1st week of the year, and
  764. * ISO8601 week numbers, based on Jan 4th defining the 1st week of the year.
  765. *
  766. * @method getWeekNumber
  767. * @param {Date} date The JavaScript date for which to find the week number
  768. * @param {Number} firstDayOfWeek The index of the first day of the week (0 = Sun, 1 = Mon ... 6 = Sat).
  769. * Defaults to 0
  770. * @param {Number} janDate The date in the first week of January which defines week one for the year
  771. * Defaults to the value of YAHOO.widget.DateMath.WEEK_ONE_JAN_DATE, which is 1 (Jan 1st).
  772. * For the U.S, this is normally Jan 1st. ISO8601 uses Jan 4th to define the first week of the year.
  773. *
  774. * @return {Number} The number of the week containing the given date.
  775. */
  776. getWeekNumber : function(date, firstDayOfWeek, janDate) {
  777. // Setup Defaults
  778. firstDayOfWeek = firstDayOfWeek || 0;
  779. janDate = janDate || this.WEEK_ONE_JAN_DATE;
  780. var targetDate = this.clearTime(date),
  781. startOfWeek,
  782. endOfWeek;
  783. if (targetDate.getDay() === firstDayOfWeek) {
  784. startOfWeek = targetDate;
  785. } else {
  786. startOfWeek = this.getFirstDayOfWeek(targetDate, firstDayOfWeek);
  787. }
  788. var startYear = startOfWeek.getFullYear(),
  789. startTime = startOfWeek.getTime();
  790. // DST shouldn't be a problem here, math is quicker than setDate();
  791. endOfWeek = new Date(startOfWeek.getTime() + 6*this.ONE_DAY_MS);
  792. var weekNum;
  793. if (startYear !== endOfWeek.getFullYear() && endOfWeek.getDate() >= janDate) {
  794. // If years don't match, endOfWeek is in Jan. and if the
  795. // week has WEEK_ONE_JAN_DATE in it, it's week one by definition.
  796. weekNum = 1;
  797. } else {
  798. // Get the 1st day of the 1st week, and
  799. // find how many days away we are from it.
  800. var weekOne = this.clearTime(this.getDate(startYear, 0, janDate)),
  801. weekOneDayOne = this.getFirstDayOfWeek(weekOne, firstDayOfWeek);
  802. // Round days to smoothen out 1 hr DST diff
  803. var daysDiff = Math.round((targetDate.getTime() - weekOneDayOne.getTime())/this.ONE_DAY_MS);
  804. // Calc. Full Weeks
  805. var rem = daysDiff % 7;
  806. var weeksDiff = (daysDiff - rem)/7;
  807. weekNum = weeksDiff + 1;
  808. }
  809. return weekNum;
  810. },
  811. /**
  812. * Get the first day of the week, for the give date.
  813. * @param {Date} dt The date in the week for which the first day is required.
  814. * @param {Number} startOfWeek The index for the first day of the week, 0 = Sun, 1 = Mon ... 6 = Sat (defaults to 0)
  815. * @return {Date} The first day of the week
  816. */
  817. getFirstDayOfWeek : function (dt, startOfWeek) {
  818. startOfWeek = startOfWeek || 0;
  819. var dayOfWeekIndex = dt.getDay(),
  820. dayOfWeek = (dayOfWeekIndex - startOfWeek + 7) % 7;
  821. return this.subtract(dt, this.DAY, dayOfWeek);
  822. },
  823. /**
  824. * Determines if a given week overlaps two different years.
  825. * @method isYearOverlapWeek
  826. * @param {Date} weekBeginDate The JavaScript Date representing the first day of the week.
  827. * @return {Boolean} true if the date overlaps two different years.
  828. */
  829. isYearOverlapWeek : function(weekBeginDate) {
  830. var overlaps = false;
  831. var nextWeek = this.add(weekBeginDate, this.DAY, 6);
  832. if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
  833. overlaps = true;
  834. }
  835. return overlaps;
  836. },
  837. /**
  838. * Determines if a given week overlaps two different months.
  839. * @method isMonthOverlapWeek
  840. * @param {Date} weekBeginDate The JavaScript Date representing the first day of the week.
  841. * @return {Boolean} true if the date overlaps two different months.
  842. */
  843. isMonthOverlapWeek : function(weekBeginDate) {
  844. var overlaps = false;
  845. var nextWeek = this.add(weekBeginDate, this.DAY, 6);
  846. if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
  847. overlaps = true;
  848. }
  849. return overlaps;
  850. },
  851. /**
  852. * Gets the first day of a month containing a given date.
  853. * @method findMonthStart
  854. * @param {Date} date The JavaScript Date used to calculate the month start
  855. * @return {Date} The JavaScript Date representing the first day of the month
  856. */
  857. findMonthStart : function(date) {
  858. var start = this.getDate(date.getFullYear(), date.getMonth(), 1);
  859. return start;
  860. },
  861. /**
  862. * Gets the last day of a month containing a given date.
  863. * @method findMonthEnd
  864. * @param {Date} date The JavaScript Date used to calculate the month end
  865. * @return {Date} The JavaScript Date representing the last day of the month
  866. */
  867. findMonthEnd : function(date) {
  868. var start = this.findMonthStart(date);
  869. var nextMonth = this.add(start, this.MONTH, 1);
  870. var end = this.subtract(nextMonth, this.DAY, 1);
  871. return end;
  872. },
  873. /**
  874. * Clears the time fields from a given date, effectively setting the time to 12 noon.
  875. * @method clearTime
  876. * @param {Date} date The JavaScript Date for which the time fields will be cleared
  877. * @return {Date} The JavaScript Date cleared of all time fields
  878. */
  879. clearTime : function(date) {
  880. date.setHours(12,0,0,0);
  881. return date;
  882. },
  883. /**
  884. * Returns a new JavaScript Date object, representing the given year, month and date. Time fields (hr, min, sec, ms) on the new Date object
  885. * are set to 0. The method allows Date instances to be created with the a year less than 100. "new Date(year, month, date)" implementations
  886. * set the year to 19xx if a year (xx) which is less than 100 is provided.
  887. * <p>
  888. * <em>NOTE:</em>Validation on argument values is not performed. It is the caller's responsibility to ensure
  889. * arguments are valid as per the ECMAScript-262 Date object specification for the new Date(year, month[, date]) constructor.
  890. * </p>
  891. * @method getDate
  892. * @param {Number} y Year.
  893. * @param {Number} m Month index from 0 (Jan) to 11 (Dec).
  894. * @param {Number} d (optional) Date from 1 to 31. If not provided, defaults to 1.
  895. * @return {Date} The JavaScript date object with year, month, date set as provided.
  896. */
  897. getDate : function(y, m, d) {
  898. var dt = null;
  899. if (YAHOO.lang.isUndefined(d)) {
  900. d = 1;
  901. }
  902. if (y >= 100) {
  903. dt = new Date(y, m, d);
  904. } else {
  905. dt = new Date();
  906. dt.setFullYear(y);
  907. dt.setMonth(m);
  908. dt.setDate(d);
  909. dt.setHours(0,0,0,0);
  910. }
  911. return dt;
  912. }
  913. };
  914. /**
  915. * The Calendar component is a UI control that enables users to choose one or more dates from a graphical calendar presented in a one-month or
  916. * multi-month interface. Calendars are generated entirely via script and can be navigated without any page refreshes.
  917. * @module calendar
  918. * @title Calendar
  919. * @namespace YAHOO.widget
  920. * @requires yahoo,dom,event
  921. */
  922. (function(){
  923. var Dom = YAHOO.util.Dom,
  924. Event = YAHOO.util.Event,
  925. Lang = YAHOO.lang,
  926. DateMath = YAHOO.widget.DateMath;
  927. /**
  928. * Calendar is the base class for the Calendar widget. In its most basic
  929. * implementation, it has the ability to render a calendar widget on the page
  930. * that can be manipulated to select a single date, move back and forth between
  931. * months and years.
  932. * <p>To construct the placeholder for the calendar widget, the code is as
  933. * follows:
  934. * <xmp>
  935. * <div id="calContainer"></div>
  936. * </xmp>
  937. * </p>
  938. * <p>
  939. * <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
  940. * The Calendar can be constructed by simply providing a container ID string,
  941. * or a reference to a container DIV HTMLElement (the element needs to exist
  942. * in the document).
  943. *
  944. * E.g.:
  945. * <xmp>
  946. * var c = new YAHOO.widget.Calendar("calContainer", configOptions);
  947. * </xmp>
  948. * or:
  949. * <xmp>
  950. * var containerDiv = YAHOO.util.Dom.get("calContainer");
  951. * var c = new YAHOO.widget.Calendar(containerDiv, configOptions);
  952. * </xmp>
  953. * </p>
  954. * <p>
  955. * If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
  956. * For example if an ID is not provided, and the container's ID is "calContainer", the Calendar's ID will be set to "calContainer_t".
  957. * </p>
  958. *
  959. * @namespace YAHOO.widget
  960. * @class Calendar
  961. * @constructor
  962. * @param {String} id optional The id of the table element that will represent the Calendar widget. As of 2.4.0, this argument is optional.
  963. * @param {String | HTMLElement} container The id of the container div element that will wrap the Calendar table, or a reference to a DIV element which exists in the document.
  964. * @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
  965. */
  966. function Calendar(id, containerId, config) {
  967. this.init.apply(this, arguments);
  968. }
  969. /**
  970. * The path to be used for images loaded for the Calendar
  971. * @property YAHOO.widget.Calendar.IMG_ROOT
  972. * @static
  973. * @deprecated You can now customize images by overriding the calclose, calnavleft and calnavright default CSS classes for the close icon, left arrow and right arrow respectively
  974. * @type String
  975. */
  976. Calendar.IMG_ROOT = null;
  977. /**
  978. * Type constant used for renderers to represent an individual date (M/D/Y)
  979. * @property YAHOO.widget.Calendar.DATE
  980. * @static
  981. * @final
  982. * @type String
  983. */
  984. Calendar.DATE = "D";
  985. /**
  986. * Type constant used for renderers to represent an individual date across any year (M/D)
  987. * @property YAHOO.widget.Calendar.MONTH_DAY
  988. * @static
  989. * @final
  990. * @type String
  991. */
  992. Calendar.MONTH_DAY = "MD";
  993. /**
  994. * Type constant used for renderers to represent a weekday
  995. * @property YAHOO.widget.Calendar.WEEKDAY
  996. * @static
  997. * @final
  998. * @type String
  999. */
  1000. Calendar.WEEKDAY = "WD";
  1001. /**
  1002. * Type constant used for renderers to represent a range of individual dates (M/D/Y-M/D/Y)
  1003. * @property YAHOO.widget.Calendar.RANGE
  1004. * @static
  1005. * @final
  1006. * @type String
  1007. */
  1008. Calendar.RANGE = "R";
  1009. /**
  1010. * Type constant used for renderers to represent a month across any year
  1011. * @property YAHOO.widget.Calendar.MONTH
  1012. * @static
  1013. * @final
  1014. * @type String
  1015. */
  1016. Calendar.MONTH = "M";
  1017. /**
  1018. * Constant that represents the total number of date cells that are displayed in a given month
  1019. * @property YAHOO.widget.Calendar.DISPLAY_DAYS
  1020. * @static
  1021. * @final
  1022. * @type Number
  1023. */
  1024. Calendar.DISPLAY_DAYS = 42;
  1025. /**
  1026. * Constant used for halting the execution of the remainder of the render stack
  1027. * @property YAHOO.widget.Calendar.STOP_RENDER
  1028. * @static
  1029. * @final
  1030. * @type String
  1031. */
  1032. Calendar.STOP_RENDER = "S";
  1033. /**
  1034. * Constant used to represent short date field string formats (e.g. Tu or Feb)
  1035. * @property YAHOO.widget.Calendar.SHORT
  1036. * @static
  1037. * @final
  1038. * @type String
  1039. */
  1040. Calendar.SHORT = "short";
  1041. /**
  1042. * Constant used to represent long date field string formats (e.g. Monday or February)
  1043. * @property YAHOO.widget.Calendar.LONG
  1044. * @static
  1045. * @final
  1046. * @type String
  1047. */
  1048. Calendar.LONG = "long";
  1049. /**
  1050. * Constant used to represent medium date field string formats (e.g. Mon)
  1051. * @property YAHOO.widget.Calendar.MEDIUM
  1052. * @static
  1053. * @final
  1054. * @type String
  1055. */
  1056. Calendar.MEDIUM = "medium";
  1057. /**
  1058. * Constant used to represent single character date field string formats (e.g. M, T, W)
  1059. * @property YAHOO.widget.Calendar.ONE_CHAR
  1060. * @static
  1061. * @final
  1062. * @type String
  1063. */
  1064. Calendar.ONE_CHAR = "1char";
  1065. /**
  1066. * The set of default Config property keys and values for the Calendar
  1067. * @property YAHOO.widget.Calendar._DEFAULT_CONFIG
  1068. * @final
  1069. * @static
  1070. * @private
  1071. * @type Object
  1072. */
  1073. Calendar._DEFAULT_CONFIG = {
  1074. // Default values for pagedate and selected are not class level constants - they are set during instance creation
  1075. PAGEDATE : {key:"pagedate", value:null},
  1076. SELECTED : {key:"selected", value:null},
  1077. TITLE : {key:"title", value:""},
  1078. CLOSE : {key:"close", value:false},
  1079. IFRAME : {key:"iframe", value:(YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) ? true : false},
  1080. MINDATE : {key:"mindate", value:null},
  1081. MAXDATE : {key:"maxdate", value:null},
  1082. MULTI_SELECT : {key:"multi_select", value:false},
  1083. START_WEEKDAY : {key:"start_weekday", value:0},
  1084. SHOW_WEEKDAYS : {key:"show_weekdays", value:true},
  1085. SHOW_WEEK_HEADER : {key:"show_week_header", value:false},
  1086. SHOW_WEEK_FOOTER : {key:"show_week_footer", value:false},
  1087. HIDE_BLANK_WEEKS : {key:"hide_blank_weeks", value:false},
  1088. NAV_ARROW_LEFT: {key:"nav_arrow_left", value:null} ,
  1089. NAV_ARROW_RIGHT : {key:"nav_arrow_right", value:null} ,
  1090. MONTHS_SHORT : {key:"months_short", value:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]},
  1091. MONTHS_LONG: {key:"months_long", value:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]},
  1092. WEEKDAYS_1CHAR: {key:"weekdays_1char", value:["S", "M", "T", "W", "T", "F", "S"]},
  1093. WEEKDAYS_SHORT: {key:"weekdays_short", value:["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]},
  1094. WEEKDAYS_MEDIUM: {key:"weekdays_medium", value:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]},
  1095. WEEKDAYS_LONG: {key:"weekdays_long", value:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]},
  1096. LOCALE_MONTHS:{key:"locale_months", value:"long"},
  1097. LOCALE_WEEKDAYS:{key:"locale_weekdays", value:"short"},
  1098. DATE_DELIMITER:{key:"date_delimiter", value:","},
  1099. DATE_FIELD_DELIMITER:{key:"date_field_delimiter", value:"/"},
  1100. DATE_RANGE_DELIMITER:{key:"date_range_delimiter", value:"-"},
  1101. MY_MONTH_POSITION:{key:"my_month_position", value:1},
  1102. MY_YEAR_POSITION:{key:"my_year_position", value:2},
  1103. MD_MONTH_POSITION:{key:"md_month_position", value:1},
  1104. MD_DAY_POSITION:{key:"md_day_position", value:2},
  1105. MDY_MONTH_POSITION:{key:"mdy_month_position", value:1},
  1106. MDY_DAY_POSITION:{key:"mdy_day_position", value:2},
  1107. MDY_YEAR_POSITION:{key:"mdy_year_position", value:3},
  1108. MY_LABEL_MONTH_POSITION:{key:"my_label_month_position", value:1},
  1109. MY_LABEL_YEAR_POSITION:{key:"my_label_year_position", value:2},
  1110. MY_LABEL_MONTH_SUFFIX:{key:"my_label_month_suffix", value:" "},
  1111. MY_LABEL_YEAR_SUFFIX:{key:"my_label_year_suffix", value:""},
  1112. NAV: {key:"navigator", value: null},
  1113. STRINGS : {
  1114. key:"strings",
  1115. value: {
  1116. previousMonth : "Previous Month",
  1117. nextMonth : "Next Month",
  1118. close: "Close"
  1119. },
  1120. supercedes : ["close", "title"]
  1121. }
  1122. };
  1123. var DEF_CFG = Calendar._DEFAULT_CONFIG;
  1124. /**
  1125. * The set of Custom Event types supported by the Calendar
  1126. * @property YAHOO.widget.Calendar._EVENT_TYPES
  1127. * @final
  1128. * @static
  1129. * @private
  1130. * @type Object
  1131. */
  1132. Calendar._EVENT_TYPES = {
  1133. BEFORE_SELECT : "beforeSelect",
  1134. SELECT : "select",
  1135. BEFORE_DESELECT : "beforeDeselect",
  1136. DESELECT : "deselect",
  1137. CHANGE_PAGE : "changePage",
  1138. BEFORE_RENDER : "beforeRender",
  1139. RENDER : "render",
  1140. BEFORE_DESTROY : "beforeDestroy",
  1141. DESTROY : "destroy",
  1142. RESET : "reset",
  1143. CLEAR : "clear",
  1144. BEFORE_HIDE : "beforeHide",
  1145. HIDE : "hide",
  1146. BEFORE_SHOW : "beforeShow",
  1147. SHOW : "show",
  1148. BEFORE_HIDE_NAV : "beforeHideNav",
  1149. HIDE_NAV : "hideNav",
  1150. BEFORE_SHOW_NAV : "beforeShowNav",
  1151. SHOW_NAV : "showNav",
  1152. BEFORE_RENDER_NAV : "beforeRenderNav",
  1153. RENDER_NAV : "renderNav"
  1154. };
  1155. /**
  1156. * The set of default style constants for the Calendar
  1157. * @property YAHOO.widget.Calendar._STYLES
  1158. * @final
  1159. * @static
  1160. * @private
  1161. * @type Object
  1162. */
  1163. Calendar._STYLES = {
  1164. CSS_ROW_HEADER: "calrowhead",
  1165. CSS_ROW_FOOTER: "calrowfoot",
  1166. CSS_CELL : "calcell",
  1167. CSS_CELL_SELECTOR : "selector",
  1168. CSS_CELL_SELECTED : "selected",
  1169. CSS_CELL_SELECTABLE : "selectable",
  1170. CSS_CELL_RESTRICTED : "restricted",
  1171. CSS_CELL_TODAY : "today",
  1172. CSS_CELL_OOM : "oom",
  1173. CSS_CELL_OOB : "previous",
  1174. CSS_HEADER : "calheader",
  1175. CSS_HEADER_TEXT : "calhead",
  1176. CSS_BODY : "calbody",
  1177. CSS_WEEKDAY_CELL : "calweekdaycell",
  1178. CSS_WEEKDAY_ROW : "calweekdayrow",
  1179. CSS_FOOTER : "calfoot",
  1180. CSS_CALENDAR : "yui-calendar",
  1181. CSS_SINGLE : "single",
  1182. CSS_CONTAINER : "yui-calcontainer",
  1183. CSS_NAV_LEFT : "calnavleft",
  1184. CSS_NAV_RIGHT : "calnavright",
  1185. CSS_NAV : "calnav",
  1186. CSS_CLOSE : "calclose",
  1187. CSS_CELL_TOP : "calcelltop",
  1188. CSS_CELL_LEFT : "calcellleft",
  1189. CSS_CELL_RIGHT : "calcellright",
  1190. CSS_CELL_BOTTOM : "calcellbottom",
  1191. CSS_CELL_HOVER : "calcellhover",
  1192. CSS_CELL_HIGHLIGHT1 : "highlight1",
  1193. CSS_CELL_HIGHLIGHT2 : "highlight2",
  1194. CSS_CELL_HIGHLIGHT3 : "highlight3",
  1195. CSS_CELL_HIGHLIGHT4 : "highlight4"
  1196. };
  1197. Calendar.prototype = {
  1198. /**
  1199. * The configuration object used to set up the calendars various locale and style options.
  1200. * @property Config
  1201. * @private
  1202. * @deprecated Configuration properties should be set by calling Calendar.cfg.setProperty.
  1203. * @type Object
  1204. */
  1205. Config : null,
  1206. /**
  1207. * The parent CalendarGroup, only to be set explicitly by the parent group
  1208. * @property parent
  1209. * @type CalendarGroup
  1210. */
  1211. parent : null,
  1212. /**
  1213. * The index of this item in the parent group
  1214. * @property index
  1215. * @type Number
  1216. */
  1217. index : -1,
  1218. /**
  1219. * The collection of calendar table cells
  1220. * @property cells
  1221. * @type HTMLTableCellElement[]
  1222. */
  1223. cells : null,
  1224. /**
  1225. * The collection of calendar cell dates that is parallel to the cells collection. The array contains dates field arrays in the format of [YYYY, M, D].
  1226. * @property cellDates
  1227. * @type Array[](Number[])
  1228. */
  1229. cellDates : null,
  1230. /**
  1231. * The id that uniquely identifies this Calendar.
  1232. * @property id
  1233. * @type String
  1234. */
  1235. id : null,
  1236. /**
  1237. * The unique id associated with the Calendar's container
  1238. * @property containerId
  1239. * @type String
  1240. */
  1241. containerId: null,
  1242. /**
  1243. * The DOM element reference that points to this calendar's container element. The calendar will be inserted into this element when the shell is rendered.
  1244. * @property oDomContainer
  1245. * @type HTMLElement
  1246. */
  1247. oDomContainer : null,
  1248. /**
  1249. * A Date object representing today's date.
  1250. * @property today
  1251. * @type Date
  1252. */
  1253. today : null,
  1254. /**
  1255. * The list of render functions, along with required parameters, used to render cells.
  1256. * @property renderStack
  1257. * @type Array[]
  1258. */
  1259. renderStack : null,
  1260. /**
  1261. * A copy of the initial render functions created before rendering.
  1262. * @property _renderStack
  1263. * @private
  1264. * @type Array
  1265. */
  1266. _renderStack : null,
  1267. /**
  1268. * A reference to the CalendarNavigator instance created for this Calendar.
  1269. * Will be null if the "navigator" configuration property has not been set
  1270. * @property oNavigator
  1271. * @type CalendarNavigator
  1272. */
  1273. oNavigator : null,
  1274. /**
  1275. * The private list of initially selected dates.
  1276. * @property _selectedDates
  1277. * @private
  1278. * @type Array
  1279. */
  1280. _selectedDates : null,
  1281. /**
  1282. * A map of DOM event handlers to attach to cells associated with specific CSS class names
  1283. * @property domEventMap
  1284. * @type Object
  1285. */
  1286. domEventMap : null,
  1287. /**
  1288. * Protected helper used to parse Calendar constructor/init arguments.
  1289. *
  1290. * As of 2.4.0, Calendar supports a simpler constructor
  1291. * signature. This method reconciles arguments
  1292. * received in the pre 2.4.0 and 2.4.0 formats.
  1293. *
  1294. * @protected
  1295. * @method _parseArgs
  1296. * @param {Array} Function "arguments" array
  1297. * @return {Object} Object with id, container, config properties containing
  1298. * the reconciled argument values.
  1299. **/
  1300. _parseArgs : function(args) {
  1301. /*
  1302. 2.4.0 Constructors signatures
  1303. new Calendar(String)
  1304. new Calendar(HTMLElement)
  1305. new Calendar(String, ConfigObject)
  1306. new Calendar(HTMLElement, ConfigObject)
  1307. Pre 2.4.0 Constructor signatures
  1308. new Calendar(String, String)
  1309. new Calendar(String, HTMLElement)
  1310. new Calendar(String, String, ConfigObject)
  1311. new Calendar(String, HTMLElement, ConfigObject)
  1312. */
  1313. var nArgs = {id:null, container:null, config:null};
  1314. if (args && args.length && args.length > 0) {
  1315. switch (args.length) {
  1316. case 1:
  1317. nArgs.id = null;
  1318. nArgs.container = args[0];
  1319. nArgs.config = null;
  1320. break;
  1321. case 2:
  1322. if (Lang.isObject(args[1]) && !args[1].tagName && !(args[1] instanceof String)) {
  1323. nArgs.id = null;
  1324. nArgs.container = args[0];
  1325. nArgs.config = args[1];
  1326. } else {
  1327. nArgs.id = args[0];
  1328. nArgs.container = args[1];
  1329. nArgs.config = null;
  1330. }
  1331. break;
  1332. default: // 3+
  1333. nArgs.id = args[0];
  1334. nArgs.container = args[1];
  1335. nArgs.config = args[2];
  1336. break;
  1337. }
  1338. } else {
  1339. }
  1340. return nArgs;
  1341. },
  1342. /**
  1343. * Initializes the Calendar widget.
  1344. * @method init
  1345. *
  1346. * @param {String} id optional The id of the table element that will represent the Calendar widget. As of 2.4.0, this argument is optional.
  1347. * @param {String | HTMLElement} container The id of the container div element that will wrap the Calendar table, or a reference to a DIV element which exists in the document.
  1348. * @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
  1349. */
  1350. init : function(id, container, config) {
  1351. // Normalize 2.4.0, pre 2.4.0 args
  1352. var nArgs = this._parseArgs(arguments);
  1353. id = nArgs.id;
  1354. container = nArgs.container;
  1355. config = nArgs.config;
  1356. this.oDomContainer = Dom.get(container);
  1357. if (!this.oDomContainer.id) {
  1358. this.oDomContainer.id = Dom.generateId();
  1359. }
  1360. if (!id) {
  1361. id = this.oDomContainer.id + "_t";
  1362. }
  1363. this.id = id;
  1364. this.containerId = this.oDomContainer.id;
  1365. this.initEvents();
  1366. this.today = new Date();
  1367. DateMath.clearTime(this.today);
  1368. /**
  1369. * The Config object used to hold the configuration variables for the Calendar
  1370. * @property cfg
  1371. * @type YAHOO.util.Config
  1372. */
  1373. this.cfg = new YAHOO.util.Config(this);
  1374. /**
  1375. * The local object which contains the Calendar's options
  1376. * @property Options
  1377. * @type Object
  1378. */
  1379. this.Options = {};
  1380. /**
  1381. * The local object which contains the Calendar's locale settings
  1382. * @property Locale
  1383. * @type Object
  1384. */
  1385. this.Locale = {};
  1386. this.initStyles();
  1387. Dom.addClass(this.oDomContainer, this.Style.CSS_CONTAINER);
  1388. Dom.addClass(this.oDomContainer, this.Style.CSS_SINGLE);
  1389. this.cellDates = [];
  1390. this.cells = [];
  1391. this.renderStack = [];
  1392. this._renderStack = [];
  1393. this.setupConfig();
  1394. if (config) {
  1395. this.cfg.applyConfig(config, true);
  1396. }
  1397. this.cfg.fireQueue();
  1398. },
  1399. /**
  1400. * Default Config listener for the iframe property. If the iframe config property is set to true,
  1401. * renders the built-in IFRAME shim if the container is relatively or absolutely positioned.
  1402. *
  1403. * @method configIframe
  1404. */
  1405. configIframe : function(type, args, obj) {
  1406. var useIframe = args[0];
  1407. if (!this.parent) {
  1408. if (Dom.inDocument(this.oDomContainer)) {
  1409. if (useIframe) {
  1410. var pos = Dom.getStyle(this.oDomContainer, "position");
  1411. if (pos == "absolute" || pos == "relative") {
  1412. if (!Dom.inDocument(this.iframe)) {
  1413. this.iframe = document.createElement("iframe");
  1414. this.iframe.src = "javascript:false;";
  1415. Dom.setStyle(this.iframe, "opacity", "0");
  1416. if (YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) {
  1417. Dom.addClass(this.iframe, "fixedsize");
  1418. }
  1419. this.oDomContainer.insertBefore(this.iframe, this.oDomContainer.firstChild);
  1420. }
  1421. }
  1422. } else {
  1423. if (this.iframe) {
  1424. if (this.iframe.parentNode) {
  1425. this.iframe.parentNode.removeChild(this.iframe);
  1426. }
  1427. this.iframe = null;
  1428. }
  1429. }
  1430. }
  1431. }
  1432. },
  1433. /**
  1434. * Default handler for the "title" property
  1435. * @method configTitle
  1436. */
  1437. configTitle : function(type, args, obj) {
  1438. var title = args[0];
  1439. // "" disables title bar
  1440. if (title) {
  1441. this.createTitleBar(title);
  1442. } else {
  1443. var close = this.cfg.getProperty(DEF_CFG.CLOSE.key);
  1444. if (!close) {
  1445. this.removeTitleBar();
  1446. } else {
  1447. this.createTitleBar("&#160;");
  1448. }
  1449. }
  1450. },
  1451. /**
  1452. * Default handler for the "close" property
  1453. * @method configClose
  1454. */
  1455. configClose : function(type, args, obj) {
  1456. var close = args[0],
  1457. title = this.cfg.getProperty(DEF_CFG.TITLE.key);
  1458. if (close) {
  1459. if (!title) {
  1460. this.createTitleBar("&#160;");
  1461. }
  1462. this.createCloseButton();
  1463. } else {
  1464. this.removeCloseButton();
  1465. if (!title) {
  1466. this.removeTitleBar();
  1467. }
  1468. }
  1469. },
  1470. /**
  1471. * Initializes Calendar's built-in CustomEvents
  1472. * @method initEvents
  1473. */
  1474. initEvents : function() {
  1475. var defEvents = Calendar._EVENT_TYPES,
  1476. CE = YAHOO.util.CustomEvent,
  1477. cal = this; // To help with minification
  1478. /**
  1479. * Fired before a date selection is made
  1480. * @event beforeSelectEvent
  1481. */
  1482. cal.beforeSelectEvent = new CE(defEvents.BEFORE_SELECT);
  1483. /**
  1484. * Fired when a date selection is made
  1485. * @event selectEvent
  1486. * @param {Array} Array of Date field arrays in the format [YYYY, MM, DD].
  1487. */
  1488. cal.selectEvent = new CE(defEvents.SELECT);
  1489. /**
  1490. * Fired before a date or set of dates is deselected
  1491. * @event beforeDeselectEvent
  1492. */
  1493. cal.beforeDeselectEvent = new CE(defEvents.BEFORE_DESELECT);
  1494. /**
  1495. * Fired when a date or set of dates is deselected
  1496. * @event deselectEvent
  1497. * @param {Array} Array of Date field arrays in the format [YYYY, MM, DD].
  1498. */
  1499. cal.deselectEvent = new CE(defEvents.DESELECT);
  1500. /**
  1501. * Fired when the Calendar page is changed
  1502. * @event changePageEvent
  1503. */
  1504. cal.changePageEvent = new CE(defEvents.CHANGE_PAGE);
  1505. /**
  1506. * Fired before the Calendar is rendered
  1507. * @event beforeRenderEvent
  1508. */
  1509. cal.beforeRenderEvent = new CE(defEvents.BEFORE_RENDER);
  1510. /**
  1511. * Fired when the Calendar is rendered
  1512. * @event renderEvent
  1513. */
  1514. cal.renderEvent = new CE(defEvents.RENDER);
  1515. /**
  1516. * Fired just before the Calendar is to be destroyed
  1517. * @event beforeDestroyEvent
  1518. */
  1519. cal.beforeDestroyEvent = new CE(defEvents.BEFORE_DESTROY);
  1520. /**
  1521. * Fired after the Calendar is destroyed. This event should be used
  1522. * for notification only. When this event is fired, important Calendar instance
  1523. * properties, dom references and event listeners have already been
  1524. * removed/dereferenced, and hence the Calendar instance is not in a usable
  1525. * state.
  1526. *
  1527. * @event destroyEvent
  1528. */
  1529. cal.destroyEvent = new CE(defEvents.DESTROY);
  1530. /**
  1531. * Fired when the Calendar is reset
  1532. * @event resetEvent
  1533. */
  1534. cal.resetEvent = new CE(defEvents.RESET);
  1535. /**
  1536. * Fired when the Calendar is cleared
  1537. * @event clearEvent
  1538. */
  1539. cal.clearEvent = new CE(defEvents.CLEAR);
  1540. /**
  1541. * Fired just before the Calendar is to be shown
  1542. * @event beforeShowEvent
  1543. */
  1544. cal.beforeShowEvent = new CE(defEvents.BEFORE_SHOW);
  1545. /**
  1546. * Fired after the Calendar is shown
  1547. * @event showEvent
  1548. */
  1549. cal.showEvent = new CE(defEvents.SHOW);
  1550. /**
  1551. * Fired just before the Calendar is to be hidden
  1552. * @event beforeHideEvent
  1553. */
  1554. cal.beforeHideEvent = new CE(defEvents.BEFORE_HIDE);
  1555. /**
  1556. * Fired after the Calendar is hidden
  1557. * @event hideEvent
  1558. */
  1559. cal.hideEvent = new CE(defEvents.HIDE);
  1560. /**
  1561. * Fired just before the CalendarNavigator is to be shown
  1562. * @event beforeShowNavEvent
  1563. */
  1564. cal.beforeShowNavEvent = new CE(defEvents.BEFORE_SHOW_NAV);
  1565. /**
  1566. * Fired after the CalendarNavigator is shown
  1567. * @event showNavEvent
  1568. */
  1569. cal.showNavEvent = new CE(defEvents.SHOW_NAV);
  1570. /**
  1571. * Fired just before the CalendarNavigator is to be hidden
  1572. * @event beforeHideNavEvent
  1573. */
  1574. cal.beforeHideNavEvent = new CE(defEvents.BEFORE_HIDE_NAV);
  1575. /**
  1576. * Fired after the CalendarNavigator is hidden
  1577. * @event hideNavEvent
  1578. */
  1579. cal.hideNavEvent = new CE(defEvents.HIDE_NAV);
  1580. /**
  1581. * Fired just before the CalendarNavigator is to be rendered
  1582. * @event beforeRenderNavEvent
  1583. */
  1584. cal.beforeRenderNavEvent = new CE(defEvents.BEFORE_RENDER_NAV);
  1585. /**
  1586. * Fired after the CalendarNavigator is rendered
  1587. * @event renderNavEvent
  1588. */
  1589. cal.renderNavEvent = new CE(defEvents.RENDER_NAV);
  1590. cal.beforeSelectEvent.subscribe(cal.onBeforeSelect, this, true);
  1591. cal.selectEvent.subscribe(cal.onSelect, this, true);
  1592. cal.beforeDeselectEvent.subscribe(cal.onBeforeDeselect, this, true);
  1593. cal.deselectEvent.subscribe(cal.onDeselect, this, true);
  1594. cal.changePageEvent.subscribe(cal.onChangePage, this, true);
  1595. cal.renderEvent.subscribe(cal.onRender, this, true);
  1596. cal.resetEvent.subscribe(cal.onReset, this, true);
  1597. cal.clearEvent.subscribe(cal.onClear, this, true);
  1598. },
  1599. /**
  1600. * The default event handler for clicks on the "Previous Month" navigation UI
  1601. *
  1602. * @method doPreviousMonthNav
  1603. * @param {DOMEvent} e The DOM event
  1604. * @param {Calendar} cal A reference to the calendar
  1605. */
  1606. doPreviousMonthNav : function(e, cal) {
  1607. Event.preventDefault(e);
  1608. // previousMonth invoked in a timeout, to allow
  1609. // event to bubble up, with correct target. Calling
  1610. // previousMonth, will call render which will remove
  1611. // HTML which generated the event, resulting in an
  1612. // invalid event target in certain browsers.
  1613. setTimeout(function() {
  1614. cal.previousMonth();
  1615. var navs = Dom.getElementsByClassName(cal.Style.CSS_NAV_LEFT, "a", cal.oDomContainer);
  1616. if (navs && navs[0]) {
  1617. try {
  1618. navs[0].focus();
  1619. } catch (e) {
  1620. // ignore
  1621. }
  1622. }
  1623. }, 0);
  1624. },
  1625. /**
  1626. * The default event handler for clicks on the "Next Month" navigation UI
  1627. *
  1628. * @method doNextMonthNav
  1629. * @param {DOMEvent} e The DOM event
  1630. * @param {Calendar} cal A reference to the calendar
  1631. */
  1632. doNextMonthNav : function(e, cal) {
  1633. Event.preventDefault(e);
  1634. setTimeout(function() {
  1635. cal.nextMonth();
  1636. var navs = Dom.getElementsByClassName(cal.Style.CSS_NAV_RIGHT, "a", cal.oDomContainer);
  1637. if (navs && navs[0]) {
  1638. try {
  1639. navs[0].focus();
  1640. } catch (e) {
  1641. // ignore
  1642. }
  1643. }
  1644. }, 0);
  1645. },
  1646. /**
  1647. * The default event handler for date cell selection. Currently attached to
  1648. * the Calendar's bounding box, referenced by it's <a href="#property_oDomContainer">oDomContainer</a> property.
  1649. *
  1650. * @method doSelectCell
  1651. * @param {DOMEvent} e The DOM event
  1652. * @param {Calendar} cal A reference to the calendar
  1653. */
  1654. doSelectCell : function(e, cal) {
  1655. var cell, d, date, index;
  1656. var target = Event.getTarget(e),
  1657. tagName = target.tagName.toLowerCase(),
  1658. defSelector = false;
  1659. while (tagName != "td" && !Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
  1660. if (!defSelector && tagName == "a" && Dom.hasClass(target, cal.Style.CSS_CELL_SELECTOR)) {
  1661. defSelector = true;
  1662. }
  1663. target = target.parentNode;
  1664. tagName = target.tagName.toLowerCase();
  1665. if (target == this.oDomContainer || tagName == "html") {
  1666. return;
  1667. }
  1668. }
  1669. if (defSelector) {
  1670. // Stop link href navigation for default renderer
  1671. Event.preventDefault(e);
  1672. }
  1673. cell = target;
  1674. if (Dom.hasClass(cell, cal.Style.CSS_CELL_SELECTABLE)) {
  1675. index = cal.getIndexFromId(cell.id);
  1676. if (index > -1) {
  1677. d = cal.cellDates[index];
  1678. if (d) {
  1679. date = DateMath.getDate(d[0],d[1]-1,d[2]);
  1680. var link;
  1681. if (cal.Options.MULTI_SELECT) {
  1682. link = cell.getElementsByTagName("a")[0];
  1683. if (link) {
  1684. link.blur();
  1685. }
  1686. var cellDate = cal.cellDates[index];
  1687. var cellDateIndex = cal._indexOfSelectedFieldArray(cellDate);
  1688. if (cellDateIndex > -1) {
  1689. cal.deselectCell(index);
  1690. } else {
  1691. cal.selectCell(index);
  1692. }
  1693. } else {
  1694. link = cell.getElementsByTagName("a")[0];
  1695. if (link) {
  1696. link.blur();
  1697. }
  1698. cal.selectCell(index);
  1699. }
  1700. }
  1701. }
  1702. }
  1703. },
  1704. /**
  1705. * The event that is executed when the user hovers over a cell
  1706. * @method doCellMouseOver
  1707. * @param {DOMEvent} e The event
  1708. * @param {Calendar} cal A reference to the calendar passed by the Event utility
  1709. */
  1710. doCellMouseOver : function(e, cal) {
  1711. var target;
  1712. if (e) {
  1713. target = Event.getTarget(e);
  1714. } else {
  1715. target = this;
  1716. }
  1717. while (target.tagName && target.tagName.toLowerCase() != "td") {
  1718. target = target.parentNode;
  1719. if (!target.tagName || target.tagName.toLowerCase() == "html") {
  1720. return;
  1721. }
  1722. }
  1723. if (Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
  1724. Dom.addClass(target, cal.Style.CSS_CELL_HOVER);
  1725. }
  1726. },
  1727. /**
  1728. * The event that is executed when the user moves the mouse out of a cell
  1729. * @method doCellMouseOut
  1730. * @param {DOMEvent} e The event
  1731. * @param {Calendar} cal A reference to the calendar passed by the Event utility
  1732. */
  1733. doCellMouseOut : function(e, cal) {
  1734. var target;
  1735. if (e) {
  1736. target = Event.getTarget(e);
  1737. } else {
  1738. target = this;
  1739. }
  1740. while (target.tagName && target.tagName.toLowerCase() != "td") {
  1741. target = target.parentNode;
  1742. if (!target.tagName || target.tagName.toLowerCase() == "html") {
  1743. return;
  1744. }
  1745. }
  1746. if (Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
  1747. Dom.removeClass(target, cal.Style.CSS_CELL_HOVER);
  1748. }
  1749. },
  1750. setupConfig : function() {
  1751. var cfg = this.cfg;
  1752. /**
  1753. * The month/year representing the current visible Calendar date (mm/yyyy)
  1754. * @config pagedate
  1755. * @type String | Date
  1756. * @default today's date
  1757. */
  1758. cfg.addProperty(DEF_CFG.PAGEDATE.key, { value:new Date(), handler:this.configPageDate } );
  1759. /**
  1760. * The date or range of dates representing the current Calendar selection
  1761. * @config selected
  1762. * @type String
  1763. * @default []
  1764. */
  1765. cfg.addProperty(DEF_CFG.SELECTED.key, { value:[], handler:this.configSelected } );
  1766. /**
  1767. * The title to display above the Calendar's month header
  1768. * @config title
  1769. * @type String
  1770. * @default ""
  1771. */
  1772. cfg.addProperty(DEF_CFG.TITLE.key, { value:DEF_CFG.TITLE.value, handler:this.configTitle } );
  1773. /**
  1774. * Whether or not a close button should be displayed for this Calendar
  1775. * @config close
  1776. * @type Boolean
  1777. * @default false
  1778. */
  1779. cfg.addProperty(DEF_CFG.CLOSE.key, { value:DEF_CFG.CLOSE.value, handler:this.configClose } );
  1780. /**
  1781. * Whether or not an iframe shim should be placed under the Calendar to prevent select boxes from bleeding through in Internet Explorer 6 and below.
  1782. * This property is enabled by default for IE6 and below. It is disabled by default for other browsers for performance reasons, but can be
  1783. * enabled if required.
  1784. *
  1785. * @config iframe
  1786. * @type Boolean
  1787. * @default true for IE6 and below, false for all other browsers
  1788. */
  1789. cfg.addProperty(DEF_CFG.IFRAME.key, { value:DEF_CFG.IFRAME.value, handler:this.configIframe, validator:cfg.checkBoolean } );
  1790. /**
  1791. * The minimum selectable date in the current Calendar (mm/dd/yyyy)
  1792. * @config mindate
  1793. * @type String | Date
  1794. * @default null
  1795. */
  1796. cfg.addProperty(DEF_CFG.MINDATE.key, { value:DEF_CFG.MINDATE.value, handler:this.configMinDate } );
  1797. /**
  1798. * The maximum selectable date in the current Calendar (mm/dd/yyyy)
  1799. * @config maxdate
  1800. * @type String | Date
  1801. * @default null
  1802. */
  1803. cfg.addProperty(DEF_CFG.MAXDATE.key, { value:DEF_CFG.MAXDATE.value, handler:this.configMaxDate } );
  1804. // Options properties
  1805. /**
  1806. * True if the Calendar should allow multiple selections. False by default.
  1807. * @config MULTI_SELECT
  1808. * @type Boolean
  1809. * @default false
  1810. */
  1811. cfg.addProperty(DEF_CFG.MULTI_SELECT.key, { value:DEF_CFG.MULTI_SELECT.value, handler:this.configOptions, validator:cfg.checkBoolean } );
  1812. /**
  1813. * The weekday the week begins on. Default is 0 (Sunday = 0, Monday = 1 ... Saturday = 6).
  1814. * @config START_WEEKDAY
  1815. * @type number
  1816. * @default 0
  1817. */
  1818. cfg.addProperty(DEF_CFG.START_WEEKDAY.key, { value:DEF_CFG.START_WEEKDAY.value, handler:this.configOptions, validator:cfg.checkNumber } );
  1819. /**
  1820. * True if the Calendar should show weekday labels. True by default.
  1821. * @config SHOW_WEEKDAYS
  1822. * @type Boolean
  1823. * @default true
  1824. */
  1825. cfg.addProperty(DEF_CFG.SHOW_WEEKDAYS.key, { value:DEF_CFG.SHOW_WEEKDAYS.value, handler:this.configOptions, validator:cfg.checkBoolean } );
  1826. /**
  1827. * True if the Calendar should show week row headers. False by default.
  1828. * @config SHOW_WEEK_HEADER
  1829. * @type Boolean
  1830. * @default false
  1831. */
  1832. cfg.addProperty(DEF_CFG.SHOW_WEEK_HEADER.key, { value:DEF_CFG.SHOW_WEEK_HEADER.value, handler:this.configOptions, validator:cfg.checkBoolean } );
  1833. /**
  1834. * True if the Calendar should show week row footers. False by default.
  1835. * @config SHOW_WEEK_FOOTER
  1836. * @type Boolean
  1837. * @default false
  1838. */
  1839. cfg.addProperty(DEF_CFG.SHOW_WEEK_FOOTER.key,{ value:DEF_CFG.SHOW_WEEK_FOOTER.value, handler:this.configOptions, validator:cfg.checkBoolean } );
  1840. /**
  1841. * True if the Calendar should suppress weeks that are not a part of the current month. False by default.
  1842. * @config HIDE_BLANK_WEEKS
  1843. * @type Boolean
  1844. * @default false
  1845. */
  1846. cfg.addProperty(DEF_CFG.HIDE_BLANK_WEEKS.key, { value:DEF_CFG.HIDE_BLANK_WEEKS.value, handler:this.configOptions, validator:cfg.checkBoolean } );
  1847. /**
  1848. * The image that should be used for the left navigation arrow.
  1849. * @config NAV_ARROW_LEFT
  1850. * @type String
  1851. * @deprecated You can customize the image by overriding the default CSS class for the left arrow - "calnavleft"
  1852. * @default null
  1853. */
  1854. cfg.addProperty(DEF_CFG.NAV_ARROW_LEFT.key, { value:DEF_CFG.NAV_ARROW_LEFT.value, handler:this.configOptions } );
  1855. /**
  1856. * The image that should be used for the right navigation arrow.
  1857. * @config NAV_ARROW_RIGHT
  1858. * @type String
  1859. * @deprecated You can customize the image by overriding the default CSS class for the right arrow - "calnavright"
  1860. * @default null
  1861. */
  1862. cfg.addProperty(DEF_CFG.NAV_ARROW_RIGHT.key, { value:DEF_CFG.NAV_ARROW_RIGHT.value, handler:this.configOptions } );
  1863. // Locale properties
  1864. /**
  1865. * The short month labels for the current locale.
  1866. * @config MONTHS_SHORT
  1867. * @type String[]
  1868. * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  1869. */
  1870. cfg.addProperty(DEF_CFG.MONTHS_SHORT.key, { value:DEF_CFG.MONTHS_SHORT.value, handler:this.configLocale } );
  1871. /**
  1872. * The long month labels for the current locale.
  1873. * @config MONTHS_LONG
  1874. * @type String[]
  1875. * @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
  1876. */
  1877. cfg.addProperty(DEF_CFG.MONTHS_LONG.key, { value:DEF_CFG.MONTHS_LONG.value, handler:this.configLocale } );
  1878. /**
  1879. * The 1-character weekday labels for the current locale.
  1880. * @config WEEKDAYS_1CHAR
  1881. * @type String[]
  1882. * @default ["S", "M", "T", "W", "T", "F", "S"]
  1883. */
  1884. cfg.addProperty(DEF_CFG.WEEKDAYS_1CHAR.key, { value:DEF_CFG.WEEKDAYS_1CHAR.value, handler:this.configLocale } );
  1885. /**
  1886. * The short weekday labels for the current locale.
  1887. * @config WEEKDAYS_SHORT
  1888. * @type String[]
  1889. * @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
  1890. */
  1891. cfg.addProperty(DEF_CFG.WEEKDAYS_SHORT.key, { value:DEF_CFG.WEEKDAYS_SHORT.value, handler:this.configLocale } );
  1892. /**
  1893. * The medium weekday labels for the current locale.
  1894. * @config WEEKDAYS_MEDIUM
  1895. * @type String[]
  1896. * @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
  1897. */
  1898. cfg.addProperty(DEF_CFG.WEEKDAYS_MEDIUM.key, { value:DEF_CFG.WEEKDAYS_MEDIUM.value, handler:this.configLocale } );
  1899. /**
  1900. * The long weekday labels for the current locale.
  1901. * @config WEEKDAYS_LONG
  1902. * @type String[]
  1903. * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
  1904. */
  1905. cfg.addProperty(DEF_CFG.WEEKDAYS_LONG.key, { value:DEF_CFG.WEEKDAYS_LONG.value, handler:this.configLocale } );
  1906. /**
  1907. * Refreshes the locale values used to build the Calendar.
  1908. * @method refreshLocale
  1909. * @private
  1910. */
  1911. var refreshLocale = function() {
  1912. cfg.refireEvent(DEF_CFG.LOCALE_MONTHS.key);
  1913. cfg.refireEvent(DEF_CFG.LOCALE_WEEKDAYS.key);
  1914. };
  1915. cfg.subscribeToConfigEvent(DEF_CFG.START_WEEKDAY.key, refreshLocale, this, true);
  1916. cfg.subscribeToConfigEvent(DEF_CFG.MONTHS_SHORT.key, refreshLocale, this, true);
  1917. cfg.subscribeToConfigEvent(DEF_CFG.MONTHS_LONG.key, refreshLocale, this, true);
  1918. cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_1CHAR.key, refreshLocale, this, true);
  1919. cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_SHORT.key, refreshLocale, this, true);
  1920. cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_MEDIUM.key, refreshLocale, this, true);
  1921. cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_LONG.key, refreshLocale, this, true);
  1922. /**
  1923. * The setting that determines which length of month labels should be used. Possible values are "short" and "long".
  1924. * @config LOCALE_MONTHS
  1925. * @type String
  1926. * @default "long"
  1927. */
  1928. cfg.addProperty(DEF_CFG.LOCALE_MONTHS.key, { value:DEF_CFG.LOCALE_MONTHS.value, handler:this.configLocaleValues } );
  1929. /**
  1930. * The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
  1931. * @config LOCALE_WEEKDAYS
  1932. * @type String
  1933. * @default "short"
  1934. */
  1935. cfg.addProperty(DEF_CFG.LOCALE_WEEKDAYS.key, { value:DEF_CFG.LOCALE_WEEKDAYS.value, handler:this.configLocaleValues } );
  1936. /**
  1937. * The value used to delimit individual dates in a date string passed to various Calendar functions.
  1938. * @config DATE_DELIMITER
  1939. * @type String
  1940. * @default ","
  1941. */
  1942. cfg.addProperty(DEF_CFG.DATE_DELIMITER.key, { value:DEF_CFG.DATE_DELIMITER.value, handler:this.configLocale } );
  1943. /**
  1944. * The value used to delimit date fields in a date string passed to various Calendar functions.
  1945. * @config DATE_FIELD_DELIMITER
  1946. * @type String
  1947. * @default "/"
  1948. */
  1949. cfg.addProperty(DEF_CFG.DATE_FIELD_DELIMITER.key, { value:DEF_CFG.DATE_FIELD_DELIMITER.value, handler:this.configLocale } );
  1950. /**
  1951. * The value used to delimit date ranges in a date string passed to various Calendar functions.
  1952. * @config DATE_RANGE_DELIMITER
  1953. * @type String
  1954. * @default "-"
  1955. */
  1956. cfg.addProperty(DEF_CFG.DATE_RANGE_DELIMITER.key, { value:DEF_CFG.DATE_RANGE_DELIMITER.value, handler:this.configLocale } );
  1957. /**
  1958. * The position of the month in a month/year date string
  1959. * @config MY_MONTH_POSITION
  1960. * @type Number
  1961. * @default 1
  1962. */
  1963. cfg.addProperty(DEF_CFG.MY_MONTH_POSITION.key, { value:DEF_CFG.MY_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  1964. /**
  1965. * The position of the year in a month/year date string
  1966. * @config MY_YEAR_POSITION
  1967. * @type Number
  1968. * @default 2
  1969. */
  1970. cfg.addProperty(DEF_CFG.MY_YEAR_POSITION.key, { value:DEF_CFG.MY_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  1971. /**
  1972. * The position of the month in a month/day date string
  1973. * @config MD_MONTH_POSITION
  1974. * @type Number
  1975. * @default 1
  1976. */
  1977. cfg.addProperty(DEF_CFG.MD_MONTH_POSITION.key, { value:DEF_CFG.MD_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  1978. /**
  1979. * The position of the day in a month/year date string
  1980. * @config MD_DAY_POSITION
  1981. * @type Number
  1982. * @default 2
  1983. */
  1984. cfg.addProperty(DEF_CFG.MD_DAY_POSITION.key, { value:DEF_CFG.MD_DAY_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  1985. /**
  1986. * The position of the month in a month/day/year date string
  1987. * @config MDY_MONTH_POSITION
  1988. * @type Number
  1989. * @default 1
  1990. */
  1991. cfg.addProperty(DEF_CFG.MDY_MONTH_POSITION.key, { value:DEF_CFG.MDY_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  1992. /**
  1993. * The position of the day in a month/day/year date string
  1994. * @config MDY_DAY_POSITION
  1995. * @type Number
  1996. * @default 2
  1997. */
  1998. cfg.addProperty(DEF_CFG.MDY_DAY_POSITION.key, { value:DEF_CFG.MDY_DAY_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  1999. /**
  2000. * The position of the year in a month/day/year date string
  2001. * @config MDY_YEAR_POSITION
  2002. * @type Number
  2003. * @default 3
  2004. */
  2005. cfg.addProperty(DEF_CFG.MDY_YEAR_POSITION.key, { value:DEF_CFG.MDY_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  2006. /**
  2007. * The position of the month in the month year label string used as the Calendar header
  2008. * @config MY_LABEL_MONTH_POSITION
  2009. * @type Number
  2010. * @default 1
  2011. */
  2012. cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_POSITION.key, { value:DEF_CFG.MY_LABEL_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  2013. /**
  2014. * The position of the year in the month year label string used as the Calendar header
  2015. * @config MY_LABEL_YEAR_POSITION
  2016. * @type Number
  2017. * @default 2
  2018. */
  2019. cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_POSITION.key, { value:DEF_CFG.MY_LABEL_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
  2020. /**
  2021. * The suffix used after the month when rendering the Calendar header
  2022. * @config MY_LABEL_MONTH_SUFFIX
  2023. * @type String
  2024. * @default " "
  2025. */
  2026. cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_SUFFIX.key, { value:DEF_CFG.MY_LABEL_MONTH_SUFFIX.value, handler:this.configLocale } );
  2027. /**
  2028. * The suffix used after the year when rendering the Calendar header
  2029. * @config MY_LABEL_YEAR_SUFFIX
  2030. * @type String
  2031. * @default ""
  2032. */
  2033. cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_SUFFIX.key, { value:DEF_CFG.MY_LABEL_YEAR_SUFFIX.value, handler:this.configLocale } );
  2034. /**
  2035. * Configuration for the Month/Year CalendarNavigator UI which allows the user to jump directly to a
  2036. * specific Month/Year without having to scroll sequentially through months.
  2037. * <p>
  2038. * Setting this property to null (default value) or false, will disable the CalendarNavigator UI.
  2039. * </p>
  2040. * <p>
  2041. * Setting this property to true will enable the CalendarNavigatior UI with the default CalendarNavigator configuration values.
  2042. * </p>
  2043. * <p>
  2044. * This property can also be set to an object literal containing configuration properties for the CalendarNavigator UI.
  2045. * The configuration object expects the the following case-sensitive properties, with the "strings" property being a nested object.
  2046. * Any properties which are not provided will use the default values (defined in the CalendarNavigator class).
  2047. * </p>
  2048. * <dl>
  2049. * <dt>strings</dt>
  2050. * <dd><em>Object</em> : An object with the properties shown below, defining the string labels to use in the Navigator's UI
  2051. * <dl>
  2052. * <dt>month</dt><dd><em>String</em> : The string to use for the month label. Defaults to "Month".</dd>
  2053. * <dt>year</dt><dd><em>String</em> : The string to use for the year label. Defaults to "Year".</dd>
  2054. * <dt>submit</dt><dd><em>String</em> : The string to use for the submit button label. Defaults to "Okay".</dd>
  2055. * <dt>cancel</dt><dd><em>String</em> : The string to use for the cancel button label. Defaults to "Cancel".</dd>
  2056. * <dt>invalidYear</dt><dd><em>String</em> : The string to use for invalid year values. Defaults to "Year needs to be a number".</dd>
  2057. * </dl>
  2058. * </dd>
  2059. * <dt>monthFormat</dt><dd><em>String</em> : The month format to use. Either YAHOO.widget.Calendar.LONG, or YAHOO.widget.Calendar.SHORT. Defaults to YAHOO.widget.Calendar.LONG</dd>
  2060. * <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
  2061. * </dl>
  2062. * <p>E.g.</p>
  2063. * <pre>
  2064. * var navConfig = {
  2065. * strings: {
  2066. * month:"Calendar Month",
  2067. * year:"Calendar Year",
  2068. * submit: "Submit",
  2069. * cancel: "Cancel",
  2070. * invalidYear: "Please enter a valid year"
  2071. * },
  2072. * monthFormat: YAHOO.widget.Calendar.SHORT,
  2073. * initialFocus: "month"
  2074. * }
  2075. * </pre>
  2076. * @config navigator
  2077. * @type {Object|Boolean}
  2078. * @default null
  2079. */
  2080. cfg.addProperty(DEF_CFG.NAV.key, { value:DEF_CFG.NAV.value, handler:this.configNavigator } );
  2081. /**
  2082. * The map of UI strings which the Calendar UI uses.
  2083. *
  2084. * @config strings
  2085. * @type {Object}
  2086. * @default An object with the properties shown below:
  2087. * <dl>
  2088. * <dt>previousMonth</dt><dd><em>String</em> : The string to use for the "Previous Month" navigation UI. Defaults to "Previous Month".</dd>
  2089. * <dt>nextMonth</dt><dd><em>String</em> : The string to use for the "Next Month" navigation UI. Defaults to "Next Month".</dd>
  2090. * <dt>close</dt><dd><em>String</em> : The string to use for the close button label. Defaults to "Close".</dd>
  2091. * </dl>
  2092. */
  2093. cfg.addProperty(DEF_CFG.STRINGS.key, {
  2094. value:DEF_CFG.STRINGS.value,
  2095. handler:this.configStrings,
  2096. validator: function(val) {
  2097. return Lang.isObject(val);
  2098. },
  2099. supercedes:DEF_CFG.STRINGS.supercedes
  2100. });
  2101. },
  2102. /**
  2103. * The default handler for the "strings" property
  2104. * @method configStrings
  2105. */
  2106. configStrings : function(type, args, obj) {
  2107. var val = Lang.merge(DEF_CFG.STRINGS.value, args[0]);
  2108. this.cfg.setProperty(DEF_CFG.STRINGS.key, val, true);
  2109. },
  2110. /**
  2111. * The default handler for the "pagedate" property
  2112. * @method configPageDate
  2113. */
  2114. configPageDate : function(type, args, obj) {
  2115. this.cfg.setProperty(DEF_CFG.PAGEDATE.key, this._parsePageDate(args[0]), true);
  2116. },
  2117. /**
  2118. * The default handler for the "mindate" property
  2119. * @method configMinDate
  2120. */
  2121. configMinDate : function(type, args, obj) {
  2122. var val = args[0];
  2123. if (Lang.isString(val)) {
  2124. val = this._parseDate(val);
  2125. this.cfg.setProperty(DEF_CFG.MINDATE.key, DateMath.getDate(val[0],(val[1]-1),val[2]));
  2126. }
  2127. },
  2128. /**
  2129. * The default handler for the "maxdate" property
  2130. * @method configMaxDate
  2131. */
  2132. configMaxDate : function(type, args, obj) {
  2133. var val = args[0];
  2134. if (Lang.isString(val)) {
  2135. val = this._parseDate(val);
  2136. this.cfg.setProperty(DEF_CFG.MAXDATE.key, DateMath.getDate(val[0],(val[1]-1),val[2]));
  2137. }
  2138. },
  2139. /**
  2140. * The default handler for the "selected" property
  2141. * @method configSelected
  2142. */
  2143. configSelected : function(type, args, obj) {
  2144. var selected = args[0],
  2145. cfgSelected = DEF_CFG.SELECTED.key;
  2146. if (selected) {
  2147. if (Lang.isString(selected)) {
  2148. this.cfg.setProperty(cfgSelected, this._parseDates(selected), true);
  2149. }
  2150. }
  2151. if (! this._selectedDates) {
  2152. this._selectedDates = this.cfg.getProperty(cfgSelected);
  2153. }
  2154. },
  2155. /**
  2156. * The default handler for all configuration options properties
  2157. * @method configOptions
  2158. */
  2159. configOptions : function(type, args, obj) {
  2160. this.Options[type.toUpperCase()] = args[0];
  2161. },
  2162. /**
  2163. * The default handler for all configuration locale properties
  2164. * @method configLocale
  2165. */
  2166. configLocale : function(type, args, obj) {
  2167. this.Locale[type.toUpperCase()] = args[0];
  2168. this.cfg.refireEvent(DEF_CFG.LOCALE_MONTHS.key);
  2169. this.cfg.refireEvent(DEF_CFG.LOCALE_WEEKDAYS.key);
  2170. },
  2171. /**
  2172. * The default handler for all configuration locale field length properties
  2173. * @method configLocaleValues
  2174. */
  2175. configLocaleValues : function(type, args, obj) {
  2176. type = type.toLowerCase();
  2177. var val = args[0],
  2178. cfg = this.cfg,
  2179. Locale = this.Locale;
  2180. switch (type) {
  2181. case DEF_CFG.LOCALE_MONTHS.key:
  2182. switch (val) {
  2183. case Calendar.SHORT:
  2184. Locale.LOCALE_MONTHS = cfg.getProperty(DEF_CFG.MONTHS_SHORT.key).concat();
  2185. break;
  2186. case Calendar.LONG:
  2187. Locale.LOCALE_MONTHS = cfg.getProperty(DEF_CFG.MONTHS_LONG.key).concat();
  2188. break;
  2189. }
  2190. break;
  2191. case DEF_CFG.LOCALE_WEEKDAYS.key:
  2192. switch (val) {
  2193. case Calendar.ONE_CHAR:
  2194. Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_1CHAR.key).concat();
  2195. break;
  2196. case Calendar.SHORT:
  2197. Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_SHORT.key).concat();
  2198. break;
  2199. case Calendar.MEDIUM:
  2200. Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_MEDIUM.key).concat();
  2201. break;
  2202. case Calendar.LONG:
  2203. Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_LONG.key).concat();
  2204. break;
  2205. }
  2206. var START_WEEKDAY = cfg.getProperty(DEF_CFG.START_WEEKDAY.key);
  2207. if (START_WEEKDAY > 0) {
  2208. for (var w=0; w < START_WEEKDAY; ++w) {
  2209. Locale.LOCALE_WEEKDAYS.push(Locale.LOCALE_WEEKDAYS.shift());
  2210. }
  2211. }
  2212. break;
  2213. }
  2214. },
  2215. /**
  2216. * The default handler for the "navigator" property
  2217. * @method configNavigator
  2218. */
  2219. configNavigator : function(type, args, obj) {
  2220. var val = args[0];
  2221. if (YAHOO.widget.CalendarNavigator && (val === true || Lang.isObject(val))) {
  2222. if (!this.oNavigator) {
  2223. this.oNavigator = new YAHOO.widget.CalendarNavigator(this);
  2224. // Cleanup DOM Refs/Events before innerHTML is removed.
  2225. this.beforeRenderEvent.subscribe(function () {
  2226. if (!this.pages) {
  2227. this.oNavigator.erase();
  2228. }
  2229. }, this, true);
  2230. }
  2231. } else {
  2232. if (this.oNavigator) {
  2233. this.oNavigator.destroy();
  2234. this.oNavigator = null;
  2235. }
  2236. }
  2237. },
  2238. /**
  2239. * Defines the style constants for the Calendar
  2240. * @method initStyles
  2241. */
  2242. initStyles : function() {
  2243. var defStyle = Calendar._STYLES;
  2244. this.Style = {
  2245. /**
  2246. * @property Style.CSS_ROW_HEADER
  2247. */
  2248. CSS_ROW_HEADER: defStyle.CSS_ROW_HEADER,
  2249. /**
  2250. * @property Style.CSS_ROW_FOOTER
  2251. */
  2252. CSS_ROW_FOOTER: defStyle.CSS_ROW_FOOTER,
  2253. /**
  2254. * @property Style.CSS_CELL
  2255. */
  2256. CSS_CELL : defStyle.CSS_CELL,
  2257. /**
  2258. * @property Style.CSS_CELL_SELECTOR
  2259. */
  2260. CSS_CELL_SELECTOR : defStyle.CSS_CELL_SELECTOR,
  2261. /**
  2262. * @property Style.CSS_CELL_SELECTED
  2263. */
  2264. CSS_CELL_SELECTED : defStyle.CSS_CELL_SELECTED,
  2265. /**
  2266. * @property Style.CSS_CELL_SELECTABLE
  2267. */
  2268. CSS_CELL_SELECTABLE : defStyle.CSS_CELL_SELECTABLE,
  2269. /**
  2270. * @property Style.CSS_CELL_RESTRICTED
  2271. */
  2272. CSS_CELL_RESTRICTED : defStyle.CSS_CELL_RESTRICTED,
  2273. /**
  2274. * @property Style.CSS_CELL_TODAY
  2275. */
  2276. CSS_CELL_TODAY : defStyle.CSS_CELL_TODAY,
  2277. /**
  2278. * @property Style.CSS_CELL_OOM
  2279. */
  2280. CSS_CELL_OOM : defStyle.CSS_CELL_OOM,
  2281. /**
  2282. * @property Style.CSS_CELL_OOB
  2283. */
  2284. CSS_CELL_OOB : defStyle.CSS_CELL_OOB,
  2285. /**
  2286. * @property Style.CSS_HEADER
  2287. */
  2288. CSS_HEADER : defStyle.CSS_HEADER,
  2289. /**
  2290. * @property Style.CSS_HEADER_TEXT
  2291. */
  2292. CSS_HEADER_TEXT : defStyle.CSS_HEADER_TEXT,
  2293. /**
  2294. * @property Style.CSS_BODY
  2295. */
  2296. CSS_BODY : defStyle.CSS_BODY,
  2297. /**
  2298. * @property Style.CSS_WEEKDAY_CELL
  2299. */
  2300. CSS_WEEKDAY_CELL : defStyle.CSS_WEEKDAY_CELL,
  2301. /**
  2302. * @property Style.CSS_WEEKDAY_ROW
  2303. */
  2304. CSS_WEEKDAY_ROW : defStyle.CSS_WEEKDAY_ROW,
  2305. /**
  2306. * @property Style.CSS_FOOTER
  2307. */
  2308. CSS_FOOTER : defStyle.CSS_FOOTER,
  2309. /**
  2310. * @property Style.CSS_CALENDAR
  2311. */
  2312. CSS_CALENDAR : defStyle.CSS_CALENDAR,
  2313. /**
  2314. * @property Style.CSS_SINGLE
  2315. */
  2316. CSS_SINGLE : defStyle.CSS_SINGLE,
  2317. /**
  2318. * @property Style.CSS_CONTAINER
  2319. */
  2320. CSS_CONTAINER : defStyle.CSS_CONTAINER,
  2321. /**
  2322. * @property Style.CSS_NAV_LEFT
  2323. */
  2324. CSS_NAV_LEFT : defStyle.CSS_NAV_LEFT,
  2325. /**
  2326. * @property Style.CSS_NAV_RIGHT
  2327. */
  2328. CSS_NAV_RIGHT : defStyle.CSS_NAV_RIGHT,
  2329. /**
  2330. * @property Style.CSS_NAV
  2331. */
  2332. CSS_NAV : defStyle.CSS_NAV,
  2333. /**
  2334. * @property Style.CSS_CLOSE
  2335. */
  2336. CSS_CLOSE : defStyle.CSS_CLOSE,
  2337. /**
  2338. * @property Style.CSS_CELL_TOP
  2339. */
  2340. CSS_CELL_TOP : defStyle.CSS_CELL_TOP,
  2341. /**
  2342. * @property Style.CSS_CELL_LEFT
  2343. */
  2344. CSS_CELL_LEFT : defStyle.CSS_CELL_LEFT,
  2345. /**
  2346. * @property Style.CSS_CELL_RIGHT
  2347. */
  2348. CSS_CELL_RIGHT : defStyle.CSS_CELL_RIGHT,
  2349. /**
  2350. * @property Style.CSS_CELL_BOTTOM
  2351. */
  2352. CSS_CELL_BOTTOM : defStyle.CSS_CELL_BOTTOM,
  2353. /**
  2354. * @property Style.CSS_CELL_HOVER
  2355. */
  2356. CSS_CELL_HOVER : defStyle.CSS_CELL_HOVER,
  2357. /**
  2358. * @property Style.CSS_CELL_HIGHLIGHT1
  2359. */
  2360. CSS_CELL_HIGHLIGHT1 : defStyle.CSS_CELL_HIGHLIGHT1,
  2361. /**
  2362. * @property Style.CSS_CELL_HIGHLIGHT2
  2363. */
  2364. CSS_CELL_HIGHLIGHT2 : defStyle.CSS_CELL_HIGHLIGHT2,
  2365. /**
  2366. * @property Style.CSS_CELL_HIGHLIGHT3
  2367. */
  2368. CSS_CELL_HIGHLIGHT3 : defStyle.CSS_CELL_HIGHLIGHT3,
  2369. /**
  2370. * @property Style.CSS_CELL_HIGHLIGHT4
  2371. */
  2372. CSS_CELL_HIGHLIGHT4 : defStyle.CSS_CELL_HIGHLIGHT4
  2373. };
  2374. },
  2375. /**
  2376. * Builds the date label that will be displayed in the calendar header or
  2377. * footer, depending on configuration.
  2378. * @method buildMonthLabel
  2379. * @return {String} The formatted calendar month label
  2380. */
  2381. buildMonthLabel : function() {
  2382. return this._buildMonthLabel(this.cfg.getProperty(DEF_CFG.PAGEDATE.key));
  2383. },
  2384. /**
  2385. * Helper method, to format a Month Year string, given a JavaScript Date, based on the
  2386. * Calendar localization settings
  2387. *
  2388. * @method _buildMonthLabel
  2389. * @private
  2390. * @param {Date} date
  2391. * @return {String} Formated month, year string
  2392. */
  2393. _buildMonthLabel : function(date) {
  2394. var monthLabel = this.Locale.LOCALE_MONTHS[date.getMonth()] + this.Locale.MY_LABEL_MONTH_SUFFIX,
  2395. yearLabel = date.getFullYear() + this.Locale.MY_LABEL_YEAR_SUFFIX;
  2396. if (this.Locale.MY_LABEL_MONTH_POSITION == 2 || this.Locale.MY_LABEL_YEAR_POSITION == 1) {
  2397. return yearLabel + monthLabel;
  2398. } else {
  2399. return monthLabel + yearLabel;
  2400. }
  2401. },
  2402. /**
  2403. * Builds the date digit that will be displayed in calendar cells
  2404. * @method buildDayLabel
  2405. * @param {Date} workingDate The current working date
  2406. * @return {String} The formatted day label
  2407. */
  2408. buildDayLabel : function(workingDate) {
  2409. return workingDate.getDate();
  2410. },
  2411. /**
  2412. * Creates the title bar element and adds it to Calendar container DIV
  2413. *
  2414. * @method createTitleBar
  2415. * @param {String} strTitle The title to display in the title bar
  2416. * @return The title bar element
  2417. */
  2418. createTitleBar : function(strTitle) {
  2419. var tDiv = Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || document.createElement("div");
  2420. tDiv.className = YAHOO.widget.CalendarGroup.CSS_2UPTITLE;
  2421. tDiv.innerHTML = strTitle;
  2422. this.oDomContainer.insertBefore(tDiv, this.oDomContainer.firstChild);
  2423. Dom.addClass(this.oDomContainer, "withtitle");
  2424. return tDiv;
  2425. },
  2426. /**
  2427. * Removes the title bar element from the DOM
  2428. *
  2429. * @method removeTitleBar
  2430. */
  2431. removeTitleBar : function() {
  2432. var tDiv = Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || null;
  2433. if (tDiv) {
  2434. Event.purgeElement(tDiv);
  2435. this.oDomContainer.removeChild(tDiv);
  2436. }
  2437. Dom.removeClass(this.oDomContainer, "withtitle");
  2438. },
  2439. /**
  2440. * Creates the close button HTML element and adds it to Calendar container DIV
  2441. *
  2442. * @method createCloseButton
  2443. * @return The close HTML element created
  2444. */
  2445. createCloseButton : function() {
  2446. var cssClose = YAHOO.widget.CalendarGroup.CSS_2UPCLOSE,
  2447. DEPR_CLOSE_PATH = "us/my/bn/x_d.gif",
  2448. lnk = Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0],
  2449. strings = this.cfg.getProperty(DEF_CFG.STRINGS.key),
  2450. closeStr = (strings && strings.close) ? strings.close : "";
  2451. if (!lnk) {
  2452. lnk = document.createElement("a");
  2453. Event.addListener(lnk, "click", function(e, cal) {
  2454. cal.hide();
  2455. Event.preventDefault(e);
  2456. }, this);
  2457. }
  2458. lnk.href = "#";
  2459. lnk.className = "link-close";
  2460. if (Calendar.IMG_ROOT !== null) {
  2461. var img = Dom.getElementsByClassName(cssClose, "img", lnk)[0] || document.createElement("img");
  2462. img.src = Calendar.IMG_ROOT + DEPR_CLOSE_PATH;
  2463. img.className = cssClose;
  2464. lnk.appendChild(img);
  2465. } else {
  2466. lnk.innerHTML = '<span class="' + cssClose + ' ' + this.Style.CSS_CLOSE + '">' + closeStr + '</span>';
  2467. }
  2468. this.oDomContainer.appendChild(lnk);
  2469. return lnk;
  2470. },
  2471. /**
  2472. * Removes the close button HTML element from the DOM
  2473. *
  2474. * @method removeCloseButton
  2475. */
  2476. removeCloseButton : function() {
  2477. var btn = Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0] || null;
  2478. if (btn) {
  2479. Event.purgeElement(btn);
  2480. this.oDomContainer.removeChild(btn);
  2481. }
  2482. },
  2483. /**
  2484. * Renders the calendar header.
  2485. * @method renderHeader
  2486. * @param {Array} html The current working HTML array
  2487. * @return {Array} The current working HTML array
  2488. */
  2489. renderHeader : function(html) {
  2490. var colSpan = 7,
  2491. DEPR_NAV_LEFT = "us/tr/callt.gif",
  2492. DEPR_NAV_RIGHT = "us/tr/calrt.gif",
  2493. cfg = this.cfg,
  2494. pageDate = cfg.getProperty(DEF_CFG.PAGEDATE.key),
  2495. strings= cfg.getProperty(DEF_CFG.STRINGS.key),
  2496. prevStr = (strings && strings.previousMonth) ? strings.previousMonth : "",
  2497. nextStr = (strings && strings.nextMonth) ? strings.nextMonth : "",
  2498. monthLabel;
  2499. if (cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key)) {
  2500. colSpan += 1;
  2501. }
  2502. if (cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key)) {
  2503. colSpan += 1;
  2504. }
  2505. html[html.length] = "<thead>";
  2506. html[html.length] = "<tr>";
  2507. html[html.length] = '<th colspan="' + colSpan + '" class="' + this.Style.CSS_HEADER_TEXT + '">';
  2508. html[html.length] = '<div class="' + this.Style.CSS_HEADER + '">';
  2509. var renderLeft, renderRight = false;
  2510. if (this.parent) {
  2511. if (this.index === 0) {
  2512. renderLeft = true;
  2513. }
  2514. if (this.index == (this.parent.cfg.getProperty("pages") -1)) {
  2515. renderRight = true;
  2516. }
  2517. } else {
  2518. renderLeft = true;
  2519. renderRight = true;
  2520. }
  2521. if (renderLeft) {
  2522. monthLabel = this._buildMonthLabel(DateMath.subtract(pageDate, DateMath.MONTH, 1));
  2523. var leftArrow = cfg.getProperty(DEF_CFG.NAV_ARROW_LEFT.key);
  2524. // Check for deprecated customization - If someone set IMG_ROOT, but didn't set NAV_ARROW_LEFT, then set NAV_ARROW_LEFT to the old deprecated value
  2525. if (leftArrow === null && Calendar.IMG_ROOT !== null) {
  2526. leftArrow = Calendar.IMG_ROOT + DEPR_NAV_LEFT;
  2527. }
  2528. var leftStyle = (leftArrow === null) ? "" : ' style="background-image:url(' + leftArrow + ')"';
  2529. html[html.length] = '<a class="' + this.Style.CSS_NAV_LEFT + '"' + leftStyle + ' href="#">' + prevStr + ' (' + monthLabel + ')' + '</a>';
  2530. }
  2531. var lbl = this.buildMonthLabel();
  2532. var cal = this.parent || this;
  2533. if (cal.cfg.getProperty("navigator")) {
  2534. lbl = "<a class=\"" + this.Style.CSS_NAV + "\" href=\"#\">" + lbl + "</a>";
  2535. }
  2536. html[html.length] = lbl;
  2537. if (renderRight) {
  2538. monthLabel = this._buildMonthLabel(DateMath.add(pageDate, DateMath.MONTH, 1));
  2539. var rightArrow = cfg.getProperty(DEF_CFG.NAV_ARROW_RIGHT.key);
  2540. if (rightArrow === null && Calendar.IMG_ROOT !== null) {
  2541. rightArrow = Calendar.IMG_ROOT + DEPR_NAV_RIGHT;
  2542. }
  2543. var rightStyle = (rightArrow === null) ? "" : ' style="background-image:url(' + rightArrow + ')"';
  2544. html[html.length] = '<a class="' + this.Style.CSS_NAV_RIGHT + '"' + rightStyle + ' href="#">' + nextStr + ' (' + monthLabel + ')' + '</a>';
  2545. }
  2546. html[html.length] = '</div>\n</th>\n</tr>';
  2547. if (cfg.getProperty(DEF_CFG.SHOW_WEEKDAYS.key)) {
  2548. html = this.buildWeekdays(html);
  2549. }
  2550. html[html.length] = '</thead>';
  2551. return html;
  2552. },
  2553. /**
  2554. * Renders the Calendar's weekday headers.
  2555. * @method buildWeekdays
  2556. * @param {Array} html The current working HTML array
  2557. * @return {Array} The current working HTML array
  2558. */
  2559. buildWeekdays : function(html) {
  2560. html[html.length] = '<tr class="' + this.Style.CSS_WEEKDAY_ROW + '">';
  2561. if (this.cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key)) {
  2562. html[html.length] = '<th>&#160;</th>';
  2563. }
  2564. for(var i=0;i < this.Locale.LOCALE_WEEKDAYS.length; ++i) {
  2565. html[html.length] = '<th class="calweekdaycell">' + this.Locale.LOCALE_WEEKDAYS[i] + '</th>';
  2566. }
  2567. if (this.cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key)) {
  2568. html[html.length] = '<th>&#160;</th>';
  2569. }
  2570. html[html.length] = '</tr>';
  2571. return html;
  2572. },
  2573. /**
  2574. * Renders the calendar body.
  2575. * @method renderBody
  2576. * @param {Date} workingDate The current working Date being used for the render process
  2577. * @param {Array} html The current working HTML array
  2578. * @return {Array} The current working HTML array
  2579. */
  2580. renderBody : function(workingDate, html) {
  2581. var startDay = this.cfg.getProperty(DEF_CFG.START_WEEKDAY.key);
  2582. this.preMonthDays = workingDate.getDay();
  2583. if (startDay > 0) {
  2584. this.preMonthDays -= startDay;
  2585. }
  2586. if (this.preMonthDays < 0) {
  2587. this.preMonthDays += 7;
  2588. }
  2589. this.monthDays = DateMath.findMonthEnd(workingDate).getDate();
  2590. this.postMonthDays = Calendar.DISPLAY_DAYS-this.preMonthDays-this.monthDays;
  2591. workingDate = DateMath.subtract(workingDate, DateMath.DAY, this.preMonthDays);
  2592. var weekNum,
  2593. weekClass,
  2594. weekPrefix = "w",
  2595. cellPrefix = "_cell",
  2596. workingDayPrefix = "wd",
  2597. dayPrefix = "d",
  2598. cellRenderers,
  2599. renderer,
  2600. t = this.today,
  2601. cfg = this.cfg,
  2602. todayYear = t.getFullYear(),
  2603. todayMonth = t.getMonth(),
  2604. todayDate = t.getDate(),
  2605. useDate = cfg.getProperty(DEF_CFG.PAGEDATE.key),
  2606. hideBlankWeeks = cfg.getProperty(DEF_CFG.HIDE_BLANK_WEEKS.key),
  2607. showWeekFooter = cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key),
  2608. showWeekHeader = cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key),
  2609. mindate = cfg.getProperty(DEF_CFG.MINDATE.key),
  2610. maxdate = cfg.getProperty(DEF_CFG.MAXDATE.key);
  2611. if (mindate) {
  2612. mindate = DateMath.clearTime(mindate);
  2613. }
  2614. if (maxdate) {
  2615. maxdate = DateMath.clearTime(maxdate);
  2616. }
  2617. html[html.length] = '<tbody class="m' + (useDate.getMonth()+1) + ' ' + this.Style.CSS_BODY + '">';
  2618. var i = 0,
  2619. tempDiv = document.createElement("div"),
  2620. cell = document.createElement("td");
  2621. tempDiv.appendChild(cell);
  2622. var cal = this.parent || this;
  2623. for (var r=0;r<6;r++) {
  2624. weekNum = DateMath.getWeekNumber(workingDate, startDay);
  2625. weekClass = weekPrefix + weekNum;
  2626. // Local OOM check for performance, since we already have pagedate
  2627. if (r !== 0 && hideBlankWeeks === true && workingDate.getMonth() != useDate.getMonth()) {
  2628. break;
  2629. } else {
  2630. html[html.length] = '<tr class="' + weekClass + '">';
  2631. if (showWeekHeader) { html = this.renderRowHeader(weekNum, html); }
  2632. for (var d=0; d < 7; d++){ // Render actual days
  2633. cellRenderers = [];
  2634. this.clearElement(cell);
  2635. cell.className = this.Style.CSS_CELL;
  2636. cell.id = this.id + cellPrefix + i;
  2637. if (workingDate.getDate() == todayDate &&
  2638. workingDate.getMonth() == todayMonth &&
  2639. workingDate.getFullYear() == todayYear) {
  2640. cellRenderers[cellRenderers.length]=cal.renderCellStyleToday;
  2641. }
  2642. var workingArray = [workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()];
  2643. this.cellDates[this.cellDates.length] = workingArray; // Add this date to cellDates
  2644. // Local OOM check for performance, since we already have pagedate
  2645. if (workingDate.getMonth() != useDate.getMonth()) {
  2646. cellRenderers[cellRenderers.length]=cal.renderCellNotThisMonth;
  2647. } else {
  2648. Dom.addClass(cell, workingDayPrefix + workingDate.getDay());
  2649. Dom.addClass(cell, dayPrefix + workingDate.getDate());
  2650. for (var s=0;s<this.renderStack.length;++s) {
  2651. renderer = null;
  2652. var rArray = this.renderStack[s],
  2653. type = rArray[0],
  2654. month,
  2655. day,
  2656. year;
  2657. switch (type) {
  2658. case Calendar.DATE:
  2659. month = rArray[1][1];
  2660. day = rArray[1][2];
  2661. year = rArray[1][0];
  2662. if (workingDate.getMonth()+1 == month && workingDate.getDate() == day && workingDate.getFullYear() == year) {
  2663. renderer = rArray[2];
  2664. this.renderStack.splice(s,1);
  2665. }
  2666. break;
  2667. case Calendar.MONTH_DAY:
  2668. month = rArray[1][0];
  2669. day = rArray[1][1];
  2670. if (workingDate.getMonth()+1 == month && workingDate.getDate() == day) {
  2671. renderer = rArray[2];
  2672. this.renderStack.splice(s,1);
  2673. }
  2674. break;
  2675. case Calendar.RANGE:
  2676. var date1 = rArray[1][0],
  2677. date2 = rArray[1][1],
  2678. d1month = date1[1],
  2679. d1day = date1[2],
  2680. d1year = date1[0],
  2681. d1 = DateMath.getDate(d1year, d1month-1, d1day),
  2682. d2month = date2[1],
  2683. d2day = date2[2],
  2684. d2year = date2[0],
  2685. d2 = DateMath.getDate(d2year, d2month-1, d2day);
  2686. if (workingDate.getTime() >= d1.getTime() && workingDate.getTime() <= d2.getTime()) {
  2687. renderer = rArray[2];
  2688. if (workingDate.getTime()==d2.getTime()) {
  2689. this.renderStack.splice(s,1);
  2690. }
  2691. }
  2692. break;
  2693. case Calendar.WEEKDAY:
  2694. var weekday = rArray[1][0];
  2695. if (workingDate.getDay()+1 == weekday) {
  2696. renderer = rArray[2];
  2697. }
  2698. break;
  2699. case Calendar.MONTH:
  2700. month = rArray[1][0];
  2701. if (workingDate.getMonth()+1 == month) {
  2702. renderer = rArray[2];
  2703. }
  2704. break;
  2705. }
  2706. if (renderer) {
  2707. cellRenderers[cellRenderers.length]=renderer;
  2708. }
  2709. }
  2710. }
  2711. if (this._indexOfSelectedFieldArray(workingArray) > -1) {
  2712. cellRenderers[cellRenderers.length]=cal.renderCellStyleSelected;
  2713. }
  2714. if ((mindate && (workingDate.getTime() < mindate.getTime())) ||
  2715. (maxdate && (workingDate.getTime() > maxdate.getTime()))
  2716. ) {
  2717. cellRenderers[cellRenderers.length]=cal.renderOutOfBoundsDate;
  2718. } else {
  2719. cellRenderers[cellRenderers.length]=cal.styleCellDefault;
  2720. cellRenderers[cellRenderers.length]=cal.renderCellDefault;
  2721. }
  2722. for (var x=0; x < cellRenderers.length; ++x) {
  2723. if (cellRenderers[x].call(cal, workingDate, cell) == Calendar.STOP_RENDER) {
  2724. break;
  2725. }
  2726. }
  2727. workingDate.setTime(workingDate.getTime() + DateMath.ONE_DAY_MS);
  2728. // Just in case we crossed DST/Summertime boundaries
  2729. workingDate = DateMath.clearTime(workingDate);
  2730. if (i >= 0 && i <= 6) {
  2731. Dom.addClass(cell, this.Style.CSS_CELL_TOP);
  2732. }
  2733. if ((i % 7) === 0) {
  2734. Dom.addClass(cell, this.Style.CSS_CELL_LEFT);
  2735. }
  2736. if (((i+1) % 7) === 0) {
  2737. Dom.addClass(cell, this.Style.CSS_CELL_RIGHT);
  2738. }
  2739. var postDays = this.postMonthDays;
  2740. if (hideBlankWeeks && postDays >= 7) {
  2741. var blankWeeks = Math.floor(postDays/7);
  2742. for (var p=0;p<blankWeeks;++p) {
  2743. postDays -= 7;
  2744. }
  2745. }
  2746. if (i >= ((this.preMonthDays+postDays+this.monthDays)-7)) {
  2747. Dom.addClass(cell, this.Style.CSS_CELL_BOTTOM);
  2748. }
  2749. html[html.length] = tempDiv.innerHTML;
  2750. i++;
  2751. }
  2752. if (showWeekFooter) { html = this.renderRowFooter(weekNum, html); }
  2753. html[html.length] = '</tr>';
  2754. }
  2755. }
  2756. html[html.length] = '</tbody>';
  2757. return html;
  2758. },
  2759. /**
  2760. * Renders the calendar footer. In the default implementation, there is
  2761. * no footer.
  2762. * @method renderFooter
  2763. * @param {Array} html The current working HTML array
  2764. * @return {Array} The current working HTML array
  2765. */
  2766. renderFooter : function(html) { return html; },
  2767. /**
  2768. * Renders the calendar after it has been configured. The render() method has a specific call chain that will execute
  2769. * when the method is called: renderHeader, renderBody, renderFooter.
  2770. * Refer to the documentation for those methods for information on
  2771. * individual render tasks.
  2772. * @method render
  2773. */
  2774. render : function() {
  2775. this.beforeRenderEvent.fire();
  2776. // Find starting day of the current month
  2777. var workingDate = DateMath.findMonthStart(this.cfg.getProperty(DEF_CFG.PAGEDATE.key));
  2778. this.resetRenderers();
  2779. this.cellDates.length = 0;
  2780. Event.purgeElement(this.oDomContainer, true);
  2781. var html = [];
  2782. html[html.length] = '<table cellSpacing="0" class="' + this.Style.CSS_CALENDAR + ' y' + workingDate.getFullYear() + '" id="' + this.id + '">';
  2783. html = this.renderHeader(html);
  2784. html = this.renderBody(workingDate, html);
  2785. html = this.renderFooter(html);
  2786. html[html.length] = '</table>';
  2787. this.oDomContainer.innerHTML = html.join("\n");
  2788. this.applyListeners();
  2789. this.cells = this.oDomContainer.getElementsByTagName("td");
  2790. this.cfg.refireEvent(DEF_CFG.TITLE.key);
  2791. this.cfg.refireEvent(DEF_CFG.CLOSE.key);
  2792. this.cfg.refireEvent(DEF_CFG.IFRAME.key);
  2793. this.renderEvent.fire();
  2794. },
  2795. /**
  2796. * Applies the Calendar's DOM listeners to applicable elements.
  2797. * @method applyListeners
  2798. */
  2799. applyListeners : function() {
  2800. var root = this.oDomContainer,
  2801. cal = this.parent || this,
  2802. anchor = "a",
  2803. click = "click";
  2804. var linkLeft = Dom.getElementsByClassName(this.Style.CSS_NAV_LEFT, anchor, root),
  2805. linkRight = Dom.getElementsByClassName(this.Style.CSS_NAV_RIGHT, anchor, root);
  2806. if (linkLeft && linkLeft.length > 0) {
  2807. this.linkLeft = linkLeft[0];
  2808. Event.addListener(this.linkLeft, click, this.doPreviousMonthNav, cal, true);
  2809. }
  2810. if (linkRight && linkRight.length > 0) {
  2811. this.linkRight = linkRight[0];
  2812. Event.addListener(this.linkRight, click, this.doNextMonthNav, cal, true);
  2813. }
  2814. if (cal.cfg.getProperty("navigator") !== null) {
  2815. this.applyNavListeners();
  2816. }
  2817. if (this.domEventMap) {
  2818. var el,elements;
  2819. for (var cls in this.domEventMap) {
  2820. if (Lang.hasOwnProperty(this.domEventMap, cls)) {
  2821. var items = this.domEventMap[cls];
  2822. if (! (items instanceof Array)) {
  2823. items = [items];
  2824. }
  2825. for (var i=0;i<items.length;i++) {
  2826. var item = items[i];
  2827. elements = Dom.getElementsByClassName(cls, item.tag, this.oDomContainer);
  2828. for (var c=0;c<elements.length;c++) {
  2829. el = elements[c];
  2830. Event.addListener(el, item.event, item.handler, item.scope, item.correct );
  2831. }
  2832. }
  2833. }
  2834. }
  2835. }
  2836. Event.addListener(this.oDomContainer, "click", this.doSelectCell, this);
  2837. Event.addListener(this.oDomContainer, "mouseover", this.doCellMouseOver, this);
  2838. Event.addListener(this.oDomContainer, "mouseout", this.doCellMouseOut, this);
  2839. },
  2840. applyNavListeners : function() {
  2841. var calParent = this.parent || this,
  2842. cal = this,
  2843. navBtns = Dom.getElementsByClassName(this.Style.CSS_NAV, "a", this.oDomContainer);
  2844. if (navBtns.length > 0) {
  2845. Event.addListener(navBtns, "click", function (e, obj) {
  2846. var target = Event.getTarget(e);
  2847. // this == navBtn
  2848. if (this === target || Dom.isAncestor(this, target)) {
  2849. Event.preventDefault(e);
  2850. }
  2851. var navigator = calParent.oNavigator;
  2852. if (navigator) {
  2853. var pgdate = cal.cfg.getProperty("pagedate");
  2854. navigator.setYear(pgdate.getFullYear());
  2855. navigator.setMonth(pgdate.getMonth());
  2856. navigator.show();
  2857. }
  2858. });
  2859. }
  2860. },
  2861. /**
  2862. * Retrieves the Date object for the specified Calendar cell
  2863. * @method getDateByCellId
  2864. * @param {String} id The id of the cell
  2865. * @return {Date} The Date object for the specified Calendar cell
  2866. */
  2867. getDateByCellId : function(id) {
  2868. var date = this.getDateFieldsByCellId(id);
  2869. return (date) ? DateMath.getDate(date[0],date[1]-1,date[2]) : null;
  2870. },
  2871. /**
  2872. * Retrieves the Date object for the specified Calendar cell
  2873. * @method getDateFieldsByCellId
  2874. * @param {String} id The id of the cell
  2875. * @return {Array} The array of Date fields for the specified Calendar cell
  2876. */
  2877. getDateFieldsByCellId : function(id) {
  2878. id = this.getIndexFromId(id);
  2879. return (id > -1) ? this.cellDates[id] : null;
  2880. },
  2881. /**
  2882. * Find the Calendar's cell index for a given date.
  2883. * If the date is not found, the method returns -1.
  2884. * <p>
  2885. * The returned index can be used to lookup the cell HTMLElement
  2886. * using the Calendar's cells array or passed to selectCell to select
  2887. * cells by index.
  2888. * </p>
  2889. *
  2890. * See <a href="#cells">cells</a>, <a href="#selectCell">selectCell</a>.
  2891. *
  2892. * @method getCellIndex
  2893. * @param {Date} date JavaScript Date object, for which to find a cell index.
  2894. * @return {Number} The index of the date in Calendars cellDates/cells arrays, or -1 if the date
  2895. * is not on the curently rendered Calendar page.
  2896. */
  2897. getCellIndex : function(date) {
  2898. var idx = -1;
  2899. if (date) {
  2900. var m = date.getMonth(),
  2901. y = date.getFullYear(),
  2902. d = date.getDate(),
  2903. dates = this.cellDates;
  2904. for (var i = 0; i < dates.length; ++i) {
  2905. var cellDate = dates[i];
  2906. if (cellDate[0] === y && cellDate[1] === m+1 && cellDate[2] === d) {
  2907. idx = i;
  2908. break;
  2909. }
  2910. }
  2911. }
  2912. return idx;
  2913. },
  2914. /**
  2915. * Given the id used to mark each Calendar cell, this method
  2916. * extracts the index number from the id.
  2917. *
  2918. * @param {String} strId The cell id
  2919. * @return {Number} The index of the cell, or -1 if id does not contain an index number
  2920. */
  2921. getIndexFromId : function(strId) {
  2922. var idx = -1,
  2923. li = strId.lastIndexOf("_cell");
  2924. if (li > -1) {
  2925. idx = parseInt(strId.substring(li + 5), 10);
  2926. }
  2927. return idx;
  2928. },
  2929. // BEGIN BUILT-IN TABLE CELL RENDERERS
  2930. /**
  2931. * Renders a cell that falls before the minimum date or after the maximum date.
  2932. * widget class.
  2933. * @method renderOutOfBoundsDate
  2934. * @param {Date} workingDate The current working Date object being used to generate the calendar
  2935. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  2936. * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
  2937. * should not be terminated
  2938. */
  2939. renderOutOfBoundsDate : function(workingDate, cell) {
  2940. Dom.addClass(cell, this.Style.CSS_CELL_OOB);
  2941. cell.innerHTML = workingDate.getDate();
  2942. return Calendar.STOP_RENDER;
  2943. },
  2944. /**
  2945. * Renders the row header for a week.
  2946. * @method renderRowHeader
  2947. * @param {Number} weekNum The week number of the current row
  2948. * @param {Array} cell The current working HTML array
  2949. */
  2950. renderRowHeader : function(weekNum, html) {
  2951. html[html.length] = '<th class="calrowhead">' + weekNum + '</th>';
  2952. return html;
  2953. },
  2954. /**
  2955. * Renders the row footer for a week.
  2956. * @method renderRowFooter
  2957. * @param {Number} weekNum The week number of the current row
  2958. * @param {Array} cell The current working HTML array
  2959. */
  2960. renderRowFooter : function(weekNum, html) {
  2961. html[html.length] = '<th class="calrowfoot">' + weekNum + '</th>';
  2962. return html;
  2963. },
  2964. /**
  2965. * Renders a single standard calendar cell in the calendar widget table.
  2966. * All logic for determining how a standard default cell will be rendered is
  2967. * encapsulated in this method, and must be accounted for when extending the
  2968. * widget class.
  2969. * @method renderCellDefault
  2970. * @param {Date} workingDate The current working Date object being used to generate the calendar
  2971. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  2972. */
  2973. renderCellDefault : function(workingDate, cell) {
  2974. cell.innerHTML = '<a href="#" class="' + this.Style.CSS_CELL_SELECTOR + '">' + this.buildDayLabel(workingDate) + "</a>";
  2975. },
  2976. /**
  2977. * Styles a selectable cell.
  2978. * @method styleCellDefault
  2979. * @param {Date} workingDate The current working Date object being used to generate the calendar
  2980. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  2981. */
  2982. styleCellDefault : function(workingDate, cell) {
  2983. Dom.addClass(cell, this.Style.CSS_CELL_SELECTABLE);
  2984. },
  2985. /**
  2986. * Renders a single standard calendar cell using the CSS hightlight1 style
  2987. * @method renderCellStyleHighlight1
  2988. * @param {Date} workingDate The current working Date object being used to generate the calendar
  2989. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  2990. */
  2991. renderCellStyleHighlight1 : function(workingDate, cell) {
  2992. Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT1);
  2993. },
  2994. /**
  2995. * Renders a single standard calendar cell using the CSS hightlight2 style
  2996. * @method renderCellStyleHighlight2
  2997. * @param {Date} workingDate The current working Date object being used to generate the calendar
  2998. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  2999. */
  3000. renderCellStyleHighlight2 : function(workingDate, cell) {
  3001. Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT2);
  3002. },
  3003. /**
  3004. * Renders a single standard calendar cell using the CSS hightlight3 style
  3005. * @method renderCellStyleHighlight3
  3006. * @param {Date} workingDate The current working Date object being used to generate the calendar
  3007. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  3008. */
  3009. renderCellStyleHighlight3 : function(workingDate, cell) {
  3010. Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT3);
  3011. },
  3012. /**
  3013. * Renders a single standard calendar cell using the CSS hightlight4 style
  3014. * @method renderCellStyleHighlight4
  3015. * @param {Date} workingDate The current working Date object being used to generate the calendar
  3016. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  3017. */
  3018. renderCellStyleHighlight4 : function(workingDate, cell) {
  3019. Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT4);
  3020. },
  3021. /**
  3022. * Applies the default style used for rendering today's date to the current calendar cell
  3023. * @method renderCellStyleToday
  3024. * @param {Date} workingDate The current working Date object being used to generate the calendar
  3025. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  3026. */
  3027. renderCellStyleToday : function(workingDate, cell) {
  3028. Dom.addClass(cell, this.Style.CSS_CELL_TODAY);
  3029. },
  3030. /**
  3031. * Applies the default style used for rendering selected dates to the current calendar cell
  3032. * @method renderCellStyleSelected
  3033. * @param {Date} workingDate The current working Date object being used to generate the calendar
  3034. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  3035. * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
  3036. * should not be terminated
  3037. */
  3038. renderCellStyleSelected : function(workingDate, cell) {
  3039. Dom.addClass(cell, this.Style.CSS_CELL_SELECTED);
  3040. },
  3041. /**
  3042. * Applies the default style used for rendering dates that are not a part of the current
  3043. * month (preceding or trailing the cells for the current month)
  3044. * @method renderCellNotThisMonth
  3045. * @param {Date} workingDate The current working Date object being used to generate the calendar
  3046. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  3047. * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
  3048. * should not be terminated
  3049. */
  3050. renderCellNotThisMonth : function(workingDate, cell) {
  3051. Dom.addClass(cell, this.Style.CSS_CELL_OOM);
  3052. cell.innerHTML=workingDate.getDate();
  3053. return Calendar.STOP_RENDER;
  3054. },
  3055. /**
  3056. * Renders the current calendar cell as a non-selectable "black-out" date using the default
  3057. * restricted style.
  3058. * @method renderBodyCellRestricted
  3059. * @param {Date} workingDate The current working Date object being used to generate the calendar
  3060. * @param {HTMLTableCellElement} cell The current working cell in the calendar
  3061. * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
  3062. * should not be terminated
  3063. */
  3064. renderBodyCellRestricted : function(workingDate, cell) {
  3065. Dom.addClass(cell, this.Style.CSS_CELL);
  3066. Dom.addClass(cell, this.Style.CSS_CELL_RESTRICTED);
  3067. cell.innerHTML=workingDate.getDate();
  3068. return Calendar.STOP_RENDER;
  3069. },
  3070. // END BUILT-IN TABLE CELL RENDERERS
  3071. // BEGIN MONTH NAVIGATION METHODS
  3072. /**
  3073. * Adds the designated number of months to the current calendar month, and sets the current
  3074. * calendar page date to the new month.
  3075. * @method addMonths
  3076. * @param {Number} count The number of months to add to the current calendar
  3077. */
  3078. addMonths : function(count) {
  3079. var cfgPageDate = DEF_CFG.PAGEDATE.key;
  3080. this.cfg.setProperty(cfgPageDate, DateMath.add(this.cfg.getProperty(cfgPageDate), DateMath.MONTH, count));
  3081. this.resetRenderers();
  3082. this.changePageEvent.fire();
  3083. },
  3084. /**
  3085. * Subtracts the designated number of months from the current calendar month, and sets the current
  3086. * calendar page date to the new month.
  3087. * @method subtractMonths
  3088. * @param {Number} count The number of months to subtract from the current calendar
  3089. */
  3090. subtractMonths : function(count) {
  3091. var cfgPageDate = DEF_CFG.PAGEDATE.key;
  3092. this.cfg.setProperty(cfgPageDate, DateMath.subtract(this.cfg.getProperty(cfgPageDate), DateMath.MONTH, count));
  3093. this.resetRenderers();
  3094. this.changePageEvent.fire();
  3095. },
  3096. /**
  3097. * Adds the designated number of years to the current calendar, and sets the current
  3098. * calendar page date to the new month.
  3099. * @method addYears
  3100. * @param {Number} count The number of years to add to the current calendar
  3101. */
  3102. addYears : function(count) {
  3103. var cfgPageDate = DEF_CFG.PAGEDATE.key;
  3104. this.cfg.setProperty(cfgPageDate, DateMath.add(this.cfg.getProperty(cfgPageDate), DateMath.YEAR, count));
  3105. this.resetRenderers();
  3106. this.changePageEvent.fire();
  3107. },
  3108. /**
  3109. * Subtcats the designated number of years from the current calendar, and sets the current
  3110. * calendar page date to the new month.
  3111. * @method subtractYears
  3112. * @param {Number} count The number of years to subtract from the current calendar
  3113. */
  3114. subtractYears : function(count) {
  3115. var cfgPageDate = DEF_CFG.PAGEDATE.key;
  3116. this.cfg.setProperty(cfgPageDate, DateMath.subtract(this.cfg.getProperty(cfgPageDate), DateMath.YEAR, count));
  3117. this.resetRenderers();
  3118. this.changePageEvent.fire();
  3119. },
  3120. /**
  3121. * Navigates to the next month page in the calendar widget.
  3122. * @method nextMonth
  3123. */
  3124. nextMonth : function() {
  3125. this.addMonths(1);
  3126. },
  3127. /**
  3128. * Navigates to the previous month page in the calendar widget.
  3129. * @method previousMonth
  3130. */
  3131. previousMonth : function() {
  3132. this.subtractMonths(1);
  3133. },
  3134. /**
  3135. * Navigates to the next year in the currently selected month in the calendar widget.
  3136. * @method nextYear
  3137. */
  3138. nextYear : function() {
  3139. this.addYears(1);
  3140. },
  3141. /**
  3142. * Navigates to the previous year in the currently selected month in the calendar widget.
  3143. * @method previousYear
  3144. */
  3145. previousYear : function() {
  3146. this.subtractYears(1);
  3147. },
  3148. // END MONTH NAVIGATION METHODS
  3149. // BEGIN SELECTION METHODS
  3150. /**
  3151. * Resets the calendar widget to the originally selected month and year, and
  3152. * sets the calendar to the initial selection(s).
  3153. * @method reset
  3154. */
  3155. reset : function() {
  3156. this.cfg.resetProperty(DEF_CFG.SELECTED.key);
  3157. this.cfg.resetProperty(DEF_CFG.PAGEDATE.key);
  3158. this.resetEvent.fire();
  3159. },
  3160. /**
  3161. * Clears the selected dates in the current calendar widget and sets the calendar
  3162. * to the current month and year.
  3163. * @method clear
  3164. */
  3165. clear : function() {
  3166. this.cfg.setProperty(DEF_CFG.SELECTED.key, []);
  3167. this.cfg.setProperty(DEF_CFG.PAGEDATE.key, new Date(this.today.getTime()));
  3168. this.clearEvent.fire();
  3169. },
  3170. /**
  3171. * Selects a date or a collection of dates on the current calendar. This method, by default,
  3172. * does not call the render method explicitly. Once selection has completed, render must be
  3173. * called for the changes to be reflected visually.
  3174. *
  3175. * Any dates which are OOB (out of bounds, not selectable) will not be selected and the array of
  3176. * selected dates passed to the selectEvent will not contain OOB dates.
  3177. *
  3178. * If all dates are OOB, the no state change will occur; beforeSelect and select events will not be fired.
  3179. *
  3180. * @method select
  3181. * @param {String/Date/Date[]} date The date string of dates to select in the current calendar. Valid formats are
  3182. * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
  3183. * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
  3184. * This method can also take a JavaScript Date object or an array of Date objects.
  3185. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  3186. */
  3187. select : function(date) {
  3188. var aToBeSelected = this._toFieldArray(date),
  3189. validDates = [],
  3190. selected = [],
  3191. cfgSelected = DEF_CFG.SELECTED.key;
  3192. for (var a=0; a < aToBeSelected.length; ++a) {
  3193. var toSelect = aToBeSelected[a];
  3194. if (!this.isDateOOB(this._toDate(toSelect))) {
  3195. if (validDates.length === 0) {
  3196. this.beforeSelectEvent.fire();
  3197. selected = this.cfg.getProperty(cfgSelected);
  3198. }
  3199. validDates.push(toSelect);
  3200. if (this._indexOfSelectedFieldArray(toSelect) == -1) {
  3201. selected[selected.length] = toSelect;
  3202. }
  3203. }
  3204. }
  3205. if (validDates.length > 0) {
  3206. if (this.parent) {
  3207. this.parent.cfg.setProperty(cfgSelected, selected);
  3208. } else {
  3209. this.cfg.setProperty(cfgSelected, selected);
  3210. }
  3211. this.selectEvent.fire(validDates);
  3212. }
  3213. return this.getSelectedDates();
  3214. },
  3215. /**
  3216. * Selects a date on the current calendar by referencing the index of the cell that should be selected.
  3217. * This method is used to easily select a single cell (usually with a mouse click) without having to do
  3218. * a full render. The selected style is applied to the cell directly.
  3219. *
  3220. * If the cell is not marked with the CSS_CELL_SELECTABLE class (as is the case by default for out of month
  3221. * or out of bounds cells), it will not be selected and in such a case beforeSelect and select events will not be fired.
  3222. *
  3223. * @method selectCell
  3224. * @param {Number} cellIndex The index of the cell to select in the current calendar.
  3225. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  3226. */
  3227. selectCell : function(cellIndex) {
  3228. var cell = this.cells[cellIndex],
  3229. cellDate = this.cellDates[cellIndex],
  3230. dCellDate = this._toDate(cellDate),
  3231. selectable = Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
  3232. if (selectable) {
  3233. this.beforeSelectEvent.fire();
  3234. var cfgSelected = DEF_CFG.SELECTED.key;
  3235. var selected = this.cfg.getProperty(cfgSelected);
  3236. var selectDate = cellDate.concat();
  3237. if (this._indexOfSelectedFieldArray(selectDate) == -1) {
  3238. selected[selected.length] = selectDate;
  3239. }
  3240. if (this.parent) {
  3241. this.parent.cfg.setProperty(cfgSelected, selected);
  3242. } else {
  3243. this.cfg.setProperty(cfgSelected, selected);
  3244. }
  3245. this.renderCellStyleSelected(dCellDate,cell);
  3246. this.selectEvent.fire([selectDate]);
  3247. this.doCellMouseOut.call(cell, null, this);
  3248. }
  3249. return this.getSelectedDates();
  3250. },
  3251. /**
  3252. * Deselects a date or a collection of dates on the current calendar. This method, by default,
  3253. * does not call the render method explicitly. Once deselection has completed, render must be
  3254. * called for the changes to be reflected visually.
  3255. *
  3256. * The method will not attempt to deselect any dates which are OOB (out of bounds, and hence not selectable)
  3257. * and the array of deselected dates passed to the deselectEvent will not contain any OOB dates.
  3258. *
  3259. * If all dates are OOB, beforeDeselect and deselect events will not be fired.
  3260. *
  3261. * @method deselect
  3262. * @param {String/Date/Date[]} date The date string of dates to deselect in the current calendar. Valid formats are
  3263. * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
  3264. * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
  3265. * This method can also take a JavaScript Date object or an array of Date objects.
  3266. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  3267. */
  3268. deselect : function(date) {
  3269. var aToBeDeselected = this._toFieldArray(date),
  3270. validDates = [],
  3271. selected = [],
  3272. cfgSelected = DEF_CFG.SELECTED.key;
  3273. for (var a=0; a < aToBeDeselected.length; ++a) {
  3274. var toDeselect = aToBeDeselected[a];
  3275. if (!this.isDateOOB(this._toDate(toDeselect))) {
  3276. if (validDates.length === 0) {
  3277. this.beforeDeselectEvent.fire();
  3278. selected = this.cfg.getProperty(cfgSelected);
  3279. }
  3280. validDates.push(toDeselect);
  3281. var index = this._indexOfSelectedFieldArray(toDeselect);
  3282. if (index != -1) {
  3283. selected.splice(index,1);
  3284. }
  3285. }
  3286. }
  3287. if (validDates.length > 0) {
  3288. if (this.parent) {
  3289. this.parent.cfg.setProperty(cfgSelected, selected);
  3290. } else {
  3291. this.cfg.setProperty(cfgSelected, selected);
  3292. }
  3293. this.deselectEvent.fire(validDates);
  3294. }
  3295. return this.getSelectedDates();
  3296. },
  3297. /**
  3298. * Deselects a date on the current calendar by referencing the index of the cell that should be deselected.
  3299. * This method is used to easily deselect a single cell (usually with a mouse click) without having to do
  3300. * a full render. The selected style is removed from the cell directly.
  3301. *
  3302. * If the cell is not marked with the CSS_CELL_SELECTABLE class (as is the case by default for out of month
  3303. * or out of bounds cells), the method will not attempt to deselect it and in such a case, beforeDeselect and
  3304. * deselect events will not be fired.
  3305. *
  3306. * @method deselectCell
  3307. * @param {Number} cellIndex The index of the cell to deselect in the current calendar.
  3308. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  3309. */
  3310. deselectCell : function(cellIndex) {
  3311. var cell = this.cells[cellIndex],
  3312. cellDate = this.cellDates[cellIndex],
  3313. cellDateIndex = this._indexOfSelectedFieldArray(cellDate);
  3314. var selectable = Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
  3315. if (selectable) {
  3316. this.beforeDeselectEvent.fire();
  3317. var selected = this.cfg.getProperty(DEF_CFG.SELECTED.key),
  3318. dCellDate = this._toDate(cellDate),
  3319. selectDate = cellDate.concat();
  3320. if (cellDateIndex > -1) {
  3321. if (this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getMonth() == dCellDate.getMonth() &&
  3322. this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getFullYear() == dCellDate.getFullYear()) {
  3323. Dom.removeClass(cell, this.Style.CSS_CELL_SELECTED);
  3324. }
  3325. selected.splice(cellDateIndex, 1);
  3326. }
  3327. if (this.parent) {
  3328. this.parent.cfg.setProperty(DEF_CFG.SELECTED.key, selected);
  3329. } else {
  3330. this.cfg.setProperty(DEF_CFG.SELECTED.key, selected);
  3331. }
  3332. this.deselectEvent.fire([selectDate]);
  3333. }
  3334. return this.getSelectedDates();
  3335. },
  3336. /**
  3337. * Deselects all dates on the current calendar.
  3338. * @method deselectAll
  3339. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  3340. * Assuming that this function executes properly, the return value should be an empty array.
  3341. * However, the empty array is returned for the sake of being able to check the selection status
  3342. * of the calendar.
  3343. */
  3344. deselectAll : function() {
  3345. this.beforeDeselectEvent.fire();
  3346. var cfgSelected = DEF_CFG.SELECTED.key,
  3347. selected = this.cfg.getProperty(cfgSelected),
  3348. count = selected.length,
  3349. sel = selected.concat();
  3350. if (this.parent) {
  3351. this.parent.cfg.setProperty(cfgSelected, []);
  3352. } else {
  3353. this.cfg.setProperty(cfgSelected, []);
  3354. }
  3355. if (count > 0) {
  3356. this.deselectEvent.fire(sel);
  3357. }
  3358. return this.getSelectedDates();
  3359. },
  3360. // END SELECTION METHODS
  3361. // BEGIN TYPE CONVERSION METHODS
  3362. /**
  3363. * Converts a date (either a JavaScript Date object, or a date string) to the internal data structure
  3364. * used to represent dates: [[yyyy,mm,dd],[yyyy,mm,dd]].
  3365. * @method _toFieldArray
  3366. * @private
  3367. * @param {String/Date/Date[]} date The date string of dates to deselect in the current calendar. Valid formats are
  3368. * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
  3369. * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
  3370. * This method can also take a JavaScript Date object or an array of Date objects.
  3371. * @return {Array[](Number[])} Array of date field arrays
  3372. */
  3373. _toFieldArray : function(date) {
  3374. var returnDate = [];
  3375. if (date instanceof Date) {
  3376. returnDate = [[date.getFullYear(), date.getMonth()+1, date.getDate()]];
  3377. } else if (Lang.isString(date)) {
  3378. returnDate = this._parseDates(date);
  3379. } else if (Lang.isArray(date)) {
  3380. for (var i=0;i<date.length;++i) {
  3381. var d = date[i];
  3382. returnDate[returnDate.length] = [d.getFullYear(),d.getMonth()+1,d.getDate()];
  3383. }
  3384. }
  3385. return returnDate;
  3386. },
  3387. /**
  3388. * Converts a date field array [yyyy,mm,dd] to a JavaScript Date object. The date field array
  3389. * is the format in which dates are as provided as arguments to selectEvent and deselectEvent listeners.
  3390. *
  3391. * @method toDate
  3392. * @param {Number[]} dateFieldArray The date field array to convert to a JavaScript Date.
  3393. * @return {Date} JavaScript Date object representing the date field array.
  3394. */
  3395. toDate : function(dateFieldArray) {
  3396. return this._toDate(dateFieldArray);
  3397. },
  3398. /**
  3399. * Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
  3400. * @method _toDate
  3401. * @private
  3402. * @deprecated Made public, toDate
  3403. * @param {Number[]} dateFieldArray The date field array to convert to a JavaScript Date.
  3404. * @return {Date} JavaScript Date object representing the date field array
  3405. */
  3406. _toDate : function(dateFieldArray) {
  3407. if (dateFieldArray instanceof Date) {
  3408. return dateFieldArray;
  3409. } else {
  3410. return DateMath.getDate(dateFieldArray[0],dateFieldArray[1]-1,dateFieldArray[2]);
  3411. }
  3412. },
  3413. // END TYPE CONVERSION METHODS
  3414. // BEGIN UTILITY METHODS
  3415. /**
  3416. * Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
  3417. * @method _fieldArraysAreEqual
  3418. * @private
  3419. * @param {Number[]} array1 The first date field array to compare
  3420. * @param {Number[]} array2 The first date field array to compare
  3421. * @return {Boolean} The boolean that represents the equality of the two arrays
  3422. */
  3423. _fieldArraysAreEqual : function(array1, array2) {
  3424. var match = false;
  3425. if (array1[0]==array2[0]&&array1[1]==array2[1]&&array1[2]==array2[2]) {
  3426. match=true;
  3427. }
  3428. return match;
  3429. },
  3430. /**
  3431. * Gets the index of a date field array [yyyy,mm,dd] in the current list of selected dates.
  3432. * @method _indexOfSelectedFieldArray
  3433. * @private
  3434. * @param {Number[]} find The date field array to search for
  3435. * @return {Number} The index of the date field array within the collection of selected dates.
  3436. * -1 will be returned if the date is not found.
  3437. */
  3438. _indexOfSelectedFieldArray : function(find) {
  3439. var selected = -1,
  3440. seldates = this.cfg.getProperty(DEF_CFG.SELECTED.key);
  3441. for (var s=0;s<seldates.length;++s) {
  3442. var sArray = seldates[s];
  3443. if (find[0]==sArray[0]&&find[1]==sArray[1]&&find[2]==sArray[2]) {
  3444. selected = s;
  3445. break;
  3446. }
  3447. }
  3448. return selected;
  3449. },
  3450. /**
  3451. * Determines whether a given date is OOM (out of month).
  3452. * @method isDateOOM
  3453. * @param {Date} date The JavaScript Date object for which to check the OOM status
  3454. * @return {Boolean} true if the date is OOM
  3455. */
  3456. isDateOOM : function(date) {
  3457. return (date.getMonth() != this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getMonth());
  3458. },
  3459. /**
  3460. * Determines whether a given date is OOB (out of bounds - less than the mindate or more than the maxdate).
  3461. *
  3462. * @method isDateOOB
  3463. * @param {Date} date The JavaScript Date object for which to check the OOB status
  3464. * @return {Boolean} true if the date is OOB
  3465. */
  3466. isDateOOB : function(date) {
  3467. var minDate = this.cfg.getProperty(DEF_CFG.MINDATE.key),
  3468. maxDate = this.cfg.getProperty(DEF_CFG.MAXDATE.key),
  3469. dm = DateMath;
  3470. if (minDate) {
  3471. minDate = dm.clearTime(minDate);
  3472. }
  3473. if (maxDate) {
  3474. maxDate = dm.clearTime(maxDate);
  3475. }
  3476. var clearedDate = new Date(date.getTime());
  3477. clearedDate = dm.clearTime(clearedDate);
  3478. return ((minDate && clearedDate.getTime() < minDate.getTime()) || (maxDate && clearedDate.getTime() > maxDate.getTime()));
  3479. },
  3480. /**
  3481. * Parses a pagedate configuration property value. The value can either be specified as a string of form "mm/yyyy" or a Date object
  3482. * and is parsed into a Date object normalized to the first day of the month. If no value is passed in, the month and year from today's date are used to create the Date object
  3483. * @method _parsePageDate
  3484. * @private
  3485. * @param {Date|String} date Pagedate value which needs to be parsed
  3486. * @return {Date} The Date object representing the pagedate
  3487. */
  3488. _parsePageDate : function(date) {
  3489. var parsedDate;
  3490. if (date) {
  3491. if (date instanceof Date) {
  3492. parsedDate = DateMath.findMonthStart(date);
  3493. } else {
  3494. var month, year, aMonthYear;
  3495. aMonthYear = date.split(this.cfg.getProperty(DEF_CFG.DATE_FIELD_DELIMITER.key));
  3496. month = parseInt(aMonthYear[this.cfg.getProperty(DEF_CFG.MY_MONTH_POSITION.key)-1], 10)-1;
  3497. year = parseInt(aMonthYear[this.cfg.getProperty(DEF_CFG.MY_YEAR_POSITION.key)-1], 10);
  3498. parsedDate = DateMath.getDate(year, month, 1);
  3499. }
  3500. } else {
  3501. parsedDate = DateMath.getDate(this.today.getFullYear(), this.today.getMonth(), 1);
  3502. }
  3503. return parsedDate;
  3504. },
  3505. // END UTILITY METHODS
  3506. // BEGIN EVENT HANDLERS
  3507. /**
  3508. * Event executed before a date is selected in the calendar widget.
  3509. * @deprecated Event handlers for this event should be susbcribed to beforeSelectEvent.
  3510. */
  3511. onBeforeSelect : function() {
  3512. if (this.cfg.getProperty(DEF_CFG.MULTI_SELECT.key) === false) {
  3513. if (this.parent) {
  3514. this.parent.callChildFunction("clearAllBodyCellStyles", this.Style.CSS_CELL_SELECTED);
  3515. this.parent.deselectAll();
  3516. } else {
  3517. this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);
  3518. this.deselectAll();
  3519. }
  3520. }
  3521. },
  3522. /**
  3523. * Event executed when a date is selected in the calendar widget.
  3524. * @param {Array} selected An array of date field arrays representing which date or dates were selected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
  3525. * @deprecated Event handlers for this event should be susbcribed to selectEvent.
  3526. */
  3527. onSelect : function(selected) { },
  3528. /**
  3529. * Event executed before a date is deselected in the calendar widget.
  3530. * @deprecated Event handlers for this event should be susbcribed to beforeDeselectEvent.
  3531. */
  3532. onBeforeDeselect : function() { },
  3533. /**
  3534. * Event executed when a date is deselected in the calendar widget.
  3535. * @param {Array} selected An array of date field arrays representing which date or dates were deselected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
  3536. * @deprecated Event handlers for this event should be susbcribed to deselectEvent.
  3537. */
  3538. onDeselect : function(deselected) { },
  3539. /**
  3540. * Event executed when the user navigates to a different calendar page.
  3541. * @deprecated Event handlers for this event should be susbcribed to changePageEvent.
  3542. */
  3543. onChangePage : function() {
  3544. this.render();
  3545. },
  3546. /**
  3547. * Event executed when the calendar widget is rendered.
  3548. * @deprecated Event handlers for this event should be susbcribed to renderEvent.
  3549. */
  3550. onRender : function() { },
  3551. /**
  3552. * Event executed when the calendar widget is reset to its original state.
  3553. * @deprecated Event handlers for this event should be susbcribed to resetEvemt.
  3554. */
  3555. onReset : function() { this.render(); },
  3556. /**
  3557. * Event executed when the calendar widget is completely cleared to the current month with no selections.
  3558. * @deprecated Event handlers for this event should be susbcribed to clearEvent.
  3559. */
  3560. onClear : function() { this.render(); },
  3561. /**
  3562. * Validates the calendar widget. This method has no default implementation
  3563. * and must be extended by subclassing the widget.
  3564. * @return Should return true if the widget validates, and false if
  3565. * it doesn't.
  3566. * @type Boolean
  3567. */
  3568. validate : function() { return true; },
  3569. // END EVENT HANDLERS
  3570. // BEGIN DATE PARSE METHODS
  3571. /**
  3572. * Converts a date string to a date field array
  3573. * @private
  3574. * @param {String} sDate Date string. Valid formats are mm/dd and mm/dd/yyyy.
  3575. * @return A date field array representing the string passed to the method
  3576. * @type Array[](Number[])
  3577. */
  3578. _parseDate : function(sDate) {
  3579. var aDate = sDate.split(this.Locale.DATE_FIELD_DELIMITER),
  3580. rArray;
  3581. if (aDate.length == 2) {
  3582. rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
  3583. rArray.type = Calendar.MONTH_DAY;
  3584. } else {
  3585. rArray = [aDate[this.Locale.MDY_YEAR_POSITION-1],aDate[this.Locale.MDY_MONTH_POSITION-1],aDate[this.Locale.MDY_DAY_POSITION-1]];
  3586. rArray.type = Calendar.DATE;
  3587. }
  3588. for (var i=0;i<rArray.length;i++) {
  3589. rArray[i] = parseInt(rArray[i], 10);
  3590. }
  3591. return rArray;
  3592. },
  3593. /**
  3594. * Converts a multi or single-date string to an array of date field arrays
  3595. * @private
  3596. * @param {String} sDates Date string with one or more comma-delimited dates. Valid formats are mm/dd, mm/dd/yyyy, mm/dd/yyyy-mm/dd/yyyy
  3597. * @return An array of date field arrays
  3598. * @type Array[](Number[])
  3599. */
  3600. _parseDates : function(sDates) {
  3601. var aReturn = [],
  3602. aDates = sDates.split(this.Locale.DATE_DELIMITER);
  3603. for (var d=0;d<aDates.length;++d) {
  3604. var sDate = aDates[d];
  3605. if (sDate.indexOf(this.Locale.DATE_RANGE_DELIMITER) != -1) {
  3606. // This is a range
  3607. var aRange = sDate.split(this.Locale.DATE_RANGE_DELIMITER),
  3608. dateStart = this._parseDate(aRange[0]),
  3609. dateEnd = this._parseDate(aRange[1]),
  3610. fullRange = this._parseRange(dateStart, dateEnd);
  3611. aReturn = aReturn.concat(fullRange);
  3612. } else {
  3613. // This is not a range
  3614. var aDate = this._parseDate(sDate);
  3615. aReturn.push(aDate);
  3616. }
  3617. }
  3618. return aReturn;
  3619. },
  3620. /**
  3621. * Converts a date range to the full list of included dates
  3622. * @private
  3623. * @param {Number[]} startDate Date field array representing the first date in the range
  3624. * @param {Number[]} endDate Date field array representing the last date in the range
  3625. * @return An array of date field arrays
  3626. * @type Array[](Number[])
  3627. */
  3628. _parseRange : function(startDate, endDate) {
  3629. var dCurrent = DateMath.add(DateMath.getDate(startDate[0],startDate[1]-1,startDate[2]),DateMath.DAY,1),
  3630. dEnd = DateMath.getDate(endDate[0], endDate[1]-1, endDate[2]),
  3631. results = [];
  3632. results.push(startDate);
  3633. while (dCurrent.getTime() <= dEnd.getTime()) {
  3634. results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
  3635. dCurrent = DateMath.add(dCurrent,DateMath.DAY,1);
  3636. }
  3637. return results;
  3638. },
  3639. // END DATE PARSE METHODS
  3640. // BEGIN RENDERER METHODS
  3641. /**
  3642. * Resets the render stack of the current calendar to its original pre-render value.
  3643. */
  3644. resetRenderers : function() {
  3645. this.renderStack = this._renderStack.concat();
  3646. },
  3647. /**
  3648. * Removes all custom renderers added to the Calendar through the addRenderer, addMonthRenderer and
  3649. * addWeekdayRenderer methods. Calendar's render method needs to be called after removing renderers
  3650. * to re-render the Calendar without custom renderers applied.
  3651. */
  3652. removeRenderers : function() {
  3653. this._renderStack = [];
  3654. this.renderStack = [];
  3655. },
  3656. /**
  3657. * Clears the inner HTML, CSS class and style information from the specified cell.
  3658. * @method clearElement
  3659. * @param {HTMLTableCellElement} cell The cell to clear
  3660. */
  3661. clearElement : function(cell) {
  3662. cell.innerHTML = "&#160;";
  3663. cell.className="";
  3664. },
  3665. /**
  3666. * Adds a renderer to the render stack. The function reference passed to this method will be executed
  3667. * when a date cell matches the conditions specified in the date string for this renderer.
  3668. * @method addRenderer
  3669. * @param {String} sDates A date string to associate with the specified renderer. Valid formats
  3670. * include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
  3671. * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
  3672. */
  3673. addRenderer : function(sDates, fnRender) {
  3674. var aDates = this._parseDates(sDates);
  3675. for (var i=0;i<aDates.length;++i) {
  3676. var aDate = aDates[i];
  3677. if (aDate.length == 2) { // this is either a range or a month/day combo
  3678. if (aDate[0] instanceof Array) { // this is a range
  3679. this._addRenderer(Calendar.RANGE,aDate,fnRender);
  3680. } else { // this is a month/day combo
  3681. this._addRenderer(Calendar.MONTH_DAY,aDate,fnRender);
  3682. }
  3683. } else if (aDate.length == 3) {
  3684. this._addRenderer(Calendar.DATE,aDate,fnRender);
  3685. }
  3686. }
  3687. },
  3688. /**
  3689. * The private method used for adding cell renderers to the local render stack.
  3690. * This method is called by other methods that set the renderer type prior to the method call.
  3691. * @method _addRenderer
  3692. * @private
  3693. * @param {String} type The type string that indicates the type of date renderer being added.
  3694. * Values are YAHOO.widget.Calendar.DATE, YAHOO.widget.Calendar.MONTH_DAY, YAHOO.widget.Calendar.WEEKDAY,
  3695. * YAHOO.widget.Calendar.RANGE, YAHOO.widget.Calendar.MONTH
  3696. * @param {Array} aDates An array of dates used to construct the renderer. The format varies based
  3697. * on the renderer type
  3698. * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
  3699. */
  3700. _addRenderer : function(type, aDates, fnRender) {
  3701. var add = [type,aDates,fnRender];
  3702. this.renderStack.unshift(add);
  3703. this._renderStack = this.renderStack.concat();
  3704. },
  3705. /**
  3706. * Adds a month to the render stack. The function reference passed to this method will be executed
  3707. * when a date cell matches the month passed to this method.
  3708. * @method addMonthRenderer
  3709. * @param {Number} month The month (1-12) to associate with this renderer
  3710. * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
  3711. */
  3712. addMonthRenderer : function(month, fnRender) {
  3713. this._addRenderer(Calendar.MONTH,[month],fnRender);
  3714. },
  3715. /**
  3716. * Adds a weekday to the render stack. The function reference passed to this method will be executed
  3717. * when a date cell matches the weekday passed to this method.
  3718. * @method addWeekdayRenderer
  3719. * @param {Number} weekday The weekday (Sunday = 1, Monday = 2 ... Saturday = 7) to associate with this renderer
  3720. * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
  3721. */
  3722. addWeekdayRenderer : function(weekday, fnRender) {
  3723. this._addRenderer(Calendar.WEEKDAY,[weekday],fnRender);
  3724. },
  3725. // END RENDERER METHODS
  3726. // BEGIN CSS METHODS
  3727. /**
  3728. * Removes all styles from all body cells in the current calendar table.
  3729. * @method clearAllBodyCellStyles
  3730. * @param {style} style The CSS class name to remove from all calendar body cells
  3731. */
  3732. clearAllBodyCellStyles : function(style) {
  3733. for (var c=0;c<this.cells.length;++c) {
  3734. Dom.removeClass(this.cells[c],style);
  3735. }
  3736. },
  3737. // END CSS METHODS
  3738. // BEGIN GETTER/SETTER METHODS
  3739. /**
  3740. * Sets the calendar's month explicitly
  3741. * @method setMonth
  3742. * @param {Number} month The numeric month, from 0 (January) to 11 (December)
  3743. */
  3744. setMonth : function(month) {
  3745. var cfgPageDate = DEF_CFG.PAGEDATE.key,
  3746. current = this.cfg.getProperty(cfgPageDate);
  3747. current.setMonth(parseInt(month, 10));
  3748. this.cfg.setProperty(cfgPageDate, current);
  3749. },
  3750. /**
  3751. * Sets the calendar's year explicitly.
  3752. * @method setYear
  3753. * @param {Number} year The numeric 4-digit year
  3754. */
  3755. setYear : function(year) {
  3756. var cfgPageDate = DEF_CFG.PAGEDATE.key,
  3757. current = this.cfg.getProperty(cfgPageDate);
  3758. current.setFullYear(parseInt(year, 10));
  3759. this.cfg.setProperty(cfgPageDate, current);
  3760. },
  3761. /**
  3762. * Gets the list of currently selected dates from the calendar.
  3763. * @method getSelectedDates
  3764. * @return {Date[]} An array of currently selected JavaScript Date objects.
  3765. */
  3766. getSelectedDates : function() {
  3767. var returnDates = [],
  3768. selected = this.cfg.getProperty(DEF_CFG.SELECTED.key);
  3769. for (var d=0;d<selected.length;++d) {
  3770. var dateArray = selected[d];
  3771. var date = DateMath.getDate(dateArray[0],dateArray[1]-1,dateArray[2]);
  3772. returnDates.push(date);
  3773. }
  3774. returnDates.sort( function(a,b) { return a-b; } );
  3775. return returnDates;
  3776. },
  3777. /// END GETTER/SETTER METHODS ///
  3778. /**
  3779. * Hides the Calendar's outer container from view.
  3780. * @method hide
  3781. */
  3782. hide : function() {
  3783. if (this.beforeHideEvent.fire()) {
  3784. this.oDomContainer.style.display = "none";
  3785. this.hideEvent.fire();
  3786. }
  3787. },
  3788. /**
  3789. * Shows the Calendar's outer container.
  3790. * @method show
  3791. */
  3792. show : function() {
  3793. if (this.beforeShowEvent.fire()) {
  3794. this.oDomContainer.style.display = "block";
  3795. this.showEvent.fire();
  3796. }
  3797. },
  3798. /**
  3799. * Returns a string representing the current browser.
  3800. * @deprecated As of 2.3.0, environment information is available in YAHOO.env.ua
  3801. * @see YAHOO.env.ua
  3802. * @property browser
  3803. * @type String
  3804. */
  3805. browser : (function() {
  3806. var ua = navigator.userAgent.toLowerCase();
  3807. if (ua.indexOf('opera')!=-1) { // Opera (check first in case of spoof)
  3808. return 'opera';
  3809. } else if (ua.indexOf('msie 7')!=-1) { // IE7
  3810. return 'ie7';
  3811. } else if (ua.indexOf('msie') !=-1) { // IE
  3812. return 'ie';
  3813. } else if (ua.indexOf('safari')!=-1) { // Safari (check before Gecko because it includes "like Gecko")
  3814. return 'safari';
  3815. } else if (ua.indexOf('gecko') != -1) { // Gecko
  3816. return 'gecko';
  3817. } else {
  3818. return false;
  3819. }
  3820. })(),
  3821. /**
  3822. * Returns a string representation of the object.
  3823. * @method toString
  3824. * @return {String} A string representation of the Calendar object.
  3825. */
  3826. toString : function() {
  3827. return "Calendar " + this.id;
  3828. },
  3829. /**
  3830. * Destroys the Calendar instance. The method will remove references
  3831. * to HTML elements, remove any event listeners added by the Calendar,
  3832. * and destroy the Config and CalendarNavigator instances it has created.
  3833. *
  3834. * @method destroy
  3835. */
  3836. destroy : function() {
  3837. if (this.beforeDestroyEvent.fire()) {
  3838. var cal = this;
  3839. // Child objects
  3840. if (cal.navigator) {
  3841. cal.navigator.destroy();
  3842. }
  3843. if (cal.cfg) {
  3844. cal.cfg.destroy();
  3845. }
  3846. // DOM event listeners
  3847. Event.purgeElement(cal.oDomContainer, true);
  3848. // Generated markup/DOM - Not removing the container DIV since we didn't create it.
  3849. Dom.removeClass(cal.oDomContainer, "withtitle");
  3850. Dom.removeClass(cal.oDomContainer, cal.Style.CSS_CONTAINER);
  3851. Dom.removeClass(cal.oDomContainer, cal.Style.CSS_SINGLE);
  3852. cal.oDomContainer.innerHTML = "";
  3853. // JS-to-DOM references
  3854. cal.oDomContainer = null;
  3855. cal.cells = null;
  3856. this.destroyEvent.fire();
  3857. }
  3858. }
  3859. };
  3860. YAHOO.widget.Calendar = Calendar;
  3861. /**
  3862. * @namespace YAHOO.widget
  3863. * @class Calendar_Core
  3864. * @extends YAHOO.widget.Calendar
  3865. * @deprecated The old Calendar_Core class is no longer necessary.
  3866. */
  3867. YAHOO.widget.Calendar_Core = YAHOO.widget.Calendar;
  3868. YAHOO.widget.Cal_Core = YAHOO.widget.Calendar;
  3869. })();
  3870. (function() {
  3871. var Dom = YAHOO.util.Dom,
  3872. DateMath = YAHOO.widget.DateMath,
  3873. Event = YAHOO.util.Event,
  3874. Lang = YAHOO.lang,
  3875. Calendar = YAHOO.widget.Calendar;
  3876. /**
  3877. * YAHOO.widget.CalendarGroup is a special container class for YAHOO.widget.Calendar. This class facilitates
  3878. * the ability to have multi-page calendar views that share a single dataset and are
  3879. * dependent on each other.
  3880. *
  3881. * The calendar group instance will refer to each of its elements using a 0-based index.
  3882. * For example, to construct the placeholder for a calendar group widget with id "cal1" and
  3883. * containerId of "cal1Container", the markup would be as follows:
  3884. * <xmp>
  3885. * <div id="cal1Container_0"></div>
  3886. * <div id="cal1Container_1"></div>
  3887. * </xmp>
  3888. * The tables for the calendars ("cal1_0" and "cal1_1") will be inserted into those containers.
  3889. *
  3890. * <p>
  3891. * <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
  3892. * The CalendarGroup can be constructed by simply providing a container ID string,
  3893. * or a reference to a container DIV HTMLElement (the element needs to exist
  3894. * in the document).
  3895. *
  3896. * E.g.:
  3897. * <xmp>
  3898. * var c = new YAHOO.widget.CalendarGroup("calContainer", configOptions);
  3899. * </xmp>
  3900. * or:
  3901. * <xmp>
  3902. * var containerDiv = YAHOO.util.Dom.get("calContainer");
  3903. * var c = new YAHOO.widget.CalendarGroup(containerDiv, configOptions);
  3904. * </xmp>
  3905. * </p>
  3906. * <p>
  3907. * If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
  3908. * For example if an ID is not provided, and the container's ID is "calContainer", the CalendarGroup's ID will be set to "calContainer_t".
  3909. * </p>
  3910. *
  3911. * @namespace YAHOO.widget
  3912. * @class CalendarGroup
  3913. * @constructor
  3914. * @param {String} id optional The id of the table element that will represent the CalendarGroup widget. As of 2.4.0, this argument is optional.
  3915. * @param {String | HTMLElement} container The id of the container div element that will wrap the CalendarGroup table, or a reference to a DIV element which exists in the document.
  3916. * @param {Object} config optional The configuration object containing the initial configuration values for the CalendarGroup.
  3917. */
  3918. function CalendarGroup(id, containerId, config) {
  3919. if (arguments.length > 0) {
  3920. this.init.apply(this, arguments);
  3921. }
  3922. }
  3923. /**
  3924. * The set of default Config property keys and values for the CalendarGroup
  3925. * @property YAHOO.widget.CalendarGroup._DEFAULT_CONFIG
  3926. * @final
  3927. * @static
  3928. * @private
  3929. * @type Object
  3930. */
  3931. CalendarGroup._DEFAULT_CONFIG = Calendar._DEFAULT_CONFIG;
  3932. CalendarGroup._DEFAULT_CONFIG.PAGES = {key:"pages", value:2};
  3933. var DEF_CFG = CalendarGroup._DEFAULT_CONFIG;
  3934. CalendarGroup.prototype = {
  3935. /**
  3936. * Initializes the calendar group. All subclasses must call this method in order for the
  3937. * group to be initialized properly.
  3938. * @method init
  3939. * @param {String} id optional The id of the table element that will represent the CalendarGroup widget. As of 2.4.0, this argument is optional.
  3940. * @param {String | HTMLElement} container The id of the container div element that will wrap the CalendarGroup table, or a reference to a DIV element which exists in the document.
  3941. * @param {Object} config optional The configuration object containing the initial configuration values for the CalendarGroup.
  3942. */
  3943. init : function(id, container, config) {
  3944. // Normalize 2.4.0, pre 2.4.0 args
  3945. var nArgs = this._parseArgs(arguments);
  3946. id = nArgs.id;
  3947. container = nArgs.container;
  3948. config = nArgs.config;
  3949. this.oDomContainer = Dom.get(container);
  3950. if (!this.oDomContainer.id) {
  3951. this.oDomContainer.id = Dom.generateId();
  3952. }
  3953. if (!id) {
  3954. id = this.oDomContainer.id + "_t";
  3955. }
  3956. /**
  3957. * The unique id associated with the CalendarGroup
  3958. * @property id
  3959. * @type String
  3960. */
  3961. this.id = id;
  3962. /**
  3963. * The unique id associated with the CalendarGroup container
  3964. * @property containerId
  3965. * @type String
  3966. */
  3967. this.containerId = this.oDomContainer.id;
  3968. this.initEvents();
  3969. this.initStyles();
  3970. /**
  3971. * The collection of Calendar pages contained within the CalendarGroup
  3972. * @property pages
  3973. * @type YAHOO.widget.Calendar[]
  3974. */
  3975. this.pages = [];
  3976. Dom.addClass(this.oDomContainer, CalendarGroup.CSS_CONTAINER);
  3977. Dom.addClass(this.oDomContainer, CalendarGroup.CSS_MULTI_UP);
  3978. /**
  3979. * The Config object used to hold the configuration variables for the CalendarGroup
  3980. * @property cfg
  3981. * @type YAHOO.util.Config
  3982. */
  3983. this.cfg = new YAHOO.util.Config(this);
  3984. /**
  3985. * The local object which contains the CalendarGroup's options
  3986. * @property Options
  3987. * @type Object
  3988. */
  3989. this.Options = {};
  3990. /**
  3991. * The local object which contains the CalendarGroup's locale settings
  3992. * @property Locale
  3993. * @type Object
  3994. */
  3995. this.Locale = {};
  3996. this.setupConfig();
  3997. if (config) {
  3998. this.cfg.applyConfig(config, true);
  3999. }
  4000. this.cfg.fireQueue();
  4001. // OPERA HACK FOR MISWRAPPED FLOATS
  4002. if (YAHOO.env.ua.opera){
  4003. this.renderEvent.subscribe(this._fixWidth, this, true);
  4004. this.showEvent.subscribe(this._fixWidth, this, true);
  4005. }
  4006. },
  4007. setupConfig : function() {
  4008. var cfg = this.cfg;
  4009. /**
  4010. * The number of pages to include in the CalendarGroup. This value can only be set once, in the CalendarGroup's constructor arguments.
  4011. * @config pages
  4012. * @type Number
  4013. * @default 2
  4014. */
  4015. cfg.addProperty(DEF_CFG.PAGES.key, { value:DEF_CFG.PAGES.value, validator:cfg.checkNumber, handler:this.configPages } );
  4016. /**
  4017. * The month/year representing the current visible Calendar date (mm/yyyy)
  4018. * @config pagedate
  4019. * @type String | Date
  4020. * @default today's date
  4021. */
  4022. cfg.addProperty(DEF_CFG.PAGEDATE.key, { value:new Date(), handler:this.configPageDate } );
  4023. /**
  4024. * The date or range of dates representing the current Calendar selection
  4025. *
  4026. * @config selected
  4027. * @type String
  4028. * @default []
  4029. */
  4030. cfg.addProperty(DEF_CFG.SELECTED.key, { value:[], handler:this.configSelected } );
  4031. /**
  4032. * The title to display above the CalendarGroup's month header
  4033. * @config title
  4034. * @type String
  4035. * @default ""
  4036. */
  4037. cfg.addProperty(DEF_CFG.TITLE.key, { value:DEF_CFG.TITLE.value, handler:this.configTitle } );
  4038. /**
  4039. * Whether or not a close button should be displayed for this CalendarGroup
  4040. * @config close
  4041. * @type Boolean
  4042. * @default false
  4043. */
  4044. cfg.addProperty(DEF_CFG.CLOSE.key, { value:DEF_CFG.CLOSE.value, handler:this.configClose } );
  4045. /**
  4046. * Whether or not an iframe shim should be placed under the Calendar to prevent select boxes from bleeding through in Internet Explorer 6 and below.
  4047. * This property is enabled by default for IE6 and below. It is disabled by default for other browsers for performance reasons, but can be
  4048. * enabled if required.
  4049. *
  4050. * @config iframe
  4051. * @type Boolean
  4052. * @default true for IE6 and below, false for all other browsers
  4053. */
  4054. cfg.addProperty(DEF_CFG.IFRAME.key, { value:DEF_CFG.IFRAME.value, handler:this.configIframe, validator:cfg.checkBoolean } );
  4055. /**
  4056. * The minimum selectable date in the current Calendar (mm/dd/yyyy)
  4057. * @config mindate
  4058. * @type String | Date
  4059. * @default null
  4060. */
  4061. cfg.addProperty(DEF_CFG.MINDATE.key, { value:DEF_CFG.MINDATE.value, handler:this.delegateConfig } );
  4062. /**
  4063. * The maximum selectable date in the current Calendar (mm/dd/yyyy)
  4064. * @config maxdate
  4065. * @type String | Date
  4066. * @default null
  4067. */
  4068. cfg.addProperty(DEF_CFG.MAXDATE.key, { value:DEF_CFG.MAXDATE.value, handler:this.delegateConfig } );
  4069. // Options properties
  4070. /**
  4071. * True if the Calendar should allow multiple selections. False by default.
  4072. * @config MULTI_SELECT
  4073. * @type Boolean
  4074. * @default false
  4075. */
  4076. cfg.addProperty(DEF_CFG.MULTI_SELECT.key, { value:DEF_CFG.MULTI_SELECT.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
  4077. /**
  4078. * The weekday the week begins on. Default is 0 (Sunday).
  4079. * @config START_WEEKDAY
  4080. * @type number
  4081. * @default 0
  4082. */
  4083. cfg.addProperty(DEF_CFG.START_WEEKDAY.key, { value:DEF_CFG.START_WEEKDAY.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4084. /**
  4085. * True if the Calendar should show weekday labels. True by default.
  4086. * @config SHOW_WEEKDAYS
  4087. * @type Boolean
  4088. * @default true
  4089. */
  4090. cfg.addProperty(DEF_CFG.SHOW_WEEKDAYS.key, { value:DEF_CFG.SHOW_WEEKDAYS.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
  4091. /**
  4092. * True if the Calendar should show week row headers. False by default.
  4093. * @config SHOW_WEEK_HEADER
  4094. * @type Boolean
  4095. * @default false
  4096. */
  4097. cfg.addProperty(DEF_CFG.SHOW_WEEK_HEADER.key,{ value:DEF_CFG.SHOW_WEEK_HEADER.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
  4098. /**
  4099. * True if the Calendar should show week row footers. False by default.
  4100. * @config SHOW_WEEK_FOOTER
  4101. * @type Boolean
  4102. * @default false
  4103. */
  4104. cfg.addProperty(DEF_CFG.SHOW_WEEK_FOOTER.key,{ value:DEF_CFG.SHOW_WEEK_FOOTER.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
  4105. /**
  4106. * True if the Calendar should suppress weeks that are not a part of the current month. False by default.
  4107. * @config HIDE_BLANK_WEEKS
  4108. * @type Boolean
  4109. * @default false
  4110. */
  4111. cfg.addProperty(DEF_CFG.HIDE_BLANK_WEEKS.key,{ value:DEF_CFG.HIDE_BLANK_WEEKS.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
  4112. /**
  4113. * The image that should be used for the left navigation arrow.
  4114. * @config NAV_ARROW_LEFT
  4115. * @type String
  4116. * @deprecated You can customize the image by overriding the default CSS class for the left arrow - "calnavleft"
  4117. * @default null
  4118. */
  4119. cfg.addProperty(DEF_CFG.NAV_ARROW_LEFT.key, { value:DEF_CFG.NAV_ARROW_LEFT.value, handler:this.delegateConfig } );
  4120. /**
  4121. * The image that should be used for the right navigation arrow.
  4122. * @config NAV_ARROW_RIGHT
  4123. * @type String
  4124. * @deprecated You can customize the image by overriding the default CSS class for the right arrow - "calnavright"
  4125. * @default null
  4126. */
  4127. cfg.addProperty(DEF_CFG.NAV_ARROW_RIGHT.key, { value:DEF_CFG.NAV_ARROW_RIGHT.value, handler:this.delegateConfig } );
  4128. // Locale properties
  4129. /**
  4130. * The short month labels for the current locale.
  4131. * @config MONTHS_SHORT
  4132. * @type String[]
  4133. * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  4134. */
  4135. cfg.addProperty(DEF_CFG.MONTHS_SHORT.key, { value:DEF_CFG.MONTHS_SHORT.value, handler:this.delegateConfig } );
  4136. /**
  4137. * The long month labels for the current locale.
  4138. * @config MONTHS_LONG
  4139. * @type String[]
  4140. * @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
  4141. */
  4142. cfg.addProperty(DEF_CFG.MONTHS_LONG.key, { value:DEF_CFG.MONTHS_LONG.value, handler:this.delegateConfig } );
  4143. /**
  4144. * The 1-character weekday labels for the current locale.
  4145. * @config WEEKDAYS_1CHAR
  4146. * @type String[]
  4147. * @default ["S", "M", "T", "W", "T", "F", "S"]
  4148. */
  4149. cfg.addProperty(DEF_CFG.WEEKDAYS_1CHAR.key, { value:DEF_CFG.WEEKDAYS_1CHAR.value, handler:this.delegateConfig } );
  4150. /**
  4151. * The short weekday labels for the current locale.
  4152. * @config WEEKDAYS_SHORT
  4153. * @type String[]
  4154. * @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
  4155. */
  4156. cfg.addProperty(DEF_CFG.WEEKDAYS_SHORT.key, { value:DEF_CFG.WEEKDAYS_SHORT.value, handler:this.delegateConfig } );
  4157. /**
  4158. * The medium weekday labels for the current locale.
  4159. * @config WEEKDAYS_MEDIUM
  4160. * @type String[]
  4161. * @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
  4162. */
  4163. cfg.addProperty(DEF_CFG.WEEKDAYS_MEDIUM.key, { value:DEF_CFG.WEEKDAYS_MEDIUM.value, handler:this.delegateConfig } );
  4164. /**
  4165. * The long weekday labels for the current locale.
  4166. * @config WEEKDAYS_LONG
  4167. * @type String[]
  4168. * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
  4169. */
  4170. cfg.addProperty(DEF_CFG.WEEKDAYS_LONG.key, { value:DEF_CFG.WEEKDAYS_LONG.value, handler:this.delegateConfig } );
  4171. /**
  4172. * The setting that determines which length of month labels should be used. Possible values are "short" and "long".
  4173. * @config LOCALE_MONTHS
  4174. * @type String
  4175. * @default "long"
  4176. */
  4177. cfg.addProperty(DEF_CFG.LOCALE_MONTHS.key, { value:DEF_CFG.LOCALE_MONTHS.value, handler:this.delegateConfig } );
  4178. /**
  4179. * The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
  4180. * @config LOCALE_WEEKDAYS
  4181. * @type String
  4182. * @default "short"
  4183. */
  4184. cfg.addProperty(DEF_CFG.LOCALE_WEEKDAYS.key, { value:DEF_CFG.LOCALE_WEEKDAYS.value, handler:this.delegateConfig } );
  4185. /**
  4186. * The value used to delimit individual dates in a date string passed to various Calendar functions.
  4187. * @config DATE_DELIMITER
  4188. * @type String
  4189. * @default ","
  4190. */
  4191. cfg.addProperty(DEF_CFG.DATE_DELIMITER.key, { value:DEF_CFG.DATE_DELIMITER.value, handler:this.delegateConfig } );
  4192. /**
  4193. * The value used to delimit date fields in a date string passed to various Calendar functions.
  4194. * @config DATE_FIELD_DELIMITER
  4195. * @type String
  4196. * @default "/"
  4197. */
  4198. cfg.addProperty(DEF_CFG.DATE_FIELD_DELIMITER.key,{ value:DEF_CFG.DATE_FIELD_DELIMITER.value, handler:this.delegateConfig } );
  4199. /**
  4200. * The value used to delimit date ranges in a date string passed to various Calendar functions.
  4201. * @config DATE_RANGE_DELIMITER
  4202. * @type String
  4203. * @default "-"
  4204. */
  4205. cfg.addProperty(DEF_CFG.DATE_RANGE_DELIMITER.key,{ value:DEF_CFG.DATE_RANGE_DELIMITER.value, handler:this.delegateConfig } );
  4206. /**
  4207. * The position of the month in a month/year date string
  4208. * @config MY_MONTH_POSITION
  4209. * @type Number
  4210. * @default 1
  4211. */
  4212. cfg.addProperty(DEF_CFG.MY_MONTH_POSITION.key, { value:DEF_CFG.MY_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4213. /**
  4214. * The position of the year in a month/year date string
  4215. * @config MY_YEAR_POSITION
  4216. * @type Number
  4217. * @default 2
  4218. */
  4219. cfg.addProperty(DEF_CFG.MY_YEAR_POSITION.key, { value:DEF_CFG.MY_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4220. /**
  4221. * The position of the month in a month/day date string
  4222. * @config MD_MONTH_POSITION
  4223. * @type Number
  4224. * @default 1
  4225. */
  4226. cfg.addProperty(DEF_CFG.MD_MONTH_POSITION.key, { value:DEF_CFG.MD_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4227. /**
  4228. * The position of the day in a month/year date string
  4229. * @config MD_DAY_POSITION
  4230. * @type Number
  4231. * @default 2
  4232. */
  4233. cfg.addProperty(DEF_CFG.MD_DAY_POSITION.key, { value:DEF_CFG.MD_DAY_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4234. /**
  4235. * The position of the month in a month/day/year date string
  4236. * @config MDY_MONTH_POSITION
  4237. * @type Number
  4238. * @default 1
  4239. */
  4240. cfg.addProperty(DEF_CFG.MDY_MONTH_POSITION.key, { value:DEF_CFG.MDY_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4241. /**
  4242. * The position of the day in a month/day/year date string
  4243. * @config MDY_DAY_POSITION
  4244. * @type Number
  4245. * @default 2
  4246. */
  4247. cfg.addProperty(DEF_CFG.MDY_DAY_POSITION.key, { value:DEF_CFG.MDY_DAY_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4248. /**
  4249. * The position of the year in a month/day/year date string
  4250. * @config MDY_YEAR_POSITION
  4251. * @type Number
  4252. * @default 3
  4253. */
  4254. cfg.addProperty(DEF_CFG.MDY_YEAR_POSITION.key, { value:DEF_CFG.MDY_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4255. /**
  4256. * The position of the month in the month year label string used as the Calendar header
  4257. * @config MY_LABEL_MONTH_POSITION
  4258. * @type Number
  4259. * @default 1
  4260. */
  4261. cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_POSITION.key, { value:DEF_CFG.MY_LABEL_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4262. /**
  4263. * The position of the year in the month year label string used as the Calendar header
  4264. * @config MY_LABEL_YEAR_POSITION
  4265. * @type Number
  4266. * @default 2
  4267. */
  4268. cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_POSITION.key, { value:DEF_CFG.MY_LABEL_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
  4269. /**
  4270. * The suffix used after the month when rendering the Calendar header
  4271. * @config MY_LABEL_MONTH_SUFFIX
  4272. * @type String
  4273. * @default " "
  4274. */
  4275. cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_SUFFIX.key, { value:DEF_CFG.MY_LABEL_MONTH_SUFFIX.value, handler:this.delegateConfig } );
  4276. /**
  4277. * The suffix used after the year when rendering the Calendar header
  4278. * @config MY_LABEL_YEAR_SUFFIX
  4279. * @type String
  4280. * @default ""
  4281. */
  4282. cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_SUFFIX.key, { value:DEF_CFG.MY_LABEL_YEAR_SUFFIX.value, handler:this.delegateConfig } );
  4283. /**
  4284. * Configuration for the Month Year Navigation UI. By default it is disabled
  4285. * @config NAV
  4286. * @type Object
  4287. * @default null
  4288. */
  4289. cfg.addProperty(DEF_CFG.NAV.key, { value:DEF_CFG.NAV.value, handler:this.configNavigator } );
  4290. /**
  4291. * The map of UI strings which the CalendarGroup UI uses.
  4292. *
  4293. * @config strings
  4294. * @type {Object}
  4295. * @default An object with the properties shown below:
  4296. * <dl>
  4297. * <dt>previousMonth</dt><dd><em>String</em> : The string to use for the "Previous Month" navigation UI. Defaults to "Previous Month".</dd>
  4298. * <dt>nextMonth</dt><dd><em>String</em> : The string to use for the "Next Month" navigation UI. Defaults to "Next Month".</dd>
  4299. * <dt>close</dt><dd><em>String</em> : The string to use for the close button label. Defaults to "Close".</dd>
  4300. * </dl>
  4301. */
  4302. cfg.addProperty(DEF_CFG.STRINGS.key, {
  4303. value:DEF_CFG.STRINGS.value,
  4304. handler:this.configStrings,
  4305. validator: function(val) {
  4306. return Lang.isObject(val);
  4307. },
  4308. supercedes: DEF_CFG.STRINGS.supercedes
  4309. });
  4310. },
  4311. /**
  4312. * Initializes CalendarGroup's built-in CustomEvents
  4313. * @method initEvents
  4314. */
  4315. initEvents : function() {
  4316. var me = this,
  4317. strEvent = "Event",
  4318. CE = YAHOO.util.CustomEvent;
  4319. /**
  4320. * Proxy subscriber to subscribe to the CalendarGroup's child Calendars' CustomEvents
  4321. * @method sub
  4322. * @private
  4323. * @param {Function} fn The function to subscribe to this CustomEvent
  4324. * @param {Object} obj The CustomEvent's scope object
  4325. * @param {Boolean} bOverride Whether or not to apply scope correction
  4326. */
  4327. var sub = function(fn, obj, bOverride) {
  4328. for (var p=0;p<me.pages.length;++p) {
  4329. var cal = me.pages[p];
  4330. cal[this.type + strEvent].subscribe(fn, obj, bOverride);
  4331. }
  4332. };
  4333. /**
  4334. * Proxy unsubscriber to unsubscribe from the CalendarGroup's child Calendars' CustomEvents
  4335. * @method unsub
  4336. * @private
  4337. * @param {Function} fn The function to subscribe to this CustomEvent
  4338. * @param {Object} obj The CustomEvent's scope object
  4339. */
  4340. var unsub = function(fn, obj) {
  4341. for (var p=0;p<me.pages.length;++p) {
  4342. var cal = me.pages[p];
  4343. cal[this.type + strEvent].unsubscribe(fn, obj);
  4344. }
  4345. };
  4346. var defEvents = Calendar._EVENT_TYPES;
  4347. /**
  4348. * Fired before a date selection is made
  4349. * @event beforeSelectEvent
  4350. */
  4351. me.beforeSelectEvent = new CE(defEvents.BEFORE_SELECT);
  4352. me.beforeSelectEvent.subscribe = sub; me.beforeSelectEvent.unsubscribe = unsub;
  4353. /**
  4354. * Fired when a date selection is made
  4355. * @event selectEvent
  4356. * @param {Array} Array of Date field arrays in the format [YYYY, MM, DD].
  4357. */
  4358. me.selectEvent = new CE(defEvents.SELECT);
  4359. me.selectEvent.subscribe = sub; me.selectEvent.unsubscribe = unsub;
  4360. /**
  4361. * Fired before a date or set of dates is deselected
  4362. * @event beforeDeselectEvent
  4363. */
  4364. me.beforeDeselectEvent = new CE(defEvents.BEFORE_DESELECT);
  4365. me.beforeDeselectEvent.subscribe = sub; me.beforeDeselectEvent.unsubscribe = unsub;
  4366. /**
  4367. * Fired when a date or set of dates has been deselected
  4368. * @event deselectEvent
  4369. * @param {Array} Array of Date field arrays in the format [YYYY, MM, DD].
  4370. */
  4371. me.deselectEvent = new CE(defEvents.DESELECT);
  4372. me.deselectEvent.subscribe = sub; me.deselectEvent.unsubscribe = unsub;
  4373. /**
  4374. * Fired when the Calendar page is changed
  4375. * @event changePageEvent
  4376. */
  4377. me.changePageEvent = new CE(defEvents.CHANGE_PAGE);
  4378. me.changePageEvent.subscribe = sub; me.changePageEvent.unsubscribe = unsub;
  4379. /**
  4380. * Fired before the Calendar is rendered
  4381. * @event beforeRenderEvent
  4382. */
  4383. me.beforeRenderEvent = new CE(defEvents.BEFORE_RENDER);
  4384. me.beforeRenderEvent.subscribe = sub; me.beforeRenderEvent.unsubscribe = unsub;
  4385. /**
  4386. * Fired when the Calendar is rendered
  4387. * @event renderEvent
  4388. */
  4389. me.renderEvent = new CE(defEvents.RENDER);
  4390. me.renderEvent.subscribe = sub; me.renderEvent.unsubscribe = unsub;
  4391. /**
  4392. * Fired when the Calendar is reset
  4393. * @event resetEvent
  4394. */
  4395. me.resetEvent = new CE(defEvents.RESET);
  4396. me.resetEvent.subscribe = sub; me.resetEvent.unsubscribe = unsub;
  4397. /**
  4398. * Fired when the Calendar is cleared
  4399. * @event clearEvent
  4400. */
  4401. me.clearEvent = new CE(defEvents.CLEAR);
  4402. me.clearEvent.subscribe = sub; me.clearEvent.unsubscribe = unsub;
  4403. /**
  4404. * Fired just before the CalendarGroup is to be shown
  4405. * @event beforeShowEvent
  4406. */
  4407. me.beforeShowEvent = new CE(defEvents.BEFORE_SHOW);
  4408. /**
  4409. * Fired after the CalendarGroup is shown
  4410. * @event showEvent
  4411. */
  4412. me.showEvent = new CE(defEvents.SHOW);
  4413. /**
  4414. * Fired just before the CalendarGroup is to be hidden
  4415. * @event beforeHideEvent
  4416. */
  4417. me.beforeHideEvent = new CE(defEvents.BEFORE_HIDE);
  4418. /**
  4419. * Fired after the CalendarGroup is hidden
  4420. * @event hideEvent
  4421. */
  4422. me.hideEvent = new CE(defEvents.HIDE);
  4423. /**
  4424. * Fired just before the CalendarNavigator is to be shown
  4425. * @event beforeShowNavEvent
  4426. */
  4427. me.beforeShowNavEvent = new CE(defEvents.BEFORE_SHOW_NAV);
  4428. /**
  4429. * Fired after the CalendarNavigator is shown
  4430. * @event showNavEvent
  4431. */
  4432. me.showNavEvent = new CE(defEvents.SHOW_NAV);
  4433. /**
  4434. * Fired just before the CalendarNavigator is to be hidden
  4435. * @event beforeHideNavEvent
  4436. */
  4437. me.beforeHideNavEvent = new CE(defEvents.BEFORE_HIDE_NAV);
  4438. /**
  4439. * Fired after the CalendarNavigator is hidden
  4440. * @event hideNavEvent
  4441. */
  4442. me.hideNavEvent = new CE(defEvents.HIDE_NAV);
  4443. /**
  4444. * Fired just before the CalendarNavigator is to be rendered
  4445. * @event beforeRenderNavEvent
  4446. */
  4447. me.beforeRenderNavEvent = new CE(defEvents.BEFORE_RENDER_NAV);
  4448. /**
  4449. * Fired after the CalendarNavigator is rendered
  4450. * @event renderNavEvent
  4451. */
  4452. me.renderNavEvent = new CE(defEvents.RENDER_NAV);
  4453. /**
  4454. * Fired just before the CalendarGroup is to be destroyed
  4455. * @event beforeDestroyEvent
  4456. */
  4457. me.beforeDestroyEvent = new CE(defEvents.BEFORE_DESTROY);
  4458. /**
  4459. * Fired after the CalendarGroup is destroyed. This event should be used
  4460. * for notification only. When this event is fired, important CalendarGroup instance
  4461. * properties, dom references and event listeners have already been
  4462. * removed/dereferenced, and hence the CalendarGroup instance is not in a usable
  4463. * state.
  4464. *
  4465. * @event destroyEvent
  4466. */
  4467. me.destroyEvent = new CE(defEvents.DESTROY);
  4468. },
  4469. /**
  4470. * The default Config handler for the "pages" property
  4471. * @method configPages
  4472. * @param {String} type The CustomEvent type (usually the property name)
  4473. * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
  4474. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
  4475. */
  4476. configPages : function(type, args, obj) {
  4477. var pageCount = args[0],
  4478. cfgPageDate = DEF_CFG.PAGEDATE.key,
  4479. sep = "_",
  4480. caldate,
  4481. firstPageDate = null,
  4482. groupCalClass = "groupcal",
  4483. firstClass = "first-of-type",
  4484. lastClass = "last-of-type";
  4485. for (var p=0;p<pageCount;++p) {
  4486. var calId = this.id + sep + p,
  4487. calContainerId = this.containerId + sep + p,
  4488. childConfig = this.cfg.getConfig();
  4489. childConfig.close = false;
  4490. childConfig.title = false;
  4491. childConfig.navigator = null;
  4492. if (p > 0) {
  4493. caldate = new Date(firstPageDate);
  4494. this._setMonthOnDate(caldate, caldate.getMonth() + p);
  4495. childConfig.pageDate = caldate;
  4496. }
  4497. var cal = this.constructChild(calId, calContainerId, childConfig);
  4498. Dom.removeClass(cal.oDomContainer, this.Style.CSS_SINGLE);
  4499. Dom.addClass(cal.oDomContainer, groupCalClass);
  4500. if (p===0) {
  4501. firstPageDate = cal.cfg.getProperty(cfgPageDate);
  4502. Dom.addClass(cal.oDomContainer, firstClass);
  4503. }
  4504. if (p==(pageCount-1)) {
  4505. Dom.addClass(cal.oDomContainer, lastClass);
  4506. }
  4507. cal.parent = this;
  4508. cal.index = p;
  4509. this.pages[this.pages.length] = cal;
  4510. }
  4511. },
  4512. /**
  4513. * The default Config handler for the "pagedate" property
  4514. * @method configPageDate
  4515. * @param {String} type The CustomEvent type (usually the property name)
  4516. * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
  4517. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
  4518. */
  4519. configPageDate : function(type, args, obj) {
  4520. var val = args[0],
  4521. firstPageDate;
  4522. var cfgPageDate = DEF_CFG.PAGEDATE.key;
  4523. for (var p=0;p<this.pages.length;++p) {
  4524. var cal = this.pages[p];
  4525. if (p === 0) {
  4526. firstPageDate = cal._parsePageDate(val);
  4527. cal.cfg.setProperty(cfgPageDate, firstPageDate);
  4528. } else {
  4529. var pageDate = new Date(firstPageDate);
  4530. this._setMonthOnDate(pageDate, pageDate.getMonth() + p);
  4531. cal.cfg.setProperty(cfgPageDate, pageDate);
  4532. }
  4533. }
  4534. },
  4535. /**
  4536. * The default Config handler for the CalendarGroup "selected" property
  4537. * @method configSelected
  4538. * @param {String} type The CustomEvent type (usually the property name)
  4539. * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
  4540. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
  4541. */
  4542. configSelected : function(type, args, obj) {
  4543. var cfgSelected = DEF_CFG.SELECTED.key;
  4544. this.delegateConfig(type, args, obj);
  4545. var selected = (this.pages.length > 0) ? this.pages[0].cfg.getProperty(cfgSelected) : [];
  4546. this.cfg.setProperty(cfgSelected, selected, true);
  4547. },
  4548. /**
  4549. * Delegates a configuration property to the CustomEvents associated with the CalendarGroup's children
  4550. * @method delegateConfig
  4551. * @param {String} type The CustomEvent type (usually the property name)
  4552. * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
  4553. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
  4554. */
  4555. delegateConfig : function(type, args, obj) {
  4556. var val = args[0];
  4557. var cal;
  4558. for (var p=0;p<this.pages.length;p++) {
  4559. cal = this.pages[p];
  4560. cal.cfg.setProperty(type, val);
  4561. }
  4562. },
  4563. /**
  4564. * Adds a function to all child Calendars within this CalendarGroup.
  4565. * @method setChildFunction
  4566. * @param {String} fnName The name of the function
  4567. * @param {Function} fn The function to apply to each Calendar page object
  4568. */
  4569. setChildFunction : function(fnName, fn) {
  4570. var pageCount = this.cfg.getProperty(DEF_CFG.PAGES.key);
  4571. for (var p=0;p<pageCount;++p) {
  4572. this.pages[p][fnName] = fn;
  4573. }
  4574. },
  4575. /**
  4576. * Calls a function within all child Calendars within this CalendarGroup.
  4577. * @method callChildFunction
  4578. * @param {String} fnName The name of the function
  4579. * @param {Array} args The arguments to pass to the function
  4580. */
  4581. callChildFunction : function(fnName, args) {
  4582. var pageCount = this.cfg.getProperty(DEF_CFG.PAGES.key);
  4583. for (var p=0;p<pageCount;++p) {
  4584. var page = this.pages[p];
  4585. if (page[fnName]) {
  4586. var fn = page[fnName];
  4587. fn.call(page, args);
  4588. }
  4589. }
  4590. },
  4591. /**
  4592. * Constructs a child calendar. This method can be overridden if a subclassed version of the default
  4593. * calendar is to be used.
  4594. * @method constructChild
  4595. * @param {String} id The id of the table element that will represent the calendar widget
  4596. * @param {String} containerId The id of the container div element that will wrap the calendar table
  4597. * @param {Object} config The configuration object containing the Calendar's arguments
  4598. * @return {YAHOO.widget.Calendar} The YAHOO.widget.Calendar instance that is constructed
  4599. */
  4600. constructChild : function(id,containerId,config) {
  4601. var container = document.getElementById(containerId);
  4602. if (! container) {
  4603. container = document.createElement("div");
  4604. container.id = containerId;
  4605. this.oDomContainer.appendChild(container);
  4606. }
  4607. return new Calendar(id,containerId,config);
  4608. },
  4609. /**
  4610. * Sets the calendar group's month explicitly. This month will be set into the first
  4611. * page of the multi-page calendar, and all other months will be iterated appropriately.
  4612. * @method setMonth
  4613. * @param {Number} month The numeric month, from 0 (January) to 11 (December)
  4614. */
  4615. setMonth : function(month) {
  4616. month = parseInt(month, 10);
  4617. var currYear;
  4618. var cfgPageDate = DEF_CFG.PAGEDATE.key;
  4619. for (var p=0; p<this.pages.length; ++p) {
  4620. var cal = this.pages[p];
  4621. var pageDate = cal.cfg.getProperty(cfgPageDate);
  4622. if (p === 0) {
  4623. currYear = pageDate.getFullYear();
  4624. } else {
  4625. pageDate.setFullYear(currYear);
  4626. }
  4627. this._setMonthOnDate(pageDate, month+p);
  4628. cal.cfg.setProperty(cfgPageDate, pageDate);
  4629. }
  4630. },
  4631. /**
  4632. * Sets the calendar group's year explicitly. This year will be set into the first
  4633. * page of the multi-page calendar, and all other months will be iterated appropriately.
  4634. * @method setYear
  4635. * @param {Number} year The numeric 4-digit year
  4636. */
  4637. setYear : function(year) {
  4638. var cfgPageDate = DEF_CFG.PAGEDATE.key;
  4639. year = parseInt(year, 10);
  4640. for (var p=0;p<this.pages.length;++p) {
  4641. var cal = this.pages[p];
  4642. var pageDate = cal.cfg.getProperty(cfgPageDate);
  4643. if ((pageDate.getMonth()+1) == 1 && p>0) {
  4644. year+=1;
  4645. }
  4646. cal.setYear(year);
  4647. }
  4648. },
  4649. /**
  4650. * Calls the render function of all child calendars within the group.
  4651. * @method render
  4652. */
  4653. render : function() {
  4654. this.renderHeader();
  4655. for (var p=0;p<this.pages.length;++p) {
  4656. var cal = this.pages[p];
  4657. cal.render();
  4658. }
  4659. this.renderFooter();
  4660. },
  4661. /**
  4662. * Selects a date or a collection of dates on the current calendar. This method, by default,
  4663. * does not call the render method explicitly. Once selection has completed, render must be
  4664. * called for the changes to be reflected visually.
  4665. * @method select
  4666. * @param {String/Date/Date[]} date The date string of dates to select in the current calendar. Valid formats are
  4667. * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
  4668. * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
  4669. * This method can also take a JavaScript Date object or an array of Date objects.
  4670. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  4671. */
  4672. select : function(date) {
  4673. for (var p=0;p<this.pages.length;++p) {
  4674. var cal = this.pages[p];
  4675. cal.select(date);
  4676. }
  4677. return this.getSelectedDates();
  4678. },
  4679. /**
  4680. * Selects dates in the CalendarGroup based on the cell index provided. This method is used to select cells without having to do a full render. The selected style is applied to the cells directly.
  4681. * The value of the MULTI_SELECT Configuration attribute will determine the set of dates which get selected.
  4682. * <ul>
  4683. * <li>If MULTI_SELECT is false, selectCell will select the cell at the specified index for only the last displayed Calendar page.</li>
  4684. * <li>If MULTI_SELECT is true, selectCell will select the cell at the specified index, on each displayed Calendar page.</li>
  4685. * </ul>
  4686. * @method selectCell
  4687. * @param {Number} cellIndex The index of the cell to be selected.
  4688. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  4689. */
  4690. selectCell : function(cellIndex) {
  4691. for (var p=0;p<this.pages.length;++p) {
  4692. var cal = this.pages[p];
  4693. cal.selectCell(cellIndex);
  4694. }
  4695. return this.getSelectedDates();
  4696. },
  4697. /**
  4698. * Deselects a date or a collection of dates on the current calendar. This method, by default,
  4699. * does not call the render method explicitly. Once deselection has completed, render must be
  4700. * called for the changes to be reflected visually.
  4701. * @method deselect
  4702. * @param {String/Date/Date[]} date The date string of dates to deselect in the current calendar. Valid formats are
  4703. * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
  4704. * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
  4705. * This method can also take a JavaScript Date object or an array of Date objects.
  4706. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  4707. */
  4708. deselect : function(date) {
  4709. for (var p=0;p<this.pages.length;++p) {
  4710. var cal = this.pages[p];
  4711. cal.deselect(date);
  4712. }
  4713. return this.getSelectedDates();
  4714. },
  4715. /**
  4716. * Deselects all dates on the current calendar.
  4717. * @method deselectAll
  4718. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  4719. * Assuming that this function executes properly, the return value should be an empty array.
  4720. * However, the empty array is returned for the sake of being able to check the selection status
  4721. * of the calendar.
  4722. */
  4723. deselectAll : function() {
  4724. for (var p=0;p<this.pages.length;++p) {
  4725. var cal = this.pages[p];
  4726. cal.deselectAll();
  4727. }
  4728. return this.getSelectedDates();
  4729. },
  4730. /**
  4731. * Deselects dates in the CalendarGroup based on the cell index provided. This method is used to select cells without having to do a full render. The selected style is applied to the cells directly.
  4732. * deselectCell will deselect the cell at the specified index on each displayed Calendar page.
  4733. *
  4734. * @method deselectCell
  4735. * @param {Number} cellIndex The index of the cell to deselect.
  4736. * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
  4737. */
  4738. deselectCell : function(cellIndex) {
  4739. for (var p=0;p<this.pages.length;++p) {
  4740. var cal = this.pages[p];
  4741. cal.deselectCell(cellIndex);
  4742. }
  4743. return this.getSelectedDates();
  4744. },
  4745. /**
  4746. * Resets the calendar widget to the originally selected month and year, and
  4747. * sets the calendar to the initial selection(s).
  4748. * @method reset
  4749. */
  4750. reset : function() {
  4751. for (var p=0;p<this.pages.length;++p) {
  4752. var cal = this.pages[p];
  4753. cal.reset();
  4754. }
  4755. },
  4756. /**
  4757. * Clears the selected dates in the current calendar widget and sets the calendar
  4758. * to the current month and year.
  4759. * @method clear
  4760. */
  4761. clear : function() {
  4762. for (var p=0;p<this.pages.length;++p) {
  4763. var cal = this.pages[p];
  4764. cal.clear();
  4765. }
  4766. this.cfg.setProperty(DEF_CFG.SELECTED.key, []);
  4767. this.cfg.setProperty(DEF_CFG.PAGEDATE.key, new Date(this.pages[0].today.getTime()));
  4768. this.render();
  4769. },
  4770. /**
  4771. * Navigates to the next month page in the calendar widget.
  4772. * @method nextMonth
  4773. */
  4774. nextMonth : function() {
  4775. for (var p=0;p<this.pages.length;++p) {
  4776. var cal = this.pages[p];
  4777. cal.nextMonth();
  4778. }
  4779. },
  4780. /**
  4781. * Navigates to the previous month page in the calendar widget.
  4782. * @method previousMonth
  4783. */
  4784. previousMonth : function() {
  4785. for (var p=this.pages.length-1;p>=0;--p) {
  4786. var cal = this.pages[p];
  4787. cal.previousMonth();
  4788. }
  4789. },
  4790. /**
  4791. * Navigates to the next year in the currently selected month in the calendar widget.
  4792. * @method nextYear
  4793. */
  4794. nextYear : function() {
  4795. for (var p=0;p<this.pages.length;++p) {
  4796. var cal = this.pages[p];
  4797. cal.nextYear();
  4798. }
  4799. },
  4800. /**
  4801. * Navigates to the previous year in the currently selected month in the calendar widget.
  4802. * @method previousYear
  4803. */
  4804. previousYear : function() {
  4805. for (var p=0;p<this.pages.length;++p) {
  4806. var cal = this.pages[p];
  4807. cal.previousYear();
  4808. }
  4809. },
  4810. /**
  4811. * Gets the list of currently selected dates from the calendar.
  4812. * @return An array of currently selected JavaScript Date objects.
  4813. * @type Date[]
  4814. */
  4815. getSelectedDates : function() {
  4816. var returnDates = [];
  4817. var selected = this.cfg.getProperty(DEF_CFG.SELECTED.key);
  4818. for (var d=0;d<selected.length;++d) {
  4819. var dateArray = selected[d];
  4820. var date = DateMath.getDate(dateArray[0],dateArray[1]-1,dateArray[2]);
  4821. returnDates.push(date);
  4822. }
  4823. returnDates.sort( function(a,b) { return a-b; } );
  4824. return returnDates;
  4825. },
  4826. /**
  4827. * Adds a renderer to the render stack. The function reference passed to this method will be executed
  4828. * when a date cell matches the conditions specified in the date string for this renderer.
  4829. * @method addRenderer
  4830. * @param {String} sDates A date string to associate with the specified renderer. Valid formats
  4831. * include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
  4832. * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
  4833. */
  4834. addRenderer : function(sDates, fnRender) {
  4835. for (var p=0;p<this.pages.length;++p) {
  4836. var cal = this.pages[p];
  4837. cal.addRenderer(sDates, fnRender);
  4838. }
  4839. },
  4840. /**
  4841. * Adds a month to the render stack. The function reference passed to this method will be executed
  4842. * when a date cell matches the month passed to this method.
  4843. * @method addMonthRenderer
  4844. * @param {Number} month The month (1-12) to associate with this renderer
  4845. * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
  4846. */
  4847. addMonthRenderer : function(month, fnRender) {
  4848. for (var p=0;p<this.pages.length;++p) {
  4849. var cal = this.pages[p];
  4850. cal.addMonthRenderer(month, fnRender);
  4851. }
  4852. },
  4853. /**
  4854. * Adds a weekday to the render stack. The function reference passed to this method will be executed
  4855. * when a date cell matches the weekday passed to this method.
  4856. * @method addWeekdayRenderer
  4857. * @param {Number} weekday The weekday (1-7) to associate with this renderer. 1=Sunday, 2=Monday etc.
  4858. * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
  4859. */
  4860. addWeekdayRenderer : function(weekday, fnRender) {
  4861. for (var p=0;p<this.pages.length;++p) {
  4862. var cal = this.pages[p];
  4863. cal.addWeekdayRenderer(weekday, fnRender);
  4864. }
  4865. },
  4866. /**
  4867. * Removes all custom renderers added to the CalendarGroup through the addRenderer, addMonthRenderer and
  4868. * addWeekRenderer methods. CalendarGroup's render method needs to be called to after removing renderers
  4869. * to see the changes applied.
  4870. *
  4871. * @method removeRenderers
  4872. */
  4873. removeRenderers : function() {
  4874. this.callChildFunction("removeRenderers");
  4875. },
  4876. /**
  4877. * Renders the header for the CalendarGroup.
  4878. * @method renderHeader
  4879. */
  4880. renderHeader : function() {
  4881. // EMPTY DEFAULT IMPL
  4882. },
  4883. /**
  4884. * Renders a footer for the 2-up calendar container. By default, this method is
  4885. * unimplemented.
  4886. * @method renderFooter
  4887. */
  4888. renderFooter : function() {
  4889. // EMPTY DEFAULT IMPL
  4890. },
  4891. /**
  4892. * Adds the designated number of months to the current calendar month, and sets the current
  4893. * calendar page date to the new month.
  4894. * @method addMonths
  4895. * @param {Number} count The number of months to add to the current calendar
  4896. */
  4897. addMonths : function(count) {
  4898. this.callChildFunction("addMonths", count);
  4899. },
  4900. /**
  4901. * Subtracts the designated number of months from the current calendar month, and sets the current
  4902. * calendar page date to the new month.
  4903. * @method subtractMonths
  4904. * @param {Number} count The number of months to subtract from the current calendar
  4905. */
  4906. subtractMonths : function(count) {
  4907. this.callChildFunction("subtractMonths", count);
  4908. },
  4909. /**
  4910. * Adds the designated number of years to the current calendar, and sets the current
  4911. * calendar page date to the new month.
  4912. * @method addYears
  4913. * @param {Number} count The number of years to add to the current calendar
  4914. */
  4915. addYears : function(count) {
  4916. this.callChildFunction("addYears", count);
  4917. },
  4918. /**
  4919. * Subtcats the designated number of years from the current calendar, and sets the current
  4920. * calendar page date to the new month.
  4921. * @method subtractYears
  4922. * @param {Number} count The number of years to subtract from the current calendar
  4923. */
  4924. subtractYears : function(count) {
  4925. this.callChildFunction("subtractYears", count);
  4926. },
  4927. /**
  4928. * Returns the Calendar page instance which has a pagedate (month/year) matching the given date.
  4929. * Returns null if no match is found.
  4930. *
  4931. * @method getCalendarPage
  4932. * @param {Date} date The JavaScript Date object for which a Calendar page is to be found.
  4933. * @return {Calendar} The Calendar page instance representing the month to which the date
  4934. * belongs.
  4935. */
  4936. getCalendarPage : function(date) {
  4937. var cal = null;
  4938. if (date) {
  4939. var y = date.getFullYear(),
  4940. m = date.getMonth();
  4941. var pages = this.pages;
  4942. for (var i = 0; i < pages.length; ++i) {
  4943. var pageDate = pages[i].cfg.getProperty("pagedate");
  4944. if (pageDate.getFullYear() === y && pageDate.getMonth() === m) {
  4945. cal = pages[i];
  4946. break;
  4947. }
  4948. }
  4949. }
  4950. return cal;
  4951. },
  4952. /**
  4953. * Sets the month on a Date object, taking into account year rollover if the month is less than 0 or greater than 11.
  4954. * The Date object passed in is modified. It should be cloned before passing it into this method if the original value needs to be maintained
  4955. * @method _setMonthOnDate
  4956. * @private
  4957. * @param {Date} date The Date object on which to set the month index
  4958. * @param {Number} iMonth The month index to set
  4959. */
  4960. _setMonthOnDate : function(date, iMonth) {
  4961. // Bug in Safari 1.3, 2.0 (WebKit build < 420), Date.setMonth does not work consistently if iMonth is not 0-11
  4962. if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420 && (iMonth < 0 || iMonth > 11)) {
  4963. var newDate = DateMath.add(date, DateMath.MONTH, iMonth-date.getMonth());
  4964. date.setTime(newDate.getTime());
  4965. } else {
  4966. date.setMonth(iMonth);
  4967. }
  4968. },
  4969. /**
  4970. * Fixes the width of the CalendarGroup container element, to account for miswrapped floats
  4971. * @method _fixWidth
  4972. * @private
  4973. */
  4974. _fixWidth : function() {
  4975. var w = 0;
  4976. for (var p=0;p<this.pages.length;++p) {
  4977. var cal = this.pages[p];
  4978. w += cal.oDomContainer.offsetWidth;
  4979. }
  4980. if (w > 0) {
  4981. this.oDomContainer.style.width = w + "px";
  4982. }
  4983. },
  4984. /**
  4985. * Returns a string representation of the object.
  4986. * @method toString
  4987. * @return {String} A string representation of the CalendarGroup object.
  4988. */
  4989. toString : function() {
  4990. return "CalendarGroup " + this.id;
  4991. },
  4992. /**
  4993. * Destroys the CalendarGroup instance. The method will remove references
  4994. * to HTML elements, remove any event listeners added by the CalendarGroup.
  4995. *
  4996. * It will also destroy the Config and CalendarNavigator instances created by the
  4997. * CalendarGroup and the individual Calendar instances created for each page.
  4998. *
  4999. * @method destroy
  5000. */
  5001. destroy : function() {
  5002. if (this.beforeDestroyEvent.fire()) {
  5003. var cal = this;
  5004. // Child objects
  5005. if (cal.navigator) {
  5006. cal.navigator.destroy();
  5007. }
  5008. if (cal.cfg) {
  5009. cal.cfg.destroy();
  5010. }
  5011. // DOM event listeners
  5012. Event.purgeElement(cal.oDomContainer, true);
  5013. // Generated markup/DOM - Not removing the container DIV since we didn't create it.
  5014. Dom.removeClass(cal.oDomContainer, CalendarGroup.CSS_CONTAINER);
  5015. Dom.removeClass(cal.oDomContainer, CalendarGroup.CSS_MULTI_UP);
  5016. for (var i = 0, l = cal.pages.length; i < l; i++) {
  5017. cal.pages[i].destroy();
  5018. cal.pages[i] = null;
  5019. }
  5020. cal.oDomContainer.innerHTML = "";
  5021. // JS-to-DOM references
  5022. cal.oDomContainer = null;
  5023. this.destroyEvent.fire();
  5024. }
  5025. }
  5026. };
  5027. /**
  5028. * CSS class representing the container for the calendar
  5029. * @property YAHOO.widget.CalendarGroup.CSS_CONTAINER
  5030. * @static
  5031. * @final
  5032. * @type String
  5033. */
  5034. CalendarGroup.CSS_CONTAINER = "yui-calcontainer";
  5035. /**
  5036. * CSS class representing the container for the calendar
  5037. * @property YAHOO.widget.CalendarGroup.CSS_MULTI_UP
  5038. * @static
  5039. * @final
  5040. * @type String
  5041. */
  5042. CalendarGroup.CSS_MULTI_UP = "multi";
  5043. /**
  5044. * CSS class representing the title for the 2-up calendar
  5045. * @property YAHOO.widget.CalendarGroup.CSS_2UPTITLE
  5046. * @static
  5047. * @final
  5048. * @type String
  5049. */
  5050. CalendarGroup.CSS_2UPTITLE = "title";
  5051. /**
  5052. * CSS class representing the close icon for the 2-up calendar
  5053. * @property YAHOO.widget.CalendarGroup.CSS_2UPCLOSE
  5054. * @static
  5055. * @final
  5056. * @deprecated Along with Calendar.IMG_ROOT and NAV_ARROW_LEFT, NAV_ARROW_RIGHT configuration properties.
  5057. * Calendar's <a href="YAHOO.widget.Calendar.html#Style.CSS_CLOSE">Style.CSS_CLOSE</a> property now represents the CSS class used to render the close icon
  5058. * @type String
  5059. */
  5060. CalendarGroup.CSS_2UPCLOSE = "close-icon";
  5061. YAHOO.lang.augmentProto(CalendarGroup, Calendar, "buildDayLabel",
  5062. "buildMonthLabel",
  5063. "renderOutOfBoundsDate",
  5064. "renderRowHeader",
  5065. "renderRowFooter",
  5066. "renderCellDefault",
  5067. "styleCellDefault",
  5068. "renderCellStyleHighlight1",
  5069. "renderCellStyleHighlight2",
  5070. "renderCellStyleHighlight3",
  5071. "renderCellStyleHighlight4",
  5072. "renderCellStyleToday",
  5073. "renderCellStyleSelected",
  5074. "renderCellNotThisMonth",
  5075. "renderBodyCellRestricted",
  5076. "initStyles",
  5077. "configTitle",
  5078. "configClose",
  5079. "configIframe",
  5080. "configStrings",
  5081. "configNavigator",
  5082. "createTitleBar",
  5083. "createCloseButton",
  5084. "removeTitleBar",
  5085. "removeCloseButton",
  5086. "hide",
  5087. "show",
  5088. "toDate",
  5089. "_toDate",
  5090. "_parseArgs",
  5091. "browser");
  5092. YAHOO.widget.CalGrp = CalendarGroup;
  5093. YAHOO.widget.CalendarGroup = CalendarGroup;
  5094. /**
  5095. * @class YAHOO.widget.Calendar2up
  5096. * @extends YAHOO.widget.CalendarGroup
  5097. * @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
  5098. */
  5099. YAHOO.widget.Calendar2up = function(id, containerId, config) {
  5100. this.init(id, containerId, config);
  5101. };
  5102. YAHOO.extend(YAHOO.widget.Calendar2up, CalendarGroup);
  5103. /**
  5104. * @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
  5105. */
  5106. YAHOO.widget.Cal2up = YAHOO.widget.Calendar2up;
  5107. })();
  5108. /**
  5109. * The CalendarNavigator is used along with a Calendar/CalendarGroup to
  5110. * provide a Month/Year popup navigation control, allowing the user to navigate
  5111. * to a specific month/year in the Calendar/CalendarGroup without having to
  5112. * scroll through months sequentially
  5113. *
  5114. * @namespace YAHOO.widget
  5115. * @class CalendarNavigator
  5116. * @constructor
  5117. * @param {Calendar|CalendarGroup} cal The instance of the Calendar or CalendarGroup to which this CalendarNavigator should be attached.
  5118. */
  5119. YAHOO.widget.CalendarNavigator = function(cal) {
  5120. this.init(cal);
  5121. };
  5122. (function() {
  5123. // Setup static properties (inside anon fn, so that we can use shortcuts)
  5124. var CN = YAHOO.widget.CalendarNavigator;
  5125. /**
  5126. * YAHOO.widget.CalendarNavigator.CLASSES contains constants
  5127. * for the class values applied to the CalendarNaviatgator's
  5128. * DOM elements
  5129. * @property YAHOO.widget.CalendarNavigator.CLASSES
  5130. * @type Object
  5131. * @static
  5132. */
  5133. CN.CLASSES = {
  5134. /**
  5135. * Class applied to the Calendar Navigator's bounding box
  5136. * @property YAHOO.widget.CalendarNavigator.CLASSES.NAV
  5137. * @type String
  5138. * @static
  5139. */
  5140. NAV :"yui-cal-nav",
  5141. /**
  5142. * Class applied to the Calendar/CalendarGroup's bounding box to indicate
  5143. * the Navigator is currently visible
  5144. * @property YAHOO.widget.CalendarNavigator.CLASSES.NAV_VISIBLE
  5145. * @type String
  5146. * @static
  5147. */
  5148. NAV_VISIBLE: "yui-cal-nav-visible",
  5149. /**
  5150. * Class applied to the Navigator mask's bounding box
  5151. * @property YAHOO.widget.CalendarNavigator.CLASSES.MASK
  5152. * @type String
  5153. * @static
  5154. */
  5155. MASK : "yui-cal-nav-mask",
  5156. /**
  5157. * Class applied to the year label/control bounding box
  5158. * @property YAHOO.widget.CalendarNavigator.CLASSES.YEAR
  5159. * @type String
  5160. * @static
  5161. */
  5162. YEAR : "yui-cal-nav-y",
  5163. /**
  5164. * Class applied to the month label/control bounding box
  5165. * @property YAHOO.widget.CalendarNavigator.CLASSES.MONTH
  5166. * @type String
  5167. * @static
  5168. */
  5169. MONTH : "yui-cal-nav-m",
  5170. /**
  5171. * Class applied to the submit/cancel button's bounding box
  5172. * @property YAHOO.widget.CalendarNavigator.CLASSES.BUTTONS
  5173. * @type String
  5174. * @static
  5175. */
  5176. BUTTONS : "yui-cal-nav-b",
  5177. /**
  5178. * Class applied to buttons wrapping element
  5179. * @property YAHOO.widget.CalendarNavigator.CLASSES.BUTTON
  5180. * @type String
  5181. * @static
  5182. */
  5183. BUTTON : "yui-cal-nav-btn",
  5184. /**
  5185. * Class applied to the validation error area's bounding box
  5186. * @property YAHOO.widget.CalendarNavigator.CLASSES.ERROR
  5187. * @type String
  5188. * @static
  5189. */
  5190. ERROR : "yui-cal-nav-e",
  5191. /**
  5192. * Class applied to the year input control
  5193. * @property YAHOO.widget.CalendarNavigator.CLASSES.YEAR_CTRL
  5194. * @type String
  5195. * @static
  5196. */
  5197. YEAR_CTRL : "yui-cal-nav-yc",
  5198. /**
  5199. * Class applied to the month input control
  5200. * @property YAHOO.widget.CalendarNavigator.CLASSES.MONTH_CTRL
  5201. * @type String
  5202. * @static
  5203. */
  5204. MONTH_CTRL : "yui-cal-nav-mc",
  5205. /**
  5206. * Class applied to controls with invalid data (e.g. a year input field with invalid an year)
  5207. * @property YAHOO.widget.CalendarNavigator.CLASSES.INVALID
  5208. * @type String
  5209. * @static
  5210. */
  5211. INVALID : "yui-invalid",
  5212. /**
  5213. * Class applied to default controls
  5214. * @property YAHOO.widget.CalendarNavigator.CLASSES.DEFAULT
  5215. * @type String
  5216. * @static
  5217. */
  5218. DEFAULT : "yui-default"
  5219. };
  5220. /**
  5221. * Object literal containing the default configuration values for the CalendarNavigator
  5222. * The configuration object is expected to follow the format below, with the properties being
  5223. * case sensitive.
  5224. * <dl>
  5225. * <dt>strings</dt>
  5226. * <dd><em>Object</em> : An object with the properties shown below, defining the string labels to use in the Navigator's UI
  5227. * <dl>
  5228. * <dt>month</dt><dd><em>String</em> : The string to use for the month label. Defaults to "Month".</dd>
  5229. * <dt>year</dt><dd><em>String</em> : The string to use for the year label. Defaults to "Year".</dd>
  5230. * <dt>submit</dt><dd><em>String</em> : The string to use for the submit button label. Defaults to "Okay".</dd>
  5231. * <dt>cancel</dt><dd><em>String</em> : The string to use for the cancel button label. Defaults to "Cancel".</dd>
  5232. * <dt>invalidYear</dt><dd><em>String</em> : The string to use for invalid year values. Defaults to "Year needs to be a number".</dd>
  5233. * </dl>
  5234. * </dd>
  5235. * <dt>monthFormat</dt><dd><em>String</em> : The month format to use. Either YAHOO.widget.Calendar.LONG, or YAHOO.widget.Calendar.SHORT. Defaults to YAHOO.widget.Calendar.LONG</dd>
  5236. * <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
  5237. * </dl>
  5238. * @property _DEFAULT_CFG
  5239. * @protected
  5240. * @type Object
  5241. * @static
  5242. */
  5243. CN._DEFAULT_CFG = {
  5244. strings : {
  5245. month: "Month",
  5246. year: "Year",
  5247. submit: "Okay",
  5248. cancel: "Cancel",
  5249. invalidYear : "Year needs to be a number"
  5250. },
  5251. monthFormat: YAHOO.widget.Calendar.LONG,
  5252. initialFocus: "year"
  5253. };
  5254. /**
  5255. * The suffix added to the Calendar/CalendarGroup's ID, to generate
  5256. * a unique ID for the Navigator and it's bounding box.
  5257. * @property YAHOO.widget.CalendarNavigator.ID_SUFFIX
  5258. * @static
  5259. * @type String
  5260. * @final
  5261. */
  5262. CN.ID_SUFFIX = "_nav";
  5263. /**
  5264. * The suffix added to the Navigator's ID, to generate
  5265. * a unique ID for the month control.
  5266. * @property YAHOO.widget.CalendarNavigator.MONTH_SUFFIX
  5267. * @static
  5268. * @type String
  5269. * @final
  5270. */
  5271. CN.MONTH_SUFFIX = "_month";
  5272. /**
  5273. * The suffix added to the Navigator's ID, to generate
  5274. * a unique ID for the year control.
  5275. * @property YAHOO.widget.CalendarNavigator.YEAR_SUFFIX
  5276. * @static
  5277. * @type String
  5278. * @final
  5279. */
  5280. CN.YEAR_SUFFIX = "_year";
  5281. /**
  5282. * The suffix added to the Navigator's ID, to generate
  5283. * a unique ID for the error bounding box.
  5284. * @property YAHOO.widget.CalendarNavigator.ERROR_SUFFIX
  5285. * @static
  5286. * @type String
  5287. * @final
  5288. */
  5289. CN.ERROR_SUFFIX = "_error";
  5290. /**
  5291. * The suffix added to the Navigator's ID, to generate
  5292. * a unique ID for the "Cancel" button.
  5293. * @property YAHOO.widget.CalendarNavigator.CANCEL_SUFFIX
  5294. * @static
  5295. * @type String
  5296. * @final
  5297. */
  5298. CN.CANCEL_SUFFIX = "_cancel";
  5299. /**
  5300. * The suffix added to the Navigator's ID, to generate
  5301. * a unique ID for the "Submit" button.
  5302. * @property YAHOO.widget.CalendarNavigator.SUBMIT_SUFFIX
  5303. * @static
  5304. * @type String
  5305. * @final
  5306. */
  5307. CN.SUBMIT_SUFFIX = "_submit";
  5308. /**
  5309. * The number of digits to which the year input control is to be limited.
  5310. * @property YAHOO.widget.CalendarNavigator.YR_MAX_DIGITS
  5311. * @static
  5312. * @type Number
  5313. */
  5314. CN.YR_MAX_DIGITS = 4;
  5315. /**
  5316. * The amount by which to increment the current year value,
  5317. * when the arrow up/down key is pressed on the year control
  5318. * @property YAHOO.widget.CalendarNavigator.YR_MINOR_INC
  5319. * @static
  5320. * @type Number
  5321. */
  5322. CN.YR_MINOR_INC = 1;
  5323. /**
  5324. * The amount by which to increment the current year value,
  5325. * when the page up/down key is pressed on the year control
  5326. * @property YAHOO.widget.CalendarNavigator.YR_MAJOR_INC
  5327. * @static
  5328. * @type Number
  5329. */
  5330. CN.YR_MAJOR_INC = 10;
  5331. /**
  5332. * Artificial delay (in ms) between the time the Navigator is hidden
  5333. * and the Calendar/CalendarGroup state is updated. Allows the user
  5334. * the see the Calendar/CalendarGroup page changing. If set to 0
  5335. * the Calendar/CalendarGroup page will be updated instantly
  5336. * @property YAHOO.widget.CalendarNavigator.UPDATE_DELAY
  5337. * @static
  5338. * @type Number
  5339. */
  5340. CN.UPDATE_DELAY = 50;
  5341. /**
  5342. * Regular expression used to validate the year input
  5343. * @property YAHOO.widget.CalendarNavigator.YR_PATTERN
  5344. * @static
  5345. * @type RegExp
  5346. */
  5347. CN.YR_PATTERN = /^\d+$/;
  5348. /**
  5349. * Regular expression used to trim strings
  5350. * @property YAHOO.widget.CalendarNavigator.TRIM
  5351. * @static
  5352. * @type RegExp
  5353. */
  5354. CN.TRIM = /^\s*(.*?)\s*$/;
  5355. })();
  5356. YAHOO.widget.CalendarNavigator.prototype = {
  5357. /**
  5358. * The unique ID for this CalendarNavigator instance
  5359. * @property id
  5360. * @type String
  5361. */
  5362. id : null,
  5363. /**
  5364. * The Calendar/CalendarGroup instance to which the navigator belongs
  5365. * @property cal
  5366. * @type {Calendar|CalendarGroup}
  5367. */
  5368. cal : null,
  5369. /**
  5370. * Reference to the HTMLElement used to render the navigator's bounding box
  5371. * @property navEl
  5372. * @type HTMLElement
  5373. */
  5374. navEl : null,
  5375. /**
  5376. * Reference to the HTMLElement used to render the navigator's mask
  5377. * @property maskEl
  5378. * @type HTMLElement
  5379. */
  5380. maskEl : null,
  5381. /**
  5382. * Reference to the HTMLElement used to input the year
  5383. * @property yearEl
  5384. * @type HTMLElement
  5385. */
  5386. yearEl : null,
  5387. /**
  5388. * Reference to the HTMLElement used to input the month
  5389. * @property monthEl
  5390. * @type HTMLElement
  5391. */
  5392. monthEl : null,
  5393. /**
  5394. * Reference to the HTMLElement used to display validation errors
  5395. * @property errorEl
  5396. * @type HTMLElement
  5397. */
  5398. errorEl : null,
  5399. /**
  5400. * Reference to the HTMLElement used to update the Calendar/Calendar group
  5401. * with the month/year values
  5402. * @property submitEl
  5403. * @type HTMLElement
  5404. */
  5405. submitEl : null,
  5406. /**
  5407. * Reference to the HTMLElement used to hide the navigator without updating the
  5408. * Calendar/Calendar group
  5409. * @property cancelEl
  5410. * @type HTMLElement
  5411. */
  5412. cancelEl : null,
  5413. /**
  5414. * Reference to the first focusable control in the navigator (by default monthEl)
  5415. * @property firstCtrl
  5416. * @type HTMLElement
  5417. */
  5418. firstCtrl : null,
  5419. /**
  5420. * Reference to the last focusable control in the navigator (by default cancelEl)
  5421. * @property lastCtrl
  5422. * @type HTMLElement
  5423. */
  5424. lastCtrl : null,
  5425. /**
  5426. * The document containing the Calendar/Calendar group instance
  5427. * @protected
  5428. * @property _doc
  5429. * @type HTMLDocument
  5430. */
  5431. _doc : null,
  5432. /**
  5433. * Internal state property for the current year displayed in the navigator
  5434. * @protected
  5435. * @property _year
  5436. * @type Number
  5437. */
  5438. _year: null,
  5439. /**
  5440. * Internal state property for the current month index displayed in the navigator
  5441. * @protected
  5442. * @property _month
  5443. * @type Number
  5444. */
  5445. _month: 0,
  5446. /**
  5447. * Private internal state property which indicates whether or not the
  5448. * Navigator has been rendered.
  5449. * @private
  5450. * @property __rendered
  5451. * @type Boolean
  5452. */
  5453. __rendered: false,
  5454. /**
  5455. * Init lifecycle method called as part of construction
  5456. *
  5457. * @method init
  5458. * @param {Calendar} cal The instance of the Calendar or CalendarGroup to which this CalendarNavigator should be attached
  5459. */
  5460. init : function(cal) {
  5461. var calBox = cal.oDomContainer;
  5462. this.cal = cal;
  5463. this.id = calBox.id + YAHOO.widget.CalendarNavigator.ID_SUFFIX;
  5464. this._doc = calBox.ownerDocument;
  5465. /**
  5466. * Private flag, to identify IE Quirks
  5467. * @private
  5468. * @property __isIEQuirks
  5469. */
  5470. var ie = YAHOO.env.ua.ie;
  5471. this.__isIEQuirks = (ie && ((ie <= 6) || (this._doc.compatMode == "BackCompat")));
  5472. },
  5473. /**
  5474. * Displays the navigator and mask, updating the input controls to reflect the
  5475. * currently set month and year. The show method will invoke the render method
  5476. * if the navigator has not been renderered already, allowing for lazy rendering
  5477. * of the control.
  5478. *
  5479. * The show method will fire the Calendar/CalendarGroup's beforeShowNav and showNav events
  5480. *
  5481. * @method show
  5482. */
  5483. show : function() {
  5484. var CLASSES = YAHOO.widget.CalendarNavigator.CLASSES;
  5485. if (this.cal.beforeShowNavEvent.fire()) {
  5486. if (!this.__rendered) {
  5487. this.render();
  5488. }
  5489. this.clearErrors();
  5490. this._updateMonthUI();
  5491. this._updateYearUI();
  5492. this._show(this.navEl, true);
  5493. this.setInitialFocus();
  5494. this.showMask();
  5495. YAHOO.util.Dom.addClass(this.cal.oDomContainer, CLASSES.NAV_VISIBLE);
  5496. this.cal.showNavEvent.fire();
  5497. }
  5498. },
  5499. /**
  5500. * Hides the navigator and mask
  5501. *
  5502. * The show method will fire the Calendar/CalendarGroup's beforeHideNav event and hideNav events
  5503. * @method hide
  5504. */
  5505. hide : function() {
  5506. var CLASSES = YAHOO.widget.CalendarNavigator.CLASSES;
  5507. if (this.cal.beforeHideNavEvent.fire()) {
  5508. this._show(this.navEl, false);
  5509. this.hideMask();
  5510. YAHOO.util.Dom.removeClass(this.cal.oDomContainer, CLASSES.NAV_VISIBLE);
  5511. this.cal.hideNavEvent.fire();
  5512. }
  5513. },
  5514. /**
  5515. * Displays the navigator's mask element
  5516. *
  5517. * @method showMask
  5518. */
  5519. showMask : function() {
  5520. this._show(this.maskEl, true);
  5521. if (this.__isIEQuirks) {
  5522. this._syncMask();
  5523. }
  5524. },
  5525. /**
  5526. * Hides the navigator's mask element
  5527. *
  5528. * @method hideMask
  5529. */
  5530. hideMask : function() {
  5531. this._show(this.maskEl, false);
  5532. },
  5533. /**
  5534. * Returns the current month set on the navigator
  5535. *
  5536. * Note: This may not be the month set in the UI, if
  5537. * the UI contains an invalid value.
  5538. *
  5539. * @method getMonth
  5540. * @return {Number} The Navigator's current month index
  5541. */
  5542. getMonth: function() {
  5543. return this._month;
  5544. },
  5545. /**
  5546. * Returns the current year set on the navigator
  5547. *
  5548. * Note: This may not be the year set in the UI, if
  5549. * the UI contains an invalid value.
  5550. *
  5551. * @method getYear
  5552. * @return {Number} The Navigator's current year value
  5553. */
  5554. getYear: function() {
  5555. return this._year;
  5556. },
  5557. /**
  5558. * Sets the current month on the Navigator, and updates the UI
  5559. *
  5560. * @method setMonth
  5561. * @param {Number} nMonth The month index, from 0 (Jan) through 11 (Dec).
  5562. */
  5563. setMonth : function(nMonth) {
  5564. if (nMonth >= 0 && nMonth < 12) {
  5565. this._month = nMonth;
  5566. }
  5567. this._updateMonthUI();
  5568. },
  5569. /**
  5570. * Sets the current year on the Navigator, and updates the UI. If the
  5571. * provided year is invalid, it will not be set.
  5572. *
  5573. * @method setYear
  5574. * @param {Number} nYear The full year value to set the Navigator to.
  5575. */
  5576. setYear : function(nYear) {
  5577. var yrPattern = YAHOO.widget.CalendarNavigator.YR_PATTERN;
  5578. if (YAHOO.lang.isNumber(nYear) && yrPattern.test(nYear+"")) {
  5579. this._year = nYear;
  5580. }
  5581. this._updateYearUI();
  5582. },
  5583. /**
  5584. * Renders the HTML for the navigator, adding it to the
  5585. * document and attaches event listeners if it has not
  5586. * already been rendered.
  5587. *
  5588. * @method render
  5589. */
  5590. render: function() {
  5591. this.cal.beforeRenderNavEvent.fire();
  5592. if (!this.__rendered) {
  5593. this.createNav();
  5594. this.createMask();
  5595. this.applyListeners();
  5596. this.__rendered = true;
  5597. }
  5598. this.cal.renderNavEvent.fire();
  5599. },
  5600. /**
  5601. * Creates the navigator's containing HTMLElement, it's contents, and appends
  5602. * the containg element to the Calendar/CalendarGroup's container.
  5603. *
  5604. * @method createNav
  5605. */
  5606. createNav : function() {
  5607. var NAV = YAHOO.widget.CalendarNavigator;
  5608. var doc = this._doc;
  5609. var d = doc.createElement("div");
  5610. d.className = NAV.CLASSES.NAV;
  5611. var htmlBuf = this.renderNavContents([]);
  5612. d.innerHTML = htmlBuf.join('');
  5613. this.cal.oDomContainer.appendChild(d);
  5614. this.navEl = d;
  5615. this.yearEl = doc.getElementById(this.id + NAV.YEAR_SUFFIX);
  5616. this.monthEl = doc.getElementById(this.id + NAV.MONTH_SUFFIX);
  5617. this.errorEl = doc.getElementById(this.id + NAV.ERROR_SUFFIX);
  5618. this.submitEl = doc.getElementById(this.id + NAV.SUBMIT_SUFFIX);
  5619. this.cancelEl = doc.getElementById(this.id + NAV.CANCEL_SUFFIX);
  5620. if (YAHOO.env.ua.gecko && this.yearEl && this.yearEl.type == "text") {
  5621. // Avoid XUL error on focus, select [ https://bugzilla.mozilla.org/show_bug.cgi?id=236791,
  5622. // supposedly fixed in 1.8.1, but there are reports of it still being around for methods other than blur ]
  5623. this.yearEl.setAttribute("autocomplete", "off");
  5624. }
  5625. this._setFirstLastElements();
  5626. },
  5627. /**
  5628. * Creates the Mask HTMLElement and appends it to the Calendar/CalendarGroups
  5629. * container.
  5630. *
  5631. * @method createMask
  5632. */
  5633. createMask : function() {
  5634. var C = YAHOO.widget.CalendarNavigator.CLASSES;
  5635. var d = this._doc.createElement("div");
  5636. d.className = C.MASK;
  5637. this.cal.oDomContainer.appendChild(d);
  5638. this.maskEl = d;
  5639. },
  5640. /**
  5641. * Used to set the width/height of the mask in pixels to match the Calendar Container.
  5642. * Currently only used for IE6 or IE in quirks mode. The other A-Grade browser are handled using CSS (width/height 100%).
  5643. * <p>
  5644. * The method is also registered as an HTMLElement resize listener on the Calendars container element.
  5645. * </p>
  5646. * @protected
  5647. * @method _syncMask
  5648. */
  5649. _syncMask : function() {
  5650. var c = this.cal.oDomContainer;
  5651. if (c && this.maskEl) {
  5652. var r = YAHOO.util.Dom.getRegion(c);
  5653. YAHOO.util.Dom.setStyle(this.maskEl, "width", r.right - r.left + "px");
  5654. YAHOO.util.Dom.setStyle(this.maskEl, "height", r.bottom - r.top + "px");
  5655. }
  5656. },
  5657. /**
  5658. * Renders the contents of the navigator
  5659. *
  5660. * @method renderNavContents
  5661. *
  5662. * @param {Array} html The HTML buffer to append the HTML to.
  5663. * @return {Array} A reference to the buffer passed in.
  5664. */
  5665. renderNavContents : function(html) {
  5666. var NAV = YAHOO.widget.CalendarNavigator,
  5667. C = NAV.CLASSES,
  5668. h = html; // just to use a shorter name
  5669. h[h.length] = '<div class="' + C.MONTH + '">';
  5670. this.renderMonth(h);
  5671. h[h.length] = '</div>';
  5672. h[h.length] = '<div class="' + C.YEAR + '">';
  5673. this.renderYear(h);
  5674. h[h.length] = '</div>';
  5675. h[h.length] = '<div class="' + C.BUTTONS + '">';
  5676. this.renderButtons(h);
  5677. h[h.length] = '</div>';
  5678. h[h.length] = '<div class="' + C.ERROR + '" id="' + this.id + NAV.ERROR_SUFFIX + '"></div>';
  5679. return h;
  5680. },
  5681. /**
  5682. * Renders the month label and control for the navigator
  5683. *
  5684. * @method renderNavContents
  5685. * @param {Array} html The HTML buffer to append the HTML to.
  5686. * @return {Array} A reference to the buffer passed in.
  5687. */
  5688. renderMonth : function(html) {
  5689. var NAV = YAHOO.widget.CalendarNavigator,
  5690. C = NAV.CLASSES;
  5691. var id = this.id + NAV.MONTH_SUFFIX,
  5692. mf = this.__getCfg("monthFormat"),
  5693. months = this.cal.cfg.getProperty((mf == YAHOO.widget.Calendar.SHORT) ? "MONTHS_SHORT" : "MONTHS_LONG"),
  5694. h = html;
  5695. if (months && months.length > 0) {
  5696. h[h.length] = '<label for="' + id + '">';
  5697. h[h.length] = this.__getCfg("month", true);
  5698. h[h.length] = '</label>';
  5699. h[h.length] = '<select name="' + id + '" id="' + id + '" class="' + C.MONTH_CTRL + '">';
  5700. for (var i = 0; i < months.length; i++) {
  5701. h[h.length] = '<option value="' + i + '">';
  5702. h[h.length] = months[i];
  5703. h[h.length] = '</option>';
  5704. }
  5705. h[h.length] = '</select>';
  5706. }
  5707. return h;
  5708. },
  5709. /**
  5710. * Renders the year label and control for the navigator
  5711. *
  5712. * @method renderYear
  5713. * @param {Array} html The HTML buffer to append the HTML to.
  5714. * @return {Array} A reference to the buffer passed in.
  5715. */
  5716. renderYear : function(html) {
  5717. var NAV = YAHOO.widget.CalendarNavigator,
  5718. C = NAV.CLASSES;
  5719. var id = this.id + NAV.YEAR_SUFFIX,
  5720. size = NAV.YR_MAX_DIGITS,
  5721. h = html;
  5722. h[h.length] = '<label for="' + id + '">';
  5723. h[h.length] = this.__getCfg("year", true);
  5724. h[h.length] = '</label>';
  5725. h[h.length] = '<input type="text" name="' + id + '" id="' + id + '" class="' + C.YEAR_CTRL + '" maxlength="' + size + '"/>';
  5726. return h;
  5727. },
  5728. /**
  5729. * Renders the submit/cancel buttons for the navigator
  5730. *
  5731. * @method renderButton
  5732. * @return {String} The HTML created for the Button UI
  5733. */
  5734. renderButtons : function(html) {
  5735. var C = YAHOO.widget.CalendarNavigator.CLASSES;
  5736. var h = html;
  5737. h[h.length] = '<span class="' + C.BUTTON + ' ' + C.DEFAULT + '">';
  5738. h[h.length] = '<button type="button" id="' + this.id + '_submit' + '">';
  5739. h[h.length] = this.__getCfg("submit", true);
  5740. h[h.length] = '</button>';
  5741. h[h.length] = '</span>';
  5742. h[h.length] = '<span class="' + C.BUTTON +'">';
  5743. h[h.length] = '<button type="button" id="' + this.id + '_cancel' + '">';
  5744. h[h.length] = this.__getCfg("cancel", true);
  5745. h[h.length] = '</button>';
  5746. h[h.length] = '</span>';
  5747. return h;
  5748. },
  5749. /**
  5750. * Attaches DOM event listeners to the rendered elements
  5751. * <p>
  5752. * The method will call applyKeyListeners, to setup keyboard specific
  5753. * listeners
  5754. * </p>
  5755. * @method applyListeners
  5756. */
  5757. applyListeners : function() {
  5758. var E = YAHOO.util.Event;
  5759. function yearUpdateHandler() {
  5760. if (this.validate()) {
  5761. this.setYear(this._getYearFromUI());
  5762. }
  5763. }
  5764. function monthUpdateHandler() {
  5765. this.setMonth(this._getMonthFromUI());
  5766. }
  5767. E.on(this.submitEl, "click", this.submit, this, true);
  5768. E.on(this.cancelEl, "click", this.cancel, this, true);
  5769. E.on(this.yearEl, "blur", yearUpdateHandler, this, true);
  5770. E.on(this.monthEl, "change", monthUpdateHandler, this, true);
  5771. if (this.__isIEQuirks) {
  5772. YAHOO.util.Event.on(this.cal.oDomContainer, "resize", this._syncMask, this, true);
  5773. }
  5774. this.applyKeyListeners();
  5775. },
  5776. /**
  5777. * Removes/purges DOM event listeners from the rendered elements
  5778. *
  5779. * @method purgeListeners
  5780. */
  5781. purgeListeners : function() {
  5782. var E = YAHOO.util.Event;
  5783. E.removeListener(this.submitEl, "click", this.submit);
  5784. E.removeListener(this.cancelEl, "click", this.cancel);
  5785. E.removeListener(this.yearEl, "blur");
  5786. E.removeListener(this.monthEl, "change");
  5787. if (this.__isIEQuirks) {
  5788. E.removeListener(this.cal.oDomContainer, "resize", this._syncMask);
  5789. }
  5790. this.purgeKeyListeners();
  5791. },
  5792. /**
  5793. * Attaches DOM listeners for keyboard support.
  5794. * Tab/Shift-Tab looping, Enter Key Submit on Year element,
  5795. * Up/Down/PgUp/PgDown year increment on Year element
  5796. * <p>
  5797. * NOTE: MacOSX Safari 2.x doesn't let you tab to buttons and
  5798. * MacOSX Gecko does not let you tab to buttons or select controls,
  5799. * so for these browsers, Tab/Shift-Tab looping is limited to the
  5800. * elements which can be reached using the tab key.
  5801. * </p>
  5802. * @method applyKeyListeners
  5803. */
  5804. applyKeyListeners : function() {
  5805. var E = YAHOO.util.Event,
  5806. ua = YAHOO.env.ua;
  5807. // IE/Safari 3.1 doesn't fire keypress for arrow/pg keys (non-char keys)
  5808. var arrowEvt = (ua.ie || ua.webkit) ? "keydown" : "keypress";
  5809. // - IE/Safari 3.1 doesn't fire keypress for non-char keys
  5810. // - Opera doesn't allow us to cancel keydown or keypress for tab, but
  5811. // changes focus successfully on keydown (keypress is too late to change focus - opera's already moved on).
  5812. var tabEvt = (ua.ie || ua.opera || ua.webkit) ? "keydown" : "keypress";
  5813. // Everyone likes keypress for Enter (char keys) - whoo hoo!
  5814. E.on(this.yearEl, "keypress", this._handleEnterKey, this, true);
  5815. E.on(this.yearEl, arrowEvt, this._handleDirectionKeys, this, true);
  5816. E.on(this.lastCtrl, tabEvt, this._handleTabKey, this, true);
  5817. E.on(this.firstCtrl, tabEvt, this._handleShiftTabKey, this, true);
  5818. },
  5819. /**
  5820. * Removes/purges DOM listeners for keyboard support
  5821. *
  5822. * @method purgeKeyListeners
  5823. */
  5824. purgeKeyListeners : function() {
  5825. var E = YAHOO.util.Event,
  5826. ua = YAHOO.env.ua;
  5827. var arrowEvt = (ua.ie || ua.webkit) ? "keydown" : "keypress";
  5828. var tabEvt = (ua.ie || ua.opera || ua.webkit) ? "keydown" : "keypress";
  5829. E.removeListener(this.yearEl, "keypress", this._handleEnterKey);
  5830. E.removeListener(this.yearEl, arrowEvt, this._handleDirectionKeys);
  5831. E.removeListener(this.lastCtrl, tabEvt, this._handleTabKey);
  5832. E.removeListener(this.firstCtrl, tabEvt, this._handleShiftTabKey);
  5833. },
  5834. /**
  5835. * Updates the Calendar/CalendarGroup's pagedate with the currently set month and year if valid.
  5836. * <p>
  5837. * If the currently set month/year is invalid, a validation error will be displayed and the
  5838. * Calendar/CalendarGroup's pagedate will not be updated.
  5839. * </p>
  5840. * @method submit
  5841. */
  5842. submit : function() {
  5843. if (this.validate()) {
  5844. this.hide();
  5845. this.setMonth(this._getMonthFromUI());
  5846. this.setYear(this._getYearFromUI());
  5847. var cal = this.cal;
  5848. // Artificial delay, just to help the user see something changed
  5849. var delay = YAHOO.widget.CalendarNavigator.UPDATE_DELAY;
  5850. if (delay > 0) {
  5851. var nav = this;
  5852. window.setTimeout(function(){ nav._update(cal); }, delay);
  5853. } else {
  5854. this._update(cal);
  5855. }
  5856. }
  5857. },
  5858. /**
  5859. * Updates the Calendar rendered state, based on the state of the CalendarNavigator
  5860. * @method _update
  5861. * @param cal The Calendar instance to update
  5862. * @protected
  5863. */
  5864. _update : function(cal) {
  5865. cal.setYear(this.getYear());
  5866. cal.setMonth(this.getMonth());
  5867. cal.render();
  5868. },
  5869. /**
  5870. * Hides the navigator and mask, without updating the Calendar/CalendarGroup's state
  5871. *
  5872. * @method cancel
  5873. */
  5874. cancel : function() {
  5875. this.hide();
  5876. },
  5877. /**
  5878. * Validates the current state of the UI controls
  5879. *
  5880. * @method validate
  5881. * @return {Boolean} true, if the current UI state contains valid values, false if not
  5882. */
  5883. validate : function() {
  5884. if (this._getYearFromUI() !== null) {
  5885. this.clearErrors();
  5886. return true;
  5887. } else {
  5888. this.setYearError();
  5889. this.setError(this.__getCfg("invalidYear", true));
  5890. return false;
  5891. }
  5892. },
  5893. /**
  5894. * Displays an error message in the Navigator's error panel
  5895. * @method setError
  5896. * @param {String} msg The error message to display
  5897. */
  5898. setError : function(msg) {
  5899. if (this.errorEl) {
  5900. this.errorEl.innerHTML = msg;
  5901. this._show(this.errorEl, true);
  5902. }
  5903. },
  5904. /**
  5905. * Clears the navigator's error message and hides the error panel
  5906. * @method clearError
  5907. */
  5908. clearError : function() {
  5909. if (this.errorEl) {
  5910. this.errorEl.innerHTML = "";
  5911. this._show(this.errorEl, false);
  5912. }
  5913. },
  5914. /**
  5915. * Displays the validation error UI for the year control
  5916. * @method setYearError
  5917. */
  5918. setYearError : function() {
  5919. YAHOO.util.Dom.addClass(this.yearEl, YAHOO.widget.CalendarNavigator.CLASSES.INVALID);
  5920. },
  5921. /**
  5922. * Removes the validation error UI for the year control
  5923. * @method clearYearError
  5924. */
  5925. clearYearError : function() {
  5926. YAHOO.util.Dom.removeClass(this.yearEl, YAHOO.widget.CalendarNavigator.CLASSES.INVALID);
  5927. },
  5928. /**
  5929. * Clears all validation and error messages in the UI
  5930. * @method clearErrors
  5931. */
  5932. clearErrors : function() {
  5933. this.clearError();
  5934. this.clearYearError();
  5935. },
  5936. /**
  5937. * Sets the initial focus, based on the configured value
  5938. * @method setInitialFocus
  5939. */
  5940. setInitialFocus : function() {
  5941. var el = this.submitEl,
  5942. f = this.__getCfg("initialFocus");
  5943. if (f && f.toLowerCase) {
  5944. f = f.toLowerCase();
  5945. if (f == "year") {
  5946. el = this.yearEl;
  5947. try {
  5948. this.yearEl.select();
  5949. } catch (selErr) {
  5950. // Ignore;
  5951. }
  5952. } else if (f == "month") {
  5953. el = this.monthEl;
  5954. }
  5955. }
  5956. if (el && YAHOO.lang.isFunction(el.focus)) {
  5957. try {
  5958. el.focus();
  5959. } catch (focusErr) {
  5960. // TODO: Fall back if focus fails?
  5961. }
  5962. }
  5963. },
  5964. /**
  5965. * Removes all renderered HTML elements for the Navigator from
  5966. * the DOM, purges event listeners and clears (nulls) any property
  5967. * references to HTML references
  5968. * @method erase
  5969. */
  5970. erase : function() {
  5971. if (this.__rendered) {
  5972. this.purgeListeners();
  5973. // Clear out innerHTML references
  5974. this.yearEl = null;
  5975. this.monthEl = null;
  5976. this.errorEl = null;
  5977. this.submitEl = null;
  5978. this.cancelEl = null;
  5979. this.firstCtrl = null;
  5980. this.lastCtrl = null;
  5981. if (this.navEl) {
  5982. this.navEl.innerHTML = "";
  5983. }
  5984. var p = this.navEl.parentNode;
  5985. if (p) {
  5986. p.removeChild(this.navEl);
  5987. }
  5988. this.navEl = null;
  5989. var pm = this.maskEl.parentNode;
  5990. if (pm) {
  5991. pm.removeChild(this.maskEl);
  5992. }
  5993. this.maskEl = null;
  5994. this.__rendered = false;
  5995. }
  5996. },
  5997. /**
  5998. * Destroys the Navigator object and any HTML references
  5999. * @method destroy
  6000. */
  6001. destroy : function() {
  6002. this.erase();
  6003. this._doc = null;
  6004. this.cal = null;
  6005. this.id = null;
  6006. },
  6007. /**
  6008. * Protected implementation to handle how UI elements are
  6009. * hidden/shown.
  6010. *
  6011. * @method _show
  6012. * @protected
  6013. */
  6014. _show : function(el, bShow) {
  6015. if (el) {
  6016. YAHOO.util.Dom.setStyle(el, "display", (bShow) ? "block" : "none");
  6017. }
  6018. },
  6019. /**
  6020. * Returns the month value (index), from the month UI element
  6021. * @protected
  6022. * @method _getMonthFromUI
  6023. * @return {Number} The month index, or 0 if a UI element for the month
  6024. * is not found
  6025. */
  6026. _getMonthFromUI : function() {
  6027. if (this.monthEl) {
  6028. return this.monthEl.selectedIndex;
  6029. } else {
  6030. return 0; // Default to Jan
  6031. }
  6032. },
  6033. /**
  6034. * Returns the year value, from the Navitator's year UI element
  6035. * @protected
  6036. * @method _getYearFromUI
  6037. * @return {Number} The year value set in the UI, if valid. null is returned if
  6038. * the UI does not contain a valid year value.
  6039. */
  6040. _getYearFromUI : function() {
  6041. var NAV = YAHOO.widget.CalendarNavigator;
  6042. var yr = null;
  6043. if (this.yearEl) {
  6044. var value = this.yearEl.value;
  6045. value = value.replace(NAV.TRIM, "$1");
  6046. if (NAV.YR_PATTERN.test(value)) {
  6047. yr = parseInt(value, 10);
  6048. }
  6049. }
  6050. return yr;
  6051. },
  6052. /**
  6053. * Updates the Navigator's year UI, based on the year value set on the Navigator object
  6054. * @protected
  6055. * @method _updateYearUI
  6056. */
  6057. _updateYearUI : function() {
  6058. if (this.yearEl && this._year !== null) {
  6059. this.yearEl.value = this._year;
  6060. }
  6061. },
  6062. /**
  6063. * Updates the Navigator's month UI, based on the month value set on the Navigator object
  6064. * @protected
  6065. * @method _updateMonthUI
  6066. */
  6067. _updateMonthUI : function() {
  6068. if (this.monthEl) {
  6069. this.monthEl.selectedIndex = this._month;
  6070. }
  6071. },
  6072. /**
  6073. * Sets up references to the first and last focusable element in the Navigator's UI
  6074. * in terms of tab order (Naviagator's firstEl and lastEl properties). The references
  6075. * are used to control modality by looping around from the first to the last control
  6076. * and visa versa for tab/shift-tab navigation.
  6077. * <p>
  6078. * See <a href="#applyKeyListeners">applyKeyListeners</a>
  6079. * </p>
  6080. * @protected
  6081. * @method _setFirstLastElements
  6082. */
  6083. _setFirstLastElements : function() {
  6084. this.firstCtrl = this.monthEl;
  6085. this.lastCtrl = this.cancelEl;
  6086. // Special handling for MacOSX.
  6087. // - Safari 2.x can't focus on buttons
  6088. // - Gecko can't focus on select boxes or buttons
  6089. if (this.__isMac) {
  6090. if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420){
  6091. this.firstCtrl = this.monthEl;
  6092. this.lastCtrl = this.yearEl;
  6093. }
  6094. if (YAHOO.env.ua.gecko) {
  6095. this.firstCtrl = this.yearEl;
  6096. this.lastCtrl = this.yearEl;
  6097. }
  6098. }
  6099. },
  6100. /**
  6101. * Default Keyboard event handler to capture Enter
  6102. * on the Navigator's year control (yearEl)
  6103. *
  6104. * @method _handleEnterKey
  6105. * @protected
  6106. * @param {Event} e The DOM event being handled
  6107. */
  6108. _handleEnterKey : function(e) {
  6109. var KEYS = YAHOO.util.KeyListener.KEY;
  6110. if (YAHOO.util.Event.getCharCode(e) == KEYS.ENTER) {
  6111. YAHOO.util.Event.preventDefault(e);
  6112. this.submit();
  6113. }
  6114. },
  6115. /**
  6116. * Default Keyboard event handler to capture up/down/pgup/pgdown
  6117. * on the Navigator's year control (yearEl).
  6118. *
  6119. * @method _handleDirectionKeys
  6120. * @protected
  6121. * @param {Event} e The DOM event being handled
  6122. */
  6123. _handleDirectionKeys : function(e) {
  6124. var E = YAHOO.util.Event,
  6125. KEYS = YAHOO.util.KeyListener.KEY,
  6126. NAV = YAHOO.widget.CalendarNavigator;
  6127. var value = (this.yearEl.value) ? parseInt(this.yearEl.value, 10) : null;
  6128. if (isFinite(value)) {
  6129. var dir = false;
  6130. switch(E.getCharCode(e)) {
  6131. case KEYS.UP:
  6132. this.yearEl.value = value + NAV.YR_MINOR_INC;
  6133. dir = true;
  6134. break;
  6135. case KEYS.DOWN:
  6136. this.yearEl.value = Math.max(value - NAV.YR_MINOR_INC, 0);
  6137. dir = true;
  6138. break;
  6139. case KEYS.PAGE_UP:
  6140. this.yearEl.value = value + NAV.YR_MAJOR_INC;
  6141. dir = true;
  6142. break;
  6143. case KEYS.PAGE_DOWN:
  6144. this.yearEl.value = Math.max(value - NAV.YR_MAJOR_INC, 0);
  6145. dir = true;
  6146. break;
  6147. default:
  6148. break;
  6149. }
  6150. if (dir) {
  6151. E.preventDefault(e);
  6152. try {
  6153. this.yearEl.select();
  6154. } catch(err) {
  6155. // Ignore
  6156. }
  6157. }
  6158. }
  6159. },
  6160. /**
  6161. * Default Keyboard event handler to capture Tab
  6162. * on the last control (lastCtrl) in the Navigator.
  6163. *
  6164. * @method _handleTabKey
  6165. * @protected
  6166. * @param {Event} e The DOM event being handled
  6167. */
  6168. _handleTabKey : function(e) {
  6169. var E = YAHOO.util.Event,
  6170. KEYS = YAHOO.util.KeyListener.KEY;
  6171. if (E.getCharCode(e) == KEYS.TAB && !e.shiftKey) {
  6172. try {
  6173. E.preventDefault(e);
  6174. this.firstCtrl.focus();
  6175. } catch (err) {
  6176. // Ignore - mainly for focus edge cases
  6177. }
  6178. }
  6179. },
  6180. /**
  6181. * Default Keyboard event handler to capture Shift-Tab
  6182. * on the first control (firstCtrl) in the Navigator.
  6183. *
  6184. * @method _handleShiftTabKey
  6185. * @protected
  6186. * @param {Event} e The DOM event being handled
  6187. */
  6188. _handleShiftTabKey : function(e) {
  6189. var E = YAHOO.util.Event,
  6190. KEYS = YAHOO.util.KeyListener.KEY;
  6191. if (e.shiftKey && E.getCharCode(e) == KEYS.TAB) {
  6192. try {
  6193. E.preventDefault(e);
  6194. this.lastCtrl.focus();
  6195. } catch (err) {
  6196. // Ignore - mainly for focus edge cases
  6197. }
  6198. }
  6199. },
  6200. /**
  6201. * Retrieve Navigator configuration values from
  6202. * the parent Calendar/CalendarGroup's config value.
  6203. * <p>
  6204. * If it has not been set in the user provided configuration, the method will
  6205. * return the default value of the configuration property, as set in _DEFAULT_CFG
  6206. * </p>
  6207. * @private
  6208. * @method __getCfg
  6209. * @param {String} Case sensitive property name.
  6210. * @param {Boolean} true, if the property is a string property, false if not.
  6211. * @return The value of the configuration property
  6212. */
  6213. __getCfg : function(prop, bIsStr) {
  6214. var DEF_CFG = YAHOO.widget.CalendarNavigator._DEFAULT_CFG;
  6215. var cfg = this.cal.cfg.getProperty("navigator");
  6216. if (bIsStr) {
  6217. return (cfg !== true && cfg.strings && cfg.strings[prop]) ? cfg.strings[prop] : DEF_CFG.strings[prop];
  6218. } else {
  6219. return (cfg !== true && cfg[prop]) ? cfg[prop] : DEF_CFG[prop];
  6220. }
  6221. },
  6222. /**
  6223. * Private flag, to identify MacOS
  6224. * @private
  6225. * @property __isMac
  6226. */
  6227. __isMac : (navigator.userAgent.toLowerCase().indexOf("macintosh") != -1)
  6228. };
  6229. YAHOO.register("calendar", YAHOO.widget.Calendar, {version: "2.7.0", build: "1799"});