/public/lib/2.9.0/build/container/container.js

https://bitbucket.org/khuongduybui/openfisma · JavaScript · 1480 lines · 642 code · 228 blank · 610 comment · 151 complexity · 329836393952d1a856327f86ce16ea37 MD5 · raw file

  1. /*
  2. Copyright (c) 2011, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 2.9.0
  6. */
  7. (function () {
  8. /**
  9. * Config is a utility used within an Object to allow the implementer to
  10. * maintain a list of local configuration properties and listen for changes
  11. * to those properties dynamically using CustomEvent. The initial values are
  12. * also maintained so that the configuration can be reset at any given point
  13. * to its initial state.
  14. * @namespace YAHOO.util
  15. * @class Config
  16. * @constructor
  17. * @param {Object} owner The owner Object to which this Config Object belongs
  18. */
  19. YAHOO.util.Config = function (owner) {
  20. if (owner) {
  21. this.init(owner);
  22. }
  23. };
  24. var Lang = YAHOO.lang,
  25. CustomEvent = YAHOO.util.CustomEvent,
  26. Config = YAHOO.util.Config;
  27. /**
  28. * Constant representing the CustomEvent type for the config changed event.
  29. * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
  30. * @private
  31. * @static
  32. * @final
  33. */
  34. Config.CONFIG_CHANGED_EVENT = "configChanged";
  35. /**
  36. * Constant representing the boolean type string
  37. * @property YAHOO.util.Config.BOOLEAN_TYPE
  38. * @private
  39. * @static
  40. * @final
  41. */
  42. Config.BOOLEAN_TYPE = "boolean";
  43. Config.prototype = {
  44. /**
  45. * Object reference to the owner of this Config Object
  46. * @property owner
  47. * @type Object
  48. */
  49. owner: null,
  50. /**
  51. * Boolean flag that specifies whether a queue is currently
  52. * being executed
  53. * @property queueInProgress
  54. * @type Boolean
  55. */
  56. queueInProgress: false,
  57. /**
  58. * Maintains the local collection of configuration property objects and
  59. * their specified values
  60. * @property config
  61. * @private
  62. * @type Object
  63. */
  64. config: null,
  65. /**
  66. * Maintains the local collection of configuration property objects as
  67. * they were initially applied.
  68. * This object is used when resetting a property.
  69. * @property initialConfig
  70. * @private
  71. * @type Object
  72. */
  73. initialConfig: null,
  74. /**
  75. * Maintains the local, normalized CustomEvent queue
  76. * @property eventQueue
  77. * @private
  78. * @type Object
  79. */
  80. eventQueue: null,
  81. /**
  82. * Custom Event, notifying subscribers when Config properties are set
  83. * (setProperty is called without the silent flag
  84. * @event configChangedEvent
  85. */
  86. configChangedEvent: null,
  87. /**
  88. * Initializes the configuration Object and all of its local members.
  89. * @method init
  90. * @param {Object} owner The owner Object to which this Config
  91. * Object belongs
  92. */
  93. init: function (owner) {
  94. this.owner = owner;
  95. this.configChangedEvent =
  96. this.createEvent(Config.CONFIG_CHANGED_EVENT);
  97. this.configChangedEvent.signature = CustomEvent.LIST;
  98. this.queueInProgress = false;
  99. this.config = {};
  100. this.initialConfig = {};
  101. this.eventQueue = [];
  102. },
  103. /**
  104. * Validates that the value passed in is a Boolean.
  105. * @method checkBoolean
  106. * @param {Object} val The value to validate
  107. * @return {Boolean} true, if the value is valid
  108. */
  109. checkBoolean: function (val) {
  110. return (typeof val == Config.BOOLEAN_TYPE);
  111. },
  112. /**
  113. * Validates that the value passed in is a number.
  114. * @method checkNumber
  115. * @param {Object} val The value to validate
  116. * @return {Boolean} true, if the value is valid
  117. */
  118. checkNumber: function (val) {
  119. return (!isNaN(val));
  120. },
  121. /**
  122. * Fires a configuration property event using the specified value.
  123. * @method fireEvent
  124. * @private
  125. * @param {String} key The configuration property's name
  126. * @param {value} Object The value of the correct type for the property
  127. */
  128. fireEvent: function ( key, value ) {
  129. var property = this.config[key];
  130. if (property && property.event) {
  131. property.event.fire(value);
  132. }
  133. },
  134. /**
  135. * Adds a property to the Config Object's private config hash.
  136. * @method addProperty
  137. * @param {String} key The configuration property's name
  138. * @param {Object} propertyObject The Object containing all of this
  139. * property's arguments
  140. */
  141. addProperty: function ( key, propertyObject ) {
  142. key = key.toLowerCase();
  143. this.config[key] = propertyObject;
  144. propertyObject.event = this.createEvent(key, { scope: this.owner });
  145. propertyObject.event.signature = CustomEvent.LIST;
  146. propertyObject.key = key;
  147. if (propertyObject.handler) {
  148. propertyObject.event.subscribe(propertyObject.handler,
  149. this.owner);
  150. }
  151. this.setProperty(key, propertyObject.value, true);
  152. if (! propertyObject.suppressEvent) {
  153. this.queueProperty(key, propertyObject.value);
  154. }
  155. },
  156. /**
  157. * Returns a key-value configuration map of the values currently set in
  158. * the Config Object.
  159. * @method getConfig
  160. * @return {Object} The current config, represented in a key-value map
  161. */
  162. getConfig: function () {
  163. var cfg = {},
  164. currCfg = this.config,
  165. prop,
  166. property;
  167. for (prop in currCfg) {
  168. if (Lang.hasOwnProperty(currCfg, prop)) {
  169. property = currCfg[prop];
  170. if (property && property.event) {
  171. cfg[prop] = property.value;
  172. }
  173. }
  174. }
  175. return cfg;
  176. },
  177. /**
  178. * Returns the value of specified property.
  179. * @method getProperty
  180. * @param {String} key The name of the property
  181. * @return {Object} The value of the specified property
  182. */
  183. getProperty: function (key) {
  184. var property = this.config[key.toLowerCase()];
  185. if (property && property.event) {
  186. return property.value;
  187. } else {
  188. return undefined;
  189. }
  190. },
  191. /**
  192. * Resets the specified property's value to its initial value.
  193. * @method resetProperty
  194. * @param {String} key The name of the property
  195. * @return {Boolean} True is the property was reset, false if not
  196. */
  197. resetProperty: function (key) {
  198. key = key.toLowerCase();
  199. var property = this.config[key];
  200. if (property && property.event) {
  201. if (key in this.initialConfig) {
  202. this.setProperty(key, this.initialConfig[key]);
  203. return true;
  204. }
  205. } else {
  206. return false;
  207. }
  208. },
  209. /**
  210. * Sets the value of a property. If the silent property is passed as
  211. * true, the property's event will not be fired.
  212. * @method setProperty
  213. * @param {String} key The name of the property
  214. * @param {String} value The value to set the property to
  215. * @param {Boolean} silent Whether the value should be set silently,
  216. * without firing the property event.
  217. * @return {Boolean} True, if the set was successful, false if it failed.
  218. */
  219. setProperty: function (key, value, silent) {
  220. var property;
  221. key = key.toLowerCase();
  222. if (this.queueInProgress && ! silent) {
  223. // Currently running through a queue...
  224. this.queueProperty(key,value);
  225. return true;
  226. } else {
  227. property = this.config[key];
  228. if (property && property.event) {
  229. if (property.validator && !property.validator(value)) {
  230. return false;
  231. } else {
  232. property.value = value;
  233. if (! silent) {
  234. this.fireEvent(key, value);
  235. this.configChangedEvent.fire([key, value]);
  236. }
  237. return true;
  238. }
  239. } else {
  240. return false;
  241. }
  242. }
  243. },
  244. /**
  245. * Sets the value of a property and queues its event to execute. If the
  246. * event is already scheduled to execute, it is
  247. * moved from its current position to the end of the queue.
  248. * @method queueProperty
  249. * @param {String} key The name of the property
  250. * @param {String} value The value to set the property to
  251. * @return {Boolean} true, if the set was successful, false if
  252. * it failed.
  253. */
  254. queueProperty: function (key, value) {
  255. key = key.toLowerCase();
  256. var property = this.config[key],
  257. foundDuplicate = false,
  258. iLen,
  259. queueItem,
  260. queueItemKey,
  261. queueItemValue,
  262. sLen,
  263. supercedesCheck,
  264. qLen,
  265. queueItemCheck,
  266. queueItemCheckKey,
  267. queueItemCheckValue,
  268. i,
  269. s,
  270. q;
  271. if (property && property.event) {
  272. if (!Lang.isUndefined(value) && property.validator &&
  273. !property.validator(value)) { // validator
  274. return false;
  275. } else {
  276. if (!Lang.isUndefined(value)) {
  277. property.value = value;
  278. } else {
  279. value = property.value;
  280. }
  281. foundDuplicate = false;
  282. iLen = this.eventQueue.length;
  283. for (i = 0; i < iLen; i++) {
  284. queueItem = this.eventQueue[i];
  285. if (queueItem) {
  286. queueItemKey = queueItem[0];
  287. queueItemValue = queueItem[1];
  288. if (queueItemKey == key) {
  289. /*
  290. found a dupe... push to end of queue, null
  291. current item, and break
  292. */
  293. this.eventQueue[i] = null;
  294. this.eventQueue.push(
  295. [key, (!Lang.isUndefined(value) ?
  296. value : queueItemValue)]);
  297. foundDuplicate = true;
  298. break;
  299. }
  300. }
  301. }
  302. // this is a refire, or a new property in the queue
  303. if (! foundDuplicate && !Lang.isUndefined(value)) {
  304. this.eventQueue.push([key, value]);
  305. }
  306. }
  307. if (property.supercedes) {
  308. sLen = property.supercedes.length;
  309. for (s = 0; s < sLen; s++) {
  310. supercedesCheck = property.supercedes[s];
  311. qLen = this.eventQueue.length;
  312. for (q = 0; q < qLen; q++) {
  313. queueItemCheck = this.eventQueue[q];
  314. if (queueItemCheck) {
  315. queueItemCheckKey = queueItemCheck[0];
  316. queueItemCheckValue = queueItemCheck[1];
  317. if (queueItemCheckKey ==
  318. supercedesCheck.toLowerCase() ) {
  319. this.eventQueue.push([queueItemCheckKey,
  320. queueItemCheckValue]);
  321. this.eventQueue[q] = null;
  322. break;
  323. }
  324. }
  325. }
  326. }
  327. }
  328. return true;
  329. } else {
  330. return false;
  331. }
  332. },
  333. /**
  334. * Fires the event for a property using the property's current value.
  335. * @method refireEvent
  336. * @param {String} key The name of the property
  337. */
  338. refireEvent: function (key) {
  339. key = key.toLowerCase();
  340. var property = this.config[key];
  341. if (property && property.event &&
  342. !Lang.isUndefined(property.value)) {
  343. if (this.queueInProgress) {
  344. this.queueProperty(key);
  345. } else {
  346. this.fireEvent(key, property.value);
  347. }
  348. }
  349. },
  350. /**
  351. * Applies a key-value Object literal to the configuration, replacing
  352. * any existing values, and queueing the property events.
  353. * Although the values will be set, fireQueue() must be called for their
  354. * associated events to execute.
  355. * @method applyConfig
  356. * @param {Object} userConfig The configuration Object literal
  357. * @param {Boolean} init When set to true, the initialConfig will
  358. * be set to the userConfig passed in, so that calling a reset will
  359. * reset the properties to the passed values.
  360. */
  361. applyConfig: function (userConfig, init) {
  362. var sKey,
  363. oConfig;
  364. if (init) {
  365. oConfig = {};
  366. for (sKey in userConfig) {
  367. if (Lang.hasOwnProperty(userConfig, sKey)) {
  368. oConfig[sKey.toLowerCase()] = userConfig[sKey];
  369. }
  370. }
  371. this.initialConfig = oConfig;
  372. }
  373. for (sKey in userConfig) {
  374. if (Lang.hasOwnProperty(userConfig, sKey)) {
  375. this.queueProperty(sKey, userConfig[sKey]);
  376. }
  377. }
  378. },
  379. /**
  380. * Refires the events for all configuration properties using their
  381. * current values.
  382. * @method refresh
  383. */
  384. refresh: function () {
  385. var prop;
  386. for (prop in this.config) {
  387. if (Lang.hasOwnProperty(this.config, prop)) {
  388. this.refireEvent(prop);
  389. }
  390. }
  391. },
  392. /**
  393. * Fires the normalized list of queued property change events
  394. * @method fireQueue
  395. */
  396. fireQueue: function () {
  397. var i,
  398. queueItem,
  399. key,
  400. value,
  401. property;
  402. this.queueInProgress = true;
  403. for (i = 0;i < this.eventQueue.length; i++) {
  404. queueItem = this.eventQueue[i];
  405. if (queueItem) {
  406. key = queueItem[0];
  407. value = queueItem[1];
  408. property = this.config[key];
  409. property.value = value;
  410. // Clear out queue entry, to avoid it being
  411. // re-added to the queue by any queueProperty/supercedes
  412. // calls which are invoked during fireEvent
  413. this.eventQueue[i] = null;
  414. this.fireEvent(key,value);
  415. }
  416. }
  417. this.queueInProgress = false;
  418. this.eventQueue = [];
  419. },
  420. /**
  421. * Subscribes an external handler to the change event for any
  422. * given property.
  423. * @method subscribeToConfigEvent
  424. * @param {String} key The property name
  425. * @param {Function} handler The handler function to use subscribe to
  426. * the property's event
  427. * @param {Object} obj The Object to use for scoping the event handler
  428. * (see CustomEvent documentation)
  429. * @param {Boolean} overrideContext Optional. If true, will override
  430. * "this" within the handler to map to the scope Object passed into the
  431. * method.
  432. * @return {Boolean} True, if the subscription was successful,
  433. * otherwise false.
  434. */
  435. subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
  436. var property = this.config[key.toLowerCase()];
  437. if (property && property.event) {
  438. if (!Config.alreadySubscribed(property.event, handler, obj)) {
  439. property.event.subscribe(handler, obj, overrideContext);
  440. }
  441. return true;
  442. } else {
  443. return false;
  444. }
  445. },
  446. /**
  447. * Unsubscribes an external handler from the change event for any
  448. * given property.
  449. * @method unsubscribeFromConfigEvent
  450. * @param {String} key The property name
  451. * @param {Function} handler The handler function to use subscribe to
  452. * the property's event
  453. * @param {Object} obj The Object to use for scoping the event
  454. * handler (see CustomEvent documentation)
  455. * @return {Boolean} True, if the unsubscription was successful,
  456. * otherwise false.
  457. */
  458. unsubscribeFromConfigEvent: function (key, handler, obj) {
  459. var property = this.config[key.toLowerCase()];
  460. if (property && property.event) {
  461. return property.event.unsubscribe(handler, obj);
  462. } else {
  463. return false;
  464. }
  465. },
  466. /**
  467. * Returns a string representation of the Config object
  468. * @method toString
  469. * @return {String} The Config object in string format.
  470. */
  471. toString: function () {
  472. var output = "Config";
  473. if (this.owner) {
  474. output += " [" + this.owner.toString() + "]";
  475. }
  476. return output;
  477. },
  478. /**
  479. * Returns a string representation of the Config object's current
  480. * CustomEvent queue
  481. * @method outputEventQueue
  482. * @return {String} The string list of CustomEvents currently queued
  483. * for execution
  484. */
  485. outputEventQueue: function () {
  486. var output = "",
  487. queueItem,
  488. q,
  489. nQueue = this.eventQueue.length;
  490. for (q = 0; q < nQueue; q++) {
  491. queueItem = this.eventQueue[q];
  492. if (queueItem) {
  493. output += queueItem[0] + "=" + queueItem[1] + ", ";
  494. }
  495. }
  496. return output;
  497. },
  498. /**
  499. * Sets all properties to null, unsubscribes all listeners from each
  500. * property's change event and all listeners from the configChangedEvent.
  501. * @method destroy
  502. */
  503. destroy: function () {
  504. var oConfig = this.config,
  505. sProperty,
  506. oProperty;
  507. for (sProperty in oConfig) {
  508. if (Lang.hasOwnProperty(oConfig, sProperty)) {
  509. oProperty = oConfig[sProperty];
  510. oProperty.event.unsubscribeAll();
  511. oProperty.event = null;
  512. }
  513. }
  514. this.configChangedEvent.unsubscribeAll();
  515. this.configChangedEvent = null;
  516. this.owner = null;
  517. this.config = null;
  518. this.initialConfig = null;
  519. this.eventQueue = null;
  520. }
  521. };
  522. /**
  523. * Checks to determine if a particular function/Object pair are already
  524. * subscribed to the specified CustomEvent
  525. * @method YAHOO.util.Config.alreadySubscribed
  526. * @static
  527. * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
  528. * the subscriptions
  529. * @param {Function} fn The function to look for in the subscribers list
  530. * @param {Object} obj The execution scope Object for the subscription
  531. * @return {Boolean} true, if the function/Object pair is already subscribed
  532. * to the CustomEvent passed in
  533. */
  534. Config.alreadySubscribed = function (evt, fn, obj) {
  535. var nSubscribers = evt.subscribers.length,
  536. subsc,
  537. i;
  538. if (nSubscribers > 0) {
  539. i = nSubscribers - 1;
  540. do {
  541. subsc = evt.subscribers[i];
  542. if (subsc && subsc.obj == obj && subsc.fn == fn) {
  543. return true;
  544. }
  545. }
  546. while (i--);
  547. }
  548. return false;
  549. };
  550. YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
  551. }());
  552. (function () {
  553. /**
  554. * The Container family of components is designed to enable developers to
  555. * create different kinds of content-containing modules on the web. Module
  556. * and Overlay are the most basic containers, and they can be used directly
  557. * or extended to build custom containers. Also part of the Container family
  558. * are four UI controls that extend Module and Overlay: Tooltip, Panel,
  559. * Dialog, and SimpleDialog.
  560. * @module container
  561. * @title Container
  562. * @requires yahoo, dom, event
  563. * @optional dragdrop, animation, button
  564. */
  565. /**
  566. * Module is a JavaScript representation of the Standard Module Format.
  567. * Standard Module Format is a simple standard for markup containers where
  568. * child nodes representing the header, body, and footer of the content are
  569. * denoted using the CSS classes "hd", "bd", and "ft" respectively.
  570. * Module is the base class for all other classes in the YUI
  571. * Container package.
  572. * @namespace YAHOO.widget
  573. * @class Module
  574. * @constructor
  575. * @param {String} el The element ID representing the Module <em>OR</em>
  576. * @param {HTMLElement} el The element representing the Module
  577. * @param {Object} userConfig The configuration Object literal containing
  578. * the configuration that should be set for this module. See configuration
  579. * documentation for more details.
  580. */
  581. YAHOO.widget.Module = function (el, userConfig) {
  582. if (el) {
  583. this.init(el, userConfig);
  584. } else {
  585. }
  586. };
  587. var Dom = YAHOO.util.Dom,
  588. Config = YAHOO.util.Config,
  589. Event = YAHOO.util.Event,
  590. CustomEvent = YAHOO.util.CustomEvent,
  591. Module = YAHOO.widget.Module,
  592. UA = YAHOO.env.ua,
  593. m_oModuleTemplate,
  594. m_oHeaderTemplate,
  595. m_oBodyTemplate,
  596. m_oFooterTemplate,
  597. /**
  598. * Constant representing the name of the Module's events
  599. * @property EVENT_TYPES
  600. * @private
  601. * @final
  602. * @type Object
  603. */
  604. EVENT_TYPES = {
  605. "BEFORE_INIT": "beforeInit",
  606. "INIT": "init",
  607. "APPEND": "append",
  608. "BEFORE_RENDER": "beforeRender",
  609. "RENDER": "render",
  610. "CHANGE_HEADER": "changeHeader",
  611. "CHANGE_BODY": "changeBody",
  612. "CHANGE_FOOTER": "changeFooter",
  613. "CHANGE_CONTENT": "changeContent",
  614. "DESTROY": "destroy",
  615. "BEFORE_SHOW": "beforeShow",
  616. "SHOW": "show",
  617. "BEFORE_HIDE": "beforeHide",
  618. "HIDE": "hide"
  619. },
  620. /**
  621. * Constant representing the Module's configuration properties
  622. * @property DEFAULT_CONFIG
  623. * @private
  624. * @final
  625. * @type Object
  626. */
  627. DEFAULT_CONFIG = {
  628. "VISIBLE": {
  629. key: "visible",
  630. value: true,
  631. validator: YAHOO.lang.isBoolean
  632. },
  633. "EFFECT": {
  634. key: "effect",
  635. suppressEvent: true,
  636. supercedes: ["visible"]
  637. },
  638. "MONITOR_RESIZE": {
  639. key: "monitorresize",
  640. value: true
  641. },
  642. "APPEND_TO_DOCUMENT_BODY": {
  643. key: "appendtodocumentbody",
  644. value: false
  645. }
  646. };
  647. /**
  648. * Constant representing the prefix path to use for non-secure images
  649. * @property YAHOO.widget.Module.IMG_ROOT
  650. * @static
  651. * @final
  652. * @type String
  653. */
  654. Module.IMG_ROOT = null;
  655. /**
  656. * Constant representing the prefix path to use for securely served images
  657. * @property YAHOO.widget.Module.IMG_ROOT_SSL
  658. * @static
  659. * @final
  660. * @type String
  661. */
  662. Module.IMG_ROOT_SSL = null;
  663. /**
  664. * Constant for the default CSS class name that represents a Module
  665. * @property YAHOO.widget.Module.CSS_MODULE
  666. * @static
  667. * @final
  668. * @type String
  669. */
  670. Module.CSS_MODULE = "yui-module";
  671. /**
  672. * CSS classname representing the module header. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
  673. * @property YAHOO.widget.Module.CSS_HEADER
  674. * @static
  675. * @final
  676. * @type String
  677. */
  678. Module.CSS_HEADER = "hd";
  679. /**
  680. * CSS classname representing the module body. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
  681. * @property YAHOO.widget.Module.CSS_BODY
  682. * @static
  683. * @final
  684. * @type String
  685. */
  686. Module.CSS_BODY = "bd";
  687. /**
  688. * CSS classname representing the module footer. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
  689. * @property YAHOO.widget.Module.CSS_FOOTER
  690. * @static
  691. * @final
  692. * @type String
  693. */
  694. Module.CSS_FOOTER = "ft";
  695. /**
  696. * Constant representing the url for the "src" attribute of the iframe
  697. * used to monitor changes to the browser's base font size
  698. * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
  699. * @static
  700. * @final
  701. * @type String
  702. */
  703. Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
  704. /**
  705. * Constant representing the buffer amount (in pixels) to use when positioning
  706. * the text resize monitor offscreen. The resize monitor is positioned
  707. * offscreen by an amount eqaul to its offsetHeight + the buffer value.
  708. *
  709. * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
  710. * @static
  711. * @type Number
  712. */
  713. // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
  714. Module.RESIZE_MONITOR_BUFFER = 1;
  715. /**
  716. * Singleton CustomEvent fired when the font size is changed in the browser.
  717. * Opera's "zoom" functionality currently does not support text
  718. * size detection.
  719. * @event YAHOO.widget.Module.textResizeEvent
  720. */
  721. Module.textResizeEvent = new CustomEvent("textResize");
  722. /**
  723. * Helper utility method, which forces a document level
  724. * redraw for Opera, which can help remove repaint
  725. * irregularities after applying DOM changes.
  726. *
  727. * @method YAHOO.widget.Module.forceDocumentRedraw
  728. * @static
  729. */
  730. Module.forceDocumentRedraw = function() {
  731. var docEl = document.documentElement;
  732. if (docEl) {
  733. docEl.className += " ";
  734. docEl.className = YAHOO.lang.trim(docEl.className);
  735. }
  736. };
  737. function createModuleTemplate() {
  738. if (!m_oModuleTemplate) {
  739. m_oModuleTemplate = document.createElement("div");
  740. m_oModuleTemplate.innerHTML = ("<div class=\"" +
  741. Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
  742. Module.CSS_BODY + "\"></div><div class=\"" +
  743. Module.CSS_FOOTER + "\"></div>");
  744. m_oHeaderTemplate = m_oModuleTemplate.firstChild;
  745. m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
  746. m_oFooterTemplate = m_oBodyTemplate.nextSibling;
  747. }
  748. return m_oModuleTemplate;
  749. }
  750. function createHeader() {
  751. if (!m_oHeaderTemplate) {
  752. createModuleTemplate();
  753. }
  754. return (m_oHeaderTemplate.cloneNode(false));
  755. }
  756. function createBody() {
  757. if (!m_oBodyTemplate) {
  758. createModuleTemplate();
  759. }
  760. return (m_oBodyTemplate.cloneNode(false));
  761. }
  762. function createFooter() {
  763. if (!m_oFooterTemplate) {
  764. createModuleTemplate();
  765. }
  766. return (m_oFooterTemplate.cloneNode(false));
  767. }
  768. Module.prototype = {
  769. /**
  770. * The class's constructor function
  771. * @property contructor
  772. * @type Function
  773. */
  774. constructor: Module,
  775. /**
  776. * The main module element that contains the header, body, and footer
  777. * @property element
  778. * @type HTMLElement
  779. */
  780. element: null,
  781. /**
  782. * The header element, denoted with CSS class "hd"
  783. * @property header
  784. * @type HTMLElement
  785. */
  786. header: null,
  787. /**
  788. * The body element, denoted with CSS class "bd"
  789. * @property body
  790. * @type HTMLElement
  791. */
  792. body: null,
  793. /**
  794. * The footer element, denoted with CSS class "ft"
  795. * @property footer
  796. * @type HTMLElement
  797. */
  798. footer: null,
  799. /**
  800. * The id of the element
  801. * @property id
  802. * @type String
  803. */
  804. id: null,
  805. /**
  806. * A string representing the root path for all images created by
  807. * a Module instance.
  808. * @deprecated It is recommend that any images for a Module be applied
  809. * via CSS using the "background-image" property.
  810. * @property imageRoot
  811. * @type String
  812. */
  813. imageRoot: Module.IMG_ROOT,
  814. /**
  815. * Initializes the custom events for Module which are fired
  816. * automatically at appropriate times by the Module class.
  817. * @method initEvents
  818. */
  819. initEvents: function () {
  820. var SIGNATURE = CustomEvent.LIST;
  821. /**
  822. * CustomEvent fired prior to class initalization.
  823. * @event beforeInitEvent
  824. * @param {class} classRef class reference of the initializing
  825. * class, such as this.beforeInitEvent.fire(Module)
  826. */
  827. this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
  828. this.beforeInitEvent.signature = SIGNATURE;
  829. /**
  830. * CustomEvent fired after class initalization.
  831. * @event initEvent
  832. * @param {class} classRef class reference of the initializing
  833. * class, such as this.beforeInitEvent.fire(Module)
  834. */
  835. this.initEvent = this.createEvent(EVENT_TYPES.INIT);
  836. this.initEvent.signature = SIGNATURE;
  837. /**
  838. * CustomEvent fired when the Module is appended to the DOM
  839. * @event appendEvent
  840. */
  841. this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
  842. this.appendEvent.signature = SIGNATURE;
  843. /**
  844. * CustomEvent fired before the Module is rendered
  845. * @event beforeRenderEvent
  846. */
  847. this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
  848. this.beforeRenderEvent.signature = SIGNATURE;
  849. /**
  850. * CustomEvent fired after the Module is rendered
  851. * @event renderEvent
  852. */
  853. this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
  854. this.renderEvent.signature = SIGNATURE;
  855. /**
  856. * CustomEvent fired when the header content of the Module
  857. * is modified
  858. * @event changeHeaderEvent
  859. * @param {String/HTMLElement} content String/element representing
  860. * the new header content
  861. */
  862. this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
  863. this.changeHeaderEvent.signature = SIGNATURE;
  864. /**
  865. * CustomEvent fired when the body content of the Module is modified
  866. * @event changeBodyEvent
  867. * @param {String/HTMLElement} content String/element representing
  868. * the new body content
  869. */
  870. this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
  871. this.changeBodyEvent.signature = SIGNATURE;
  872. /**
  873. * CustomEvent fired when the footer content of the Module
  874. * is modified
  875. * @event changeFooterEvent
  876. * @param {String/HTMLElement} content String/element representing
  877. * the new footer content
  878. */
  879. this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
  880. this.changeFooterEvent.signature = SIGNATURE;
  881. /**
  882. * CustomEvent fired when the content of the Module is modified
  883. * @event changeContentEvent
  884. */
  885. this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
  886. this.changeContentEvent.signature = SIGNATURE;
  887. /**
  888. * CustomEvent fired when the Module is destroyed
  889. * @event destroyEvent
  890. */
  891. this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
  892. this.destroyEvent.signature = SIGNATURE;
  893. /**
  894. * CustomEvent fired before the Module is shown
  895. * @event beforeShowEvent
  896. */
  897. this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
  898. this.beforeShowEvent.signature = SIGNATURE;
  899. /**
  900. * CustomEvent fired after the Module is shown
  901. * @event showEvent
  902. */
  903. this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
  904. this.showEvent.signature = SIGNATURE;
  905. /**
  906. * CustomEvent fired before the Module is hidden
  907. * @event beforeHideEvent
  908. */
  909. this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
  910. this.beforeHideEvent.signature = SIGNATURE;
  911. /**
  912. * CustomEvent fired after the Module is hidden
  913. * @event hideEvent
  914. */
  915. this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
  916. this.hideEvent.signature = SIGNATURE;
  917. },
  918. /**
  919. * String identifying whether the current platform is windows or mac. This property
  920. * currently only identifies these 2 platforms, and returns false otherwise.
  921. * @property platform
  922. * @deprecated Use YAHOO.env.ua
  923. * @type {String|Boolean}
  924. */
  925. platform: function () {
  926. var ua = navigator.userAgent.toLowerCase();
  927. if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
  928. return "windows";
  929. } else if (ua.indexOf("macintosh") != -1) {
  930. return "mac";
  931. } else {
  932. return false;
  933. }
  934. }(),
  935. /**
  936. * String representing the user-agent of the browser
  937. * @deprecated Use YAHOO.env.ua
  938. * @property browser
  939. * @type {String|Boolean}
  940. */
  941. browser: function () {
  942. var ua = navigator.userAgent.toLowerCase();
  943. /*
  944. Check Opera first in case of spoof and check Safari before
  945. Gecko since Safari's user agent string includes "like Gecko"
  946. */
  947. if (ua.indexOf('opera') != -1) {
  948. return 'opera';
  949. } else if (ua.indexOf('msie 7') != -1) {
  950. return 'ie7';
  951. } else if (ua.indexOf('msie') != -1) {
  952. return 'ie';
  953. } else if (ua.indexOf('safari') != -1) {
  954. return 'safari';
  955. } else if (ua.indexOf('gecko') != -1) {
  956. return 'gecko';
  957. } else {
  958. return false;
  959. }
  960. }(),
  961. /**
  962. * Boolean representing whether or not the current browsing context is
  963. * secure (https)
  964. * @property isSecure
  965. * @type Boolean
  966. */
  967. isSecure: function () {
  968. if (window.location.href.toLowerCase().indexOf("https") === 0) {
  969. return true;
  970. } else {
  971. return false;
  972. }
  973. }(),
  974. /**
  975. * Initializes the custom events for Module which are fired
  976. * automatically at appropriate times by the Module class.
  977. */
  978. initDefaultConfig: function () {
  979. // Add properties //
  980. /**
  981. * Specifies whether the Module is visible on the page.
  982. * @config visible
  983. * @type Boolean
  984. * @default true
  985. */
  986. this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
  987. handler: this.configVisible,
  988. value: DEFAULT_CONFIG.VISIBLE.value,
  989. validator: DEFAULT_CONFIG.VISIBLE.validator
  990. });
  991. /**
  992. * <p>
  993. * Object or array of objects representing the ContainerEffect
  994. * classes that are active for animating the container.
  995. * </p>
  996. * <p>
  997. * <strong>NOTE:</strong> Although this configuration
  998. * property is introduced at the Module level, an out of the box
  999. * implementation is not shipped for the Module class so setting
  1000. * the proroperty on the Module class has no effect. The Overlay
  1001. * class is the first class to provide out of the box ContainerEffect
  1002. * support.
  1003. * </p>
  1004. * @config effect
  1005. * @type Object
  1006. * @default null
  1007. */
  1008. this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
  1009. handler: this.configEffect,
  1010. suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
  1011. supercedes: DEFAULT_CONFIG.EFFECT.supercedes
  1012. });
  1013. /**
  1014. * Specifies whether to create a special proxy iframe to monitor
  1015. * for user font resizing in the document
  1016. * @config monitorresize
  1017. * @type Boolean
  1018. * @default true
  1019. */
  1020. this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
  1021. handler: this.configMonitorResize,
  1022. value: DEFAULT_CONFIG.MONITOR_RESIZE.value
  1023. });
  1024. /**
  1025. * Specifies if the module should be rendered as the first child
  1026. * of document.body or appended as the last child when render is called
  1027. * with document.body as the "appendToNode".
  1028. * <p>
  1029. * Appending to the body while the DOM is still being constructed can
  1030. * lead to Operation Aborted errors in IE hence this flag is set to
  1031. * false by default.
  1032. * </p>
  1033. *
  1034. * @config appendtodocumentbody
  1035. * @type Boolean
  1036. * @default false
  1037. */
  1038. this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
  1039. value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
  1040. });
  1041. },
  1042. /**
  1043. * The Module class's initialization method, which is executed for
  1044. * Module and all of its subclasses. This method is automatically
  1045. * called by the constructor, and sets up all DOM references for
  1046. * pre-existing markup, and creates required markup if it is not
  1047. * already present.
  1048. * <p>
  1049. * If the element passed in does not have an id, one will be generated
  1050. * for it.
  1051. * </p>
  1052. * @method init
  1053. * @param {String} el The element ID representing the Module <em>OR</em>
  1054. * @param {HTMLElement} el The element representing the Module
  1055. * @param {Object} userConfig The configuration Object literal
  1056. * containing the configuration that should be set for this module.
  1057. * See configuration documentation for more details.
  1058. */
  1059. init: function (el, userConfig) {
  1060. var elId, child;
  1061. this.initEvents();
  1062. this.beforeInitEvent.fire(Module);
  1063. /**
  1064. * The Module's Config object used for monitoring
  1065. * configuration properties.
  1066. * @property cfg
  1067. * @type YAHOO.util.Config
  1068. */
  1069. this.cfg = new Config(this);
  1070. if (this.isSecure) {
  1071. this.imageRoot = Module.IMG_ROOT_SSL;
  1072. }
  1073. if (typeof el == "string") {
  1074. elId = el;
  1075. el = document.getElementById(el);
  1076. if (! el) {
  1077. el = (createModuleTemplate()).cloneNode(false);
  1078. el.id = elId;
  1079. }
  1080. }
  1081. this.id = Dom.generateId(el);
  1082. this.element = el;
  1083. child = this.element.firstChild;
  1084. if (child) {
  1085. var fndHd = false, fndBd = false, fndFt = false;
  1086. do {
  1087. // We're looking for elements
  1088. if (1 == child.nodeType) {
  1089. if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
  1090. this.header = child;
  1091. fndHd = true;
  1092. } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
  1093. this.body = child;
  1094. fndBd = true;
  1095. } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
  1096. this.footer = child;
  1097. fndFt = true;
  1098. }
  1099. }
  1100. } while ((child = child.nextSibling));
  1101. }
  1102. this.initDefaultConfig();
  1103. Dom.addClass(this.element, Module.CSS_MODULE);
  1104. if (userConfig) {
  1105. this.cfg.applyConfig(userConfig, true);
  1106. }
  1107. /*
  1108. Subscribe to the fireQueue() method of Config so that any
  1109. queued configuration changes are excecuted upon render of
  1110. the Module
  1111. */
  1112. if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
  1113. this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
  1114. }
  1115. this.initEvent.fire(Module);
  1116. },
  1117. /**
  1118. * Initialize an empty IFRAME that is placed out of the visible area
  1119. * that can be used to detect text resize.
  1120. * @method initResizeMonitor
  1121. */
  1122. initResizeMonitor: function () {
  1123. var isGeckoWin = (UA.gecko && this.platform == "windows");
  1124. if (isGeckoWin) {
  1125. // Help prevent spinning loading icon which
  1126. // started with FireFox 2.0.0.8/Win
  1127. var self = this;
  1128. setTimeout(function(){self._initResizeMonitor();}, 0);
  1129. } else {
  1130. this._initResizeMonitor();
  1131. }
  1132. },
  1133. /**
  1134. * Create and initialize the text resize monitoring iframe.
  1135. *
  1136. * @protected
  1137. * @method _initResizeMonitor
  1138. */
  1139. _initResizeMonitor : function() {
  1140. var oDoc,
  1141. oIFrame,
  1142. sHTML;
  1143. function fireTextResize() {
  1144. Module.textResizeEvent.fire();
  1145. }
  1146. if (!UA.opera) {
  1147. oIFrame = Dom.get("_yuiResizeMonitor");
  1148. var supportsCWResize = this._supportsCWResize();
  1149. if (!oIFrame) {
  1150. oIFrame = document.createElement("iframe");
  1151. if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
  1152. oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
  1153. }
  1154. if (!supportsCWResize) {
  1155. // Can't monitor on contentWindow, so fire from inside iframe
  1156. sHTML = ["<html><head><script ",
  1157. "type=\"text/javascript\">",
  1158. "window.onresize=function(){window.parent.",
  1159. "YAHOO.widget.Module.textResizeEvent.",
  1160. "fire();};<",
  1161. "\/script></head>",
  1162. "<body></body></html>"].join('');
  1163. oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
  1164. }
  1165. oIFrame.id = "_yuiResizeMonitor";
  1166. oIFrame.title = "Text Resize Monitor";
  1167. oIFrame.tabIndex = -1;
  1168. oIFrame.setAttribute("role", "presentation");
  1169. /*
  1170. Need to set "position" property before inserting the
  1171. iframe into the document or Safari's status bar will
  1172. forever indicate the iframe is loading
  1173. (See YUILibrary bug #1723064)
  1174. */
  1175. oIFrame.style.position = "absolute";
  1176. oIFrame.style.visibility = "hidden";
  1177. var db = document.body,
  1178. fc = db.firstChild;
  1179. if (fc) {
  1180. db.insertBefore(oIFrame, fc);
  1181. } else {
  1182. db.appendChild(oIFrame);
  1183. }
  1184. // Setting the background color fixes an issue with IE6/IE7, where
  1185. // elements in the DOM, with -ve margin-top which positioned them
  1186. // offscreen (so they would be overlapped by the iframe and its -ve top
  1187. // setting), would have their -ve margin-top ignored, when the iframe
  1188. // was added.
  1189. oIFrame.style.backgroundColor = "transparent";
  1190. oIFrame.style.borderWidth = "0";
  1191. oIFrame.style.width = "2em";
  1192. oIFrame.style.height = "2em";
  1193. oIFrame.style.left = "0";
  1194. oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
  1195. oIFrame.style.visibility = "visible";
  1196. /*
  1197. Don't open/close the document for Gecko like we used to, since it
  1198. leads to duplicate cookies. (See YUILibrary bug #1721755)
  1199. */
  1200. if (UA.webkit) {
  1201. oDoc = oIFrame.contentWindow.document;
  1202. oDoc.open();
  1203. oDoc.close();
  1204. }
  1205. }
  1206. if (oIFrame && oIFrame.contentWindow) {
  1207. Module.textResizeEvent.subscribe(this.onDomResize, this, true);
  1208. if (!Module.textResizeInitialized) {
  1209. if (supportsCWResize) {
  1210. if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
  1211. /*
  1212. This will fail in IE if document.domain has
  1213. changed, so we must change the listener to
  1214. use the oIFrame element instead
  1215. */
  1216. Event.on(oIFrame, "resize", fireTextResize);
  1217. }
  1218. }
  1219. Module.textResizeInitialized = true;
  1220. }
  1221. this.resizeMonitor = oIFrame;
  1222. }
  1223. }
  1224. },
  1225. /**
  1226. * Text resize monitor helper method.
  1227. * Determines if the browser supports resize events on iframe content windows.
  1228. *
  1229. * @private
  1230. * @method _supportsCWResize
  1231. */
  1232. _supportsCWResize : function() {
  1233. /*
  1234. Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
  1235. Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
  1236. We don't want to start sniffing for patch versions, so fire textResize the same
  1237. way on all FF2 flavors
  1238. */
  1239. var bSupported = true;
  1240. if (UA.gecko && UA.gecko <= 1.8) {
  1241. bSupported = false;
  1242. }
  1243. return bSupported;
  1244. },
  1245. /**
  1246. * Event handler fired when the resize monitor element is resized.
  1247. * @method onDomResize
  1248. * @param {DOMEvent} e The DOM resize event
  1249. * @param {Object} obj The scope object passed to the handler
  1250. */
  1251. onDomResize: fu