PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

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

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