/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

Large files are truncated click here to view the full 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…