/jdk-1.5-parent/yui-parent/yui/src/main/java/org/wicketstuff/yui/inc/2.4.1/container/container_core.js

https://github.com/adben/core · JavaScript · 1526 lines · 658 code · 273 blank · 595 comment · 158 complexity · 99e4e6bae5a4e5135443652830c3f2b7 MD5 · raw file

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