PageRenderTime 67ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/hippo/src/main/webapp/yui/container/container_core-debug.js

http://hdbc.googlecode.com/
JavaScript | 1887 lines | 808 code | 290 blank | 789 comment | 193 complexity | 47b862b306ac8a9f79362606f6434565 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. (function () {
  559. /**
  560. * The Container family of components is designed to enable developers to
  561. * create different kinds of content-containing modules on the web. Module
  562. * and Overlay are the most basic containers, and they can be used directly
  563. * or extended to build custom containers. Also part of the Container family
  564. * are four UI controls that extend Module and Overlay: Tooltip, Panel,
  565. * Dialog, and SimpleDialog.
  566. * @module container
  567. * @title Container
  568. * @requires yahoo, dom, event
  569. * @optional dragdrop, animation, button
  570. */
  571. /**
  572. * Module is a JavaScript representation of the Standard Module Format.
  573. * Standard Module Format is a simple standard for markup containers where
  574. * child nodes representing the header, body, and footer of the content are
  575. * denoted using the CSS classes "hd", "bd", and "ft" respectively.
  576. * Module is the base class for all other classes in the YUI
  577. * Container package.
  578. * @namespace YAHOO.widget
  579. * @class Module
  580. * @constructor
  581. * @param {String} el The element ID representing the Module <em>OR</em>
  582. * @param {HTMLElement} el The element representing the Module
  583. * @param {Object} userConfig The configuration Object literal containing
  584. * the configuration that should be set for this module. See configuration
  585. * documentation for more details.
  586. */
  587. YAHOO.widget.Module = function (el, userConfig) {
  588. if (el) {
  589. this.init(el, userConfig);
  590. } else {
  591. YAHOO.log("No element or element ID specified" +
  592. " for Module instantiation", "error");
  593. }
  594. };
  595. var Dom = YAHOO.util.Dom,
  596. Config = YAHOO.util.Config,
  597. Event = YAHOO.util.Event,
  598. CustomEvent = YAHOO.util.CustomEvent,
  599. Module = YAHOO.widget.Module,
  600. UA = YAHOO.env.ua,
  601. m_oModuleTemplate,
  602. m_oHeaderTemplate,
  603. m_oBodyTemplate,
  604. m_oFooterTemplate,
  605. /**
  606. * Constant representing the name of the Module's events
  607. * @property EVENT_TYPES
  608. * @private
  609. * @final
  610. * @type Object
  611. */
  612. EVENT_TYPES = {
  613. "BEFORE_INIT": "beforeInit",
  614. "INIT": "init",
  615. "APPEND": "append",
  616. "BEFORE_RENDER": "beforeRender",
  617. "RENDER": "render",
  618. "CHANGE_HEADER": "changeHeader",
  619. "CHANGE_BODY": "changeBody",
  620. "CHANGE_FOOTER": "changeFooter",
  621. "CHANGE_CONTENT": "changeContent",
  622. "DESTORY": "destroy",
  623. "BEFORE_SHOW": "beforeShow",
  624. "SHOW": "show",
  625. "BEFORE_HIDE": "beforeHide",
  626. "HIDE": "hide"
  627. },
  628. /**
  629. * Constant representing the Module's configuration properties
  630. * @property DEFAULT_CONFIG
  631. * @private
  632. * @final
  633. * @type Object
  634. */
  635. DEFAULT_CONFIG = {
  636. "VISIBLE": {
  637. key: "visible",
  638. value: true,
  639. validator: YAHOO.lang.isBoolean
  640. },
  641. "EFFECT": {
  642. key: "effect",
  643. suppressEvent: true,
  644. supercedes: ["visible"]
  645. },
  646. "MONITOR_RESIZE": {
  647. key: "monitorresize",
  648. value: true
  649. },
  650. "APPEND_TO_DOCUMENT_BODY": {
  651. key: "appendtodocumentbody",
  652. value: false
  653. }
  654. };
  655. /**
  656. * Constant representing the prefix path to use for non-secure images
  657. * @property YAHOO.widget.Module.IMG_ROOT
  658. * @static
  659. * @final
  660. * @type String
  661. */
  662. Module.IMG_ROOT = null;
  663. /**
  664. * Constant representing the prefix path to use for securely served images
  665. * @property YAHOO.widget.Module.IMG_ROOT_SSL
  666. * @static
  667. * @final
  668. * @type String
  669. */
  670. Module.IMG_ROOT_SSL = null;
  671. /**
  672. * Constant for the default CSS class name that represents a Module
  673. * @property YAHOO.widget.Module.CSS_MODULE
  674. * @static
  675. * @final
  676. * @type String
  677. */
  678. Module.CSS_MODULE = "yui-module";
  679. /**
  680. * Constant representing the module header
  681. * @property YAHOO.widget.Module.CSS_HEADER
  682. * @static
  683. * @final
  684. * @type String
  685. */
  686. Module.CSS_HEADER = "hd";
  687. /**
  688. * Constant representing the module body
  689. * @property YAHOO.widget.Module.CSS_BODY
  690. * @static
  691. * @final
  692. * @type String
  693. */
  694. Module.CSS_BODY = "bd";
  695. /**
  696. * Constant representing the module footer
  697. * @property YAHOO.widget.Module.CSS_FOOTER
  698. * @static
  699. * @final
  700. * @type String
  701. */
  702. Module.CSS_FOOTER = "ft";
  703. /**
  704. * Constant representing the url for the "src" attribute of the iframe
  705. * used to monitor changes to the browser's base font size
  706. * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
  707. * @static
  708. * @final
  709. * @type String
  710. */
  711. Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
  712. /**
  713. * Constant representing the buffer amount (in pixels) to use when positioning
  714. * the text resize monitor offscreen. The resize monitor is positioned
  715. * offscreen by an amount eqaul to its offsetHeight + the buffer value.
  716. *
  717. * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
  718. * @static
  719. * @type Number
  720. */
  721. // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
  722. Module.RESIZE_MONITOR_BUFFER = 1;
  723. /**
  724. * Singleton CustomEvent fired when the font size is changed in the browser.
  725. * Opera's "zoom" functionality currently does not support text
  726. * size detection.
  727. * @event YAHOO.widget.Module.textResizeEvent
  728. */
  729. Module.textResizeEvent = new CustomEvent("textResize");
  730. /**
  731. * Helper utility method, which forces a document level
  732. * redraw for Opera, which can help remove repaint
  733. * irregularities after applying DOM changes.
  734. *
  735. * @method YAHOO.widget.Module.forceDocumentRedraw
  736. * @static
  737. */
  738. Module.forceDocumentRedraw = function() {
  739. var docEl = document.documentElement;
  740. if (docEl) {
  741. docEl.className += " ";
  742. docEl.className = YAHOO.lang.trim(docEl.className);
  743. }
  744. };
  745. function createModuleTemplate() {
  746. if (!m_oModuleTemplate) {
  747. m_oModuleTemplate = document.createElement("div");
  748. m_oModuleTemplate.innerHTML = ("<div class=\"" +
  749. Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
  750. Module.CSS_BODY + "\"></div><div class=\"" +
  751. Module.CSS_FOOTER + "\"></div>");
  752. m_oHeaderTemplate = m_oModuleTemplate.firstChild;
  753. m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
  754. m_oFooterTemplate = m_oBodyTemplate.nextSibling;
  755. }
  756. return m_oModuleTemplate;
  757. }
  758. function createHeader() {
  759. if (!m_oHeaderTemplate) {
  760. createModuleTemplate();
  761. }
  762. return (m_oHeaderTemplate.cloneNode(false));
  763. }
  764. function createBody() {
  765. if (!m_oBodyTemplate) {
  766. createModuleTemplate();
  767. }
  768. return (m_oBodyTemplate.cloneNode(false));
  769. }
  770. function createFooter() {
  771. if (!m_oFooterTemplate) {
  772. createModuleTemplate();
  773. }
  774. return (m_oFooterTemplate.cloneNode(false));
  775. }
  776. Module.prototype = {
  777. /**
  778. * The class's constructor function
  779. * @property contructor
  780. * @type Function
  781. */
  782. constructor: Module,
  783. /**
  784. * The main module element that contains the header, body, and footer
  785. * @property element
  786. * @type HTMLElement
  787. */
  788. element: null,
  789. /**
  790. * The header element, denoted with CSS class "hd"
  791. * @property header
  792. * @type HTMLElement
  793. */
  794. header: null,
  795. /**
  796. * The body element, denoted with CSS class "bd"
  797. * @property body
  798. * @type HTMLElement
  799. */
  800. body: null,
  801. /**
  802. * The footer element, denoted with CSS class "ft"
  803. * @property footer
  804. * @type HTMLElement
  805. */
  806. footer: null,
  807. /**
  808. * The id of the element
  809. * @property id
  810. * @type String
  811. */
  812. id: null,
  813. /**
  814. * A string representing the root path for all images created by
  815. * a Module instance.
  816. * @deprecated It is recommend that any images for a Module be applied
  817. * via CSS using the "background-image" property.
  818. * @property imageRoot
  819. * @type String
  820. */
  821. imageRoot: Module.IMG_ROOT,
  822. /**
  823. * Initializes the custom events for Module which are fired
  824. * automatically at appropriate times by the Module class.
  825. * @method initEvents
  826. */
  827. initEvents: function () {
  828. var SIGNATURE = CustomEvent.LIST;
  829. /**
  830. * CustomEvent fired prior to class initalization.
  831. * @event beforeInitEvent
  832. * @param {class} classRef class reference of the initializing
  833. * class, such as this.beforeInitEvent.fire(Module)
  834. */
  835. this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
  836. this.beforeInitEvent.signature = SIGNATURE;
  837. /**
  838. * CustomEvent fired after class initalization.
  839. * @event initEvent
  840. * @param {class} classRef class reference of the initializing
  841. * class, such as this.beforeInitEvent.fire(Module)
  842. */
  843. this.initEvent = this.createEvent(EVENT_TYPES.INIT);
  844. this.initEvent.signature = SIGNATURE;
  845. /**
  846. * CustomEvent fired when the Module is appended to the DOM
  847. * @event appendEvent
  848. */
  849. this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
  850. this.appendEvent.signature = SIGNATURE;
  851. /**
  852. * CustomEvent fired before the Module is rendered
  853. * @event beforeRenderEvent
  854. */
  855. this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
  856. this.beforeRenderEvent.signature = SIGNATURE;
  857. /**
  858. * CustomEvent fired after the Module is rendered
  859. * @event renderEvent
  860. */
  861. this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
  862. this.renderEvent.signature = SIGNATURE;
  863. /**
  864. * CustomEvent fired when the header content of the Module
  865. * is modified
  866. * @event changeHeaderEvent
  867. * @param {String/HTMLElement} content String/element representing
  868. * the new header content
  869. */
  870. this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
  871. this.changeHeaderEvent.signature = SIGNATURE;
  872. /**
  873. * CustomEvent fired when the body content of the Module is modified
  874. * @event changeBodyEvent
  875. * @param {String/HTMLElement} content String/element representing
  876. * the new body content
  877. */
  878. this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
  879. this.changeBodyEvent.signature = SIGNATURE;
  880. /**
  881. * CustomEvent fired when the footer content of the Module
  882. * is modified
  883. * @event changeFooterEvent
  884. * @param {String/HTMLElement} content String/element representing
  885. * the new footer content
  886. */
  887. this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
  888. this.changeFooterEvent.signature = SIGNATURE;
  889. /**
  890. * CustomEvent fired when the content of the Module is modified
  891. * @event changeContentEvent
  892. */
  893. this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
  894. this.changeContentEvent.signature = SIGNATURE;
  895. /**
  896. * CustomEvent fired when the Module is destroyed
  897. * @event destroyEvent
  898. */
  899. this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
  900. this.destroyEvent.signature = SIGNATURE;
  901. /**
  902. * CustomEvent fired before the Module is shown
  903. * @event beforeShowEvent
  904. */
  905. this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
  906. this.beforeShowEvent.signature = SIGNATURE;
  907. /**
  908. * CustomEvent fired after the Module is shown
  909. * @event showEvent
  910. */
  911. this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
  912. this.showEvent.signature = SIGNATURE;
  913. /**
  914. * CustomEvent fired before the Module is hidden
  915. * @event beforeHideEvent
  916. */
  917. this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
  918. this.beforeHideEvent.signature = SIGNATURE;
  919. /**
  920. * CustomEvent fired after the Module is hidden
  921. * @event hideEvent
  922. */
  923. this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
  924. this.hideEvent.signature = SIGNATURE;
  925. },
  926. /**
  927. * String representing the current user-agent platform
  928. * @property platform
  929. * @type String
  930. */
  931. platform: function () {
  932. var ua = navigator.userAgent.toLowerCase();
  933. if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
  934. return "windows";
  935. } else if (ua.indexOf("macintosh") != -1) {
  936. return "mac";
  937. } else {
  938. return false;
  939. }
  940. }(),
  941. /**
  942. * String representing the user-agent of the browser
  943. * @deprecated Use YAHOO.env.ua
  944. * @property browser
  945. * @type String
  946. */
  947. browser: function () {
  948. var ua = navigator.userAgent.toLowerCase();
  949. /*
  950. Check Opera first in case of spoof and check Safari before
  951. Gecko since Safari's user agent string includes "like Gecko"
  952. */
  953. if (ua.indexOf('opera') != -1) {
  954. return 'opera';
  955. } else if (ua.indexOf('msie 7') != -1) {
  956. return 'ie7';
  957. } else if (ua.indexOf('msie') != -1) {
  958. return 'ie';
  959. } else if (ua.indexOf('safari') != -1) {
  960. return 'safari';
  961. } else if (ua.indexOf('gecko') != -1) {
  962. return 'gecko';
  963. } else {
  964. return false;
  965. }
  966. }(),
  967. /**
  968. * Boolean representing whether or not the current browsing context is
  969. * secure (https)
  970. * @property isSecure
  971. * @type Boolean
  972. */
  973. isSecure: function () {
  974. if (window.location.href.toLowerCase().indexOf("https") === 0) {
  975. return true;
  976. } else {
  977. return false;
  978. }
  979. }(),
  980. /**
  981. * Initializes the custom events for Module which are fired
  982. * automatically at appropriate times by the Module class.
  983. */
  984. initDefaultConfig: function () {
  985. // Add properties //
  986. /**
  987. * Specifies whether the Module is visible on the page.
  988. * @config visible
  989. * @type Boolean
  990. * @default true
  991. */
  992. this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
  993. handler: this.configVisible,
  994. value: DEFAULT_CONFIG.VISIBLE.value,
  995. validator: DEFAULT_CONFIG.VISIBLE.validator
  996. });
  997. /**
  998. * <p>
  999. * Object or array of objects representing the ContainerEffect
  1000. * classes that are active for animating the container.
  1001. * </p>
  1002. * <p>
  1003. * <strong>NOTE:</strong> Although this configuration
  1004. * property is introduced at the Module level, an out of the box
  1005. * implementation is not shipped for the Module class so setting
  1006. * the proroperty on the Module class has no effect. The Overlay
  1007. * class is the first class to provide out of the box ContainerEffect
  1008. * support.
  1009. * </p>
  1010. * @config effect
  1011. * @type Object
  1012. * @default null
  1013. */
  1014. this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
  1015. suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
  1016. supercedes: DEFAULT_CONFIG.EFFECT.supercedes
  1017. });
  1018. /**
  1019. * Specifies whether to create a special proxy iframe to monitor
  1020. * for user font resizing in the document
  1021. * @config monitorresize
  1022. * @type Boolean
  1023. * @default true
  1024. */
  1025. this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
  1026. handler: this.configMonitorResize,
  1027. value: DEFAULT_CONFIG.MONITOR_RESIZE.value
  1028. });
  1029. /**
  1030. * Specifies if the module should be rendered as the first child
  1031. * of document.body or appended as the last child when render is called
  1032. * with document.body as the "appendToNode".
  1033. * <p>
  1034. * Appending to the body while the DOM is still being constructed can
  1035. * lead to Operation Aborted errors in IE hence this flag is set to
  1036. * false by default.
  1037. * </p>
  1038. *
  1039. * @config appendtodocumentbody
  1040. * @type Boolean
  1041. * @default false
  1042. */
  1043. this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
  1044. value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
  1045. });
  1046. },
  1047. /**
  1048. * The Module class's initialization method, which is executed for
  1049. * Module and all of its subclasses. This method is automatically
  1050. * called by the constructor, and sets up all DOM references for
  1051. * pre-existing markup, and creates required markup if it is not
  1052. * already present.
  1053. * <p>
  1054. * If the element passed in does not have an id, one will be generated
  1055. * for it.
  1056. * </p>
  1057. * @method init
  1058. * @param {String} el The element ID representing the Module <em>OR</em>
  1059. * @param {HTMLElement} el The element representing the Module
  1060. * @param {Object} userConfig The configuration Object literal
  1061. * containing the configuration that should be set for this module.
  1062. * See configuration documentation for more details.
  1063. */
  1064. init: function (el, userConfig) {
  1065. var elId, child;
  1066. this.initEvents();
  1067. this.beforeInitEvent.fire(Module);
  1068. /**
  1069. * The Module's Config object used for monitoring
  1070. * configuration properties.
  1071. * @property cfg
  1072. * @type YAHOO.util.Config
  1073. */
  1074. this.cfg = new Config(this);
  1075. if (this.isSecure) {
  1076. this.imageRoot = Module.IMG_ROOT_SSL;
  1077. }
  1078. if (typeof el == "string") {
  1079. elId = el;
  1080. el = document.getElementById(el);
  1081. if (! el) {
  1082. el = (createModuleTemplate()).cloneNode(false);
  1083. el.id = elId;
  1084. }
  1085. }
  1086. this.id = Dom.generateId(el);
  1087. this.element = el;
  1088. child = this.element.firstChild;
  1089. if (child) {
  1090. var fndHd = false, fndBd = false, fndFt = false;
  1091. do {
  1092. // We're looking for elements
  1093. if (1 == child.nodeType) {
  1094. if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
  1095. this.header = child;
  1096. fndHd = true;
  1097. } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
  1098. this.body = child;
  1099. fndBd = true;
  1100. } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
  1101. this.footer = child;
  1102. fndFt = true;
  1103. }
  1104. }
  1105. } while ((child = child.nextSibling));
  1106. }
  1107. this.initDefaultConfig();
  1108. Dom.addClass(this.element, Module.CSS_MODULE);
  1109. if (userConfig) {
  1110. this.cfg.applyConfig(userConfig, true);
  1111. }
  1112. /*
  1113. Subscribe to the fireQueue() method of Config so that any
  1114. queued configuration changes are excecuted upon render of
  1115. the Module
  1116. */
  1117. if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
  1118. this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
  1119. }
  1120. this.initEvent.fire(Module);
  1121. },
  1122. /**
  1123. * Initialize an empty IFRAME that is placed out of the visible area
  1124. * that can be used to detect text resize.
  1125. * @method initResizeMonitor
  1126. */
  1127. initResizeMonitor: function () {
  1128. var isGeckoWin = (UA.gecko && this.platform == "windows");
  1129. if (isGeckoWin) {
  1130. // Help prevent spinning loading icon which
  1131. // started with FireFox 2.0.0.8/Win
  1132. var self = this;
  1133. setTimeout(function(){self._initResizeMonitor();}, 0);
  1134. } else {
  1135. this._initResizeMonitor();
  1136. }
  1137. },
  1138. /**
  1139. * Create and initialize the text resize monitoring iframe.
  1140. *
  1141. * @protected
  1142. * @method _initResizeMonitor
  1143. */
  1144. _initResizeMonitor : function() {
  1145. var oDoc,
  1146. oIFrame,
  1147. sHTML;
  1148. function fireTextResize() {
  1149. Module.textResizeEvent.fire();
  1150. }
  1151. if (!UA.opera) {
  1152. oIFrame = Dom.get("_yuiResizeMonitor");
  1153. var supportsCWResize = this._supportsCWResize();
  1154. if (!oIFrame) {
  1155. oIFrame = document.createElement("iframe");
  1156. if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
  1157. oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
  1158. }
  1159. if (!supportsCWResize) {
  1160. // Can't monitor on contentWindow, so fire from inside iframe
  1161. sHTML = ["<html><head><script ",
  1162. "type=\"text/javascript\">",
  1163. "window.onresize=function(){window.parent.",
  1164. "YAHOO.widget.Module.textResizeEvent.",
  1165. "fire();};<",
  1166. "\/script></head>",
  1167. "<body></body></html>"].join('');
  1168. oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
  1169. }
  1170. oIFrame.id = "_yuiResizeMonitor";
  1171. oIFrame.title = "Text Resize Monitor";
  1172. /*
  1173. Need to set "position" property before inserting the
  1174. iframe into the document or Safari's status bar will
  1175. forever indicate the iframe is loading
  1176. (See SourceForge bug #1723064)
  1177. */
  1178. oIFrame.style.position = "absolute";
  1179. oIFrame.style.visibility = "hidden";
  1180. var db = document.body,
  1181. fc = db.firstChild;
  1182. if (fc) {
  1183. db.insertBefore(oIFrame, fc);
  1184. } else {
  1185. db.appendChild(oIFrame);
  1186. }
  1187. oIFrame.style.width = "2em";
  1188. oIFrame.style.height = "2em";
  1189. oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
  1190. oIFrame.style.left = "0";
  1191. oIFrame.style.borderWidth = "0";
  1192. oIFrame.style.visibility = "visible";
  1193. /*
  1194. Don't open/close the document for Gecko like we used to, since it
  1195. leads to duplicate cookies. (See SourceForge bug #1721755)
  1196. */
  1197. if (UA.webkit) {
  1198. oDoc = oIFrame.contentWindow.document;
  1199. oDoc.open();
  1200. oDoc.close();
  1201. }
  1202. }
  1203. if (oIFrame && oIFrame.contentWindow) {
  1204. Module.textResizeEvent.subscribe(this.onDomResize, this, true);
  1205. if (!Module.textResizeInitialized) {
  1206. if (supportsCWResize) {
  1207. if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
  1208. /*
  1209. This will fail in IE if document.domain has
  1210. changed, so we must change the listener to
  1211. use the oIFrame element instead
  1212. */
  1213. Event.on(oIFrame, "resize", fireTextResize);
  1214. }
  1215. }
  1216. Module.textResizeInitialized = true;
  1217. }
  1218. this.resizeMonitor = oIFrame;
  1219. }
  1220. }
  1221. },
  1222. /**
  1223. * Text resize monitor helper method.
  1224. * Determines if the browser supports resize events on iframe content windows.
  1225. *
  1226. * @private
  1227. * @method _supportsCWResize
  1228. */
  1229. _supportsCWResize : function() {
  1230. /*
  1231. Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
  1232. Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
  1233. We don't want to start sniffing for patch versions, so fire textResize the same
  1234. way on all FF2 flavors
  1235. */
  1236. var bSupported = true;
  1237. if (UA.gecko && UA.gecko <= 1.8) {
  1238. bSupported = false;
  1239. }
  1240. return bSupported;
  1241. },
  1242. /**
  1243. * Event handler fired when the resize monitor element is resized.
  1244. * @method onDomResize
  1245. * @param {DOMEvent} e The DOM resize event
  1246. * @param {Object} obj The scope object passed to the handler
  1247. */
  1248. onDomResize: function (e, obj) {
  1249. var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
  1250. this.resizeMonitor.style.top = nTop + "px";
  1251. this.resizeMonitor.style.left = "0";
  1252. },
  1253. /**
  1254. * Sets the Module's header content to the string specified, or appends
  1255. * the passed element to the header. If no header is present, one will
  1256. * be automatically created. An empty string can be passed to the method
  1257. * to clear the contents of the header.
  1258. *
  1259. * @method setHeader
  1260. * @param {String} headerContent The string used to set the header.
  1261. * As a convenience, non HTMLElement objects can also be passed into
  1262. * the method, and will be treated as strings, with the header innerHTML
  1263. * set to their default toString implementations.
  1264. * <em>OR</em>
  1265. * @param {HTMLElement} headerContent The HTMLElement to append to
  1266. * <em>OR</em>
  1267. * @param {DocumentFragment} headerContent The document fragment
  1268. * containing elements which are to be added to the header
  1269. */
  1270. setHeader: function (headerContent) {
  1271. var oHeader = this.header || (this.header = createHeader());
  1272. if (headerContent.nodeName) {
  1273. oHeader.innerHTML = "";
  1274. oHeader.appendChild(headerContent);
  1275. } else {
  1276. oHeader.innerHTML = headerContent;
  1277. }
  1278. this.changeHeaderEvent.fire(headerContent);
  1279. this.changeContentEvent.fire();
  1280. },
  1281. /**
  1282. * Appends the passed element to the header. If no header is present,
  1283. * one will be automatically created.
  1284. * @method appendToHeader
  1285. * @param {HTMLElement | DocumentFragment} element The element to
  1286. * append to the header. In the case of a document fragment, the
  1287. * children of the fragment will be appended to the header.
  1288. */
  1289. appendToHeader: function (element) {
  1290. var oHeader = this.header || (this.header = createHeader());
  1291. oHeader.appendChild(element);
  1292. this.changeHeaderEvent.fire(element);
  1293. this.changeContentEvent.fire();
  1294. },
  1295. /**
  1296. * Sets the Module's body content to the HTML specified.
  1297. *
  1298. * If no body is present, one will be automatically created.
  1299. *
  1300. * An empty string can be passed to the method to clear the contents of the body.
  1301. * @method setBody
  1302. * @param {String} bodyContent The HTML used to set the body.
  1303. * As a convenience, non HTMLElement objects can also be passed into
  1304. * the method, and will be treated as strings, with the body innerHTML
  1305. * set to their default toString implementations.
  1306. * <em>OR</em>
  1307. * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
  1308. * child of the body element.
  1309. * <em>OR</em>
  1310. * @param {DocumentFragment} bodyContent The document fragment
  1311. * containing elements which are to be added to the body
  1312. */
  1313. setBody: function (bodyContent) {
  1314. var oBody = this.body || (this.body = createBody());
  1315. if (bodyContent.nodeName) {
  1316. oBody.innerHTML = "";
  1317. oBody.appendChild(bodyContent);
  1318. } else {
  1319. oBody.innerHTML = bodyContent;
  1320. }
  1321. this.changeBodyEvent.fire(bodyContent);
  1322. this.changeContentEvent.fire();
  1323. },
  1324. /**
  1325. * Appends the passed element to the body. If no body is present, one
  1326. * will be automatically created.
  1327. * @method appendToBody
  1328. * @param {HTMLElement | DocumentFragment} element The element to
  1329. * append to the body. In the case of a document fragment, the
  1330. * children of the fragment will be appended to the body.
  1331. *
  1332. */
  1333. appendToBody: function (element) {
  1334. var oBody = this.body || (this.body = createBody());
  1335. oBody.appendChild(element);
  1336. this.changeBodyEvent.fire(element);
  1337. this.changeContentEvent.fire();
  1338. },
  1339. /**
  1340. * Sets the Module's footer content to the HTML specified, or appends
  1341. * the passed element to the footer. If no footer is present, one will
  1342. * be automatically created. An empty string can be passed to the method
  1343. * to clear the contents of the footer.
  1344. * @method setFooter
  1345. * @param {String} footerContent The HTML used to set the footer
  1346. * As a convenience, non HTMLElement objects can also be passed into
  1347. * the method, and will be treated as strings, with the footer innerHTML
  1348. * set to their default toString implementations.
  1349. * <em>OR</em>
  1350. * @param {HTMLElement} footerContent The HTMLElement to append to
  1351. * the footer
  1352. * <em>OR</em>
  1353. * @param {DocumentFragment} footerContent The document fragment containing
  1354. * elements which are to be added to the footer
  1355. */
  1356. setFooter: function (footerContent) {
  1357. var oFooter = this.footer || (this.footer = createFooter());
  1358. if (footerContent.nodeName) {
  1359. oFooter.innerHTML = "";
  1360. oFooter.appendChild(footerContent);
  1361. } else {
  1362. oFooter.innerHTML = footerContent;
  1363. }
  1364. this.changeFooterEvent.fire(footerContent);
  1365. this.changeContentEvent.fire();
  1366. },
  1367. /**
  1368. * Appends the passed element to the footer. If no footer is present,
  1369. * one will be automatically created.
  1370. * @method appendToFooter
  1371. * @param {HTMLElement | DocumentFragment} element The element to
  1372. * append to the footer. In the case of a document fragment, the
  1373. * children of the fragment will be appended to the footer
  1374. */
  1375. appendToFooter: function (element) {
  1376. var oFooter = this.footer || (this.footer = createFooter());
  1377. oFooter.appendChild(element);
  1378. this.changeFooterEvent.fire(element);
  1379. this.changeContentEvent.fire();
  1380. },
  1381. /**
  1382. * Renders the Module by inserting the elements that are not already
  1383. * in the main Module into their correct places. Optionally appends
  1384. * the Module to the specified node prior to the render's execution.
  1385. * <p>
  1386. * For Modules without existing markup, the appendToNode argument
  1387. * is REQUIRED. If this argument is ommitted and the current element is
  1388. * not present in the document, the function will return false,
  1389. * indicating that the render was a failure.
  1390. * </p>
  1391. * <p>
  1392. * NOTE: As of 2.3.1, if the appendToNode is the document's body element
  1393. * then the module is rendered as the first child of the body element,
  1394. * and not appended to it, to avoid Operation Aborted errors in IE when
  1395. * rendering the module before window's load event is fired. You can
  1396. * use the appendtodocumentbody configuration property to change this
  1397. * to append to document.body if required.
  1398. * </p>
  1399. * @method render
  1400. * @param {String} appendToNode The element id to which the Module
  1401. * should be appended to prior to rendering <em>OR</em>
  1402. * @param {HTMLElement} appendToNode The element to which the Module
  1403. * should be appended to prior to rendering
  1404. * @param {HTMLElement} moduleElement OPTIONAL. The element that
  1405. * represents the actual Standard Module container.
  1406. * @return {Boolean} Success or failure of the render
  1407. */
  1408. render: function (appendToNode, moduleElement) {
  1409. var me = this,
  1410. firstChild;
  1411. function appendTo(parentNode) {
  1412. if (typeof parentNode == "string") {
  1413. parentNode = document.getElementById(parentNode);
  1414. }
  1415. if (parentNode) {
  1416. me._addToParent(parentNode, me.element);
  1417. me.appendEvent.fire();
  1418. }
  1419. }
  1420. this.beforeRenderEvent.fire();
  1421. if (! moduleElement) {
  1422. moduleElement = this.element;
  1423. }
  1424. if (appendToNode) {
  1425. appendTo(appendToNode);
  1426. } else {
  1427. // No node was passed in. If the element is not already in the Dom, this fails
  1428. if (! Dom.inDocument(this.element)) {
  1429. YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
  1430. return false;
  1431. }
  1432. }
  1433. // Need to get everything into the DOM if it isn't already
  1434. if (this.header && ! Dom.inDocument(this.header)) {
  1435. // There is a header, but it's not in the DOM yet. Need to add it.
  1436. firstChild = moduleElement.firstChild;
  1437. if (firstChild) {
  1438. moduleElement.insertBefore(this.header, firstChild);
  1439. } else {
  1440. moduleElement.appendChild(this.header);
  1441. }
  1442. }
  1443. if (this.body && ! Dom.inDocument(this.body)) {
  1444. // There is a body, but it's not in the DOM yet. Need to add it.
  1445. if (this.footer && Dom.isAncestor(this.moduleElement, this.footer)) {
  1446. moduleElement.insertBefore(this.body, this.footer);
  1447. } else {
  1448. moduleElement.appendChild(this.body);
  1449. }
  1450. }
  1451. if (this.footer && ! Dom.inDocument(this.footer)) {
  1452. // There is a footer, but it's not in the DOM yet. Need to add it.
  1453. moduleElement.appendChild(this.footer);
  1454. }
  1455. this.renderEvent.fire();
  1456. return true;
  1457. },
  1458. /**
  1459. * Removes the Module element from the DOM and sets all child elements
  1460. * to null.
  1461. * @method destroy
  1462. */
  1463. destroy: function () {
  1464. var parent;
  1465. if (this.element) {
  1466. Event.purgeElement(this.element, true);
  1467. parent = this.element.parentNode;
  1468. }
  1469. if (parent) {
  1470. parent.removeChild(this.element);
  1471. }
  1472. this.element = null;
  1473. this.header = null;
  1474. this.body = null;
  1475. this.footer = null;
  1476. Module.textResizeEvent.unsubscribe(this.onDomResize, this);
  1477. this.cfg.destroy();
  1478. this.cfg = null;
  1479. this.destroyEvent.fire();
  1480. },
  1481. /**
  1482. * Shows the Module element by setting the visible configuration
  1483. * property to true. Also fires two events: beforeShowEvent prior to
  1484. * the visibility change, and showEvent after.
  1485. * @method show
  1486. */
  1487. show: function () {
  1488. this.cfg.setProperty("visible", true);
  1489. },
  1490. /**
  1491. * Hides the Module element by setting the visible configuration
  1492. * property to false. Also fires two events: beforeHideEvent prior to
  1493. * the visibility change, and hideEvent after.
  1494. * @method hide
  1495. */
  1496. hide: function () {
  1497. this.cfg.setProperty("visible", false);
  1498. },
  1499. // BUILT-IN EVENT HANDLERS FOR MODULE //
  1500. /**
  1501. * Default event handler for changing the visibility property of a
  1502. * Module. By default, this is achieved by switching the "display" style
  1503. * between "block" and "none".
  1504. * This method is responsible for firing showEvent and hideEvent.
  1505. * @param {String} type The CustomEvent type (usually the property name)
  1506. * @param {Object[]} args The CustomEvent arguments. For configuration
  1507. * handlers, args[0] will equal the newly applied value for the property.
  1508. * @param {Object} obj The scope object. For configuration handlers,
  1509. * this will usually equal the owner.
  1510. * @method configVisible
  1511. */
  1512. configVisible: function (type, args, obj) {
  1513. var visible = args[0];
  1514. if (visible) {
  1515. this.beforeShowEvent.fire();
  1516. Dom.setStyle(this.element, "display", "block");
  1517. this.showEvent.fire();
  1518. } else {
  1519. this.beforeHideEvent.fire();
  1520. Dom.setStyle(this.element, "display", "none");
  1521. this.hideEvent.fire();
  1522. }
  1523. },
  1524. /**
  1525. * Default event handler for the "monitorresize" configuration property
  1526. * @param {String} type The CustomEvent type (usually the property name)
  1527. * @param {Object[]} args The CustomEvent arguments. For configuration
  1528. * handlers, args[0] will equal the newly applied value for the property.
  1529. * @param {Object} obj The scope object. For configuration handlers,
  1530. * this will usually equal the owner.
  1531. * @method configMonitorResize
  1532. */
  1533. configMonitorResize: function (type, args, obj) {
  1534. var monitor = args[0];
  1535. if (monitor) {
  1536. this.initResizeMonitor();
  1537. } else {
  1538. Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
  1539. this.resizeMonitor = null;
  1540. }
  1541. },
  1542. /**
  1543. * This method is a protected helper, used when constructing the DOM structure for the module
  1544. * to account for situations which may cause Operation Aborted errors in IE. It should not
  1545. * be used for general DOM construction.
  1546. * <p>
  1547. * If the parentNode is not document.body, the element is appended as the last element.
  1548. * </p>
  1549. * <p>
  1550. * If the parentNode is document.body the element is added as the first child to help
  1551. * prevent Operation Aborted errors in IE.
  1552. * </p>
  1553. *
  1554. * @param {parentNode} The HTML element to which the element will be added
  1555. * @param {element} The HTML element to be added to parentNode's children
  1556. * @method _addToParent
  1557. * @protected
  1558. */
  1559. _addToParent: function(parentNode, element) {
  1560. if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
  1561. parentNode.insertBefore(element, parentNode.firstChild);
  1562. } else {
  1563. parentNode.appendChild(element);
  1564. }
  1565. },
  1566. /**
  1567. * Returns a String representation of the Object.
  1568. * @method toString
  1569. * @return {String} The string representation of the Module
  1570. */
  1571. toString: function () {
  1572. return "Module " + this.id;
  1573. }
  1574. };
  1575. YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
  1576. }());
  1577. (function () {
  1578. /**
  1579. * Overlay is a Module that is absolutely positioned above the page flow. It
  1580. * has convenience methods for positioning and sizing, as well as options for
  1581. * controlling zIndex and constraining the Overlay's position to the current
  1582. * visible viewport. Overlay also contains a dynamicly generated IFRAME which
  1583. * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
  1584. * properly rendered above SELECT elements.
  1585. * @namespace YAHOO.widget
  1586. * @class Overlay
  1587. * @extends YAHOO.widget.Module
  1588. * @param {String} el The element ID representing the Overlay <em>OR</em>
  1589. * @param {HTMLElement} el The element representing the Overlay
  1590. * @param {Object} userConfig The configuration object literal containing
  1591. * the configuration that should be set for this Overlay. See configuration
  1592. * documentation for more details.
  1593. * @constructor
  1594. */
  1595. YAHOO.widget.Overlay = function (el, userConfig) {
  1596. YAHOO.widget.Overlay.superclass.constructor.call(this, el, us