/* Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version 0.12.1 */ /** * Config is a utility used within an Object to allow the implementer to maintain a list of local configuration properties and listen for changes to those properties dynamically using CustomEvent. The initial values are also maintained so that the configuration can be reset at any given point to its initial state. * @namespace YAHOO.util * @class Config * @constructor * @param {Object} owner The owner Object to which this Config Object belongs */ YAHOO.util.Config = function(owner) { if (owner) { this.init(owner); } }; YAHOO.util.Config.prototype = { /** * Object reference to the owner of this Config Object * @property owner * @type Object */ owner : null, /** * Boolean flag that specifies whether a queue is currently being executed * @property queueInProgress * @type Boolean */ queueInProgress : false, /** * Validates that the value passed in is a Boolean. * @method checkBoolean * @param {Object} val The value to validate * @return {Boolean} true, if the value is valid */ checkBoolean: function(val) { if (typeof val == 'boolean') { return true; } else { return false; } }, /** * Validates that the value passed in is a number. * @method checkNumber * @param {Object} val The value to validate * @return {Boolean} true, if the value is valid */ checkNumber: function(val) { if (isNaN(val)) { return false; } else { return true; } } }; /** * Initializes the configuration Object and all of its local members. * @method init * @param {Object} owner The owner Object to which this Config Object belongs */ YAHOO.util.Config.prototype.init = function(owner) { this.owner = owner; /** * Object reference to the owner of this Config Object * @event configChangedEvent */ this.configChangedEvent = new YAHOO.util.CustomEvent("configChanged"); this.queueInProgress = false; /* Private Members */ /** * Maintains the local collection of configuration property objects and their specified values * @property config * @private * @type Object */ var config = {}; /** * Maintains the local collection of configuration property objects as they were initially applied. * This object is used when resetting a property. * @property initialConfig * @private * @type Object */ var initialConfig = {}; /** * Maintains the local, normalized CustomEvent queue * @property eventQueue * @private * @type Object */ var eventQueue = []; /** * Fires a configuration property event using the specified value. * @method fireEvent * @private * @param {String} key The configuration property's name * @param {value} Object The value of the correct type for the property */ var fireEvent = function( key, value ) { key = key.toLowerCase(); var property = config[key]; if (typeof property != 'undefined' && property.event) { property.event.fire(value); } }; /* End Private Members */ /** * Adds a property to the Config Object's private config hash. * @method addProperty * @param {String} key The configuration property's name * @param {Object} propertyObject The Object containing all of this property's arguments */ this.addProperty = function( key, propertyObject ) { key = key.toLowerCase(); config[key] = propertyObject; propertyObject.event = new YAHOO.util.CustomEvent(key); propertyObject.key = key; if (propertyObject.handler) { propertyObject.event.subscribe(propertyObject.handler, this.owner, true); } this.setProperty(key, propertyObject.value, true); if (! propertyObject.suppressEvent) { this.queueProperty(key, propertyObject.value); } }; /** * Returns a key-value configuration map of the values currently set in the Config Object. * @method getConfig * @return {Object} The current config, represented in a key-value map */ this.getConfig = function() { var cfg = {}; for (var prop in config) { var property = config[prop]; if (typeof property != 'undefined' && property.event) { cfg[prop] = property.value; } } return cfg; }; /** * Returns the value of specified property. * @method getProperty * @param {String} key The name of the property * @return {Object} The value of the specified property */ this.getProperty = function(key) { key = key.toLowerCase(); var property = config[key]; if (typeof property != 'undefined' && property.event) { return property.value; } else { return undefined; } }; /** * Resets the specified property's value to its initial value. * @method resetProperty * @param {String} key The name of the property * @return {Boolean} True is the property was reset, false if not */ this.resetProperty = function(key) { key = key.toLowerCase(); var property = config[key]; if (typeof property != 'undefined' && property.event) { if (initialConfig[key] && initialConfig[key] != 'undefined') { this.setProperty(key, initialConfig[key]); } return true; } else { return false; } }; /** * Sets the value of a property. If the silent property is passed as true, the property's event will not be fired. * @method setProperty * @param {String} key The name of the property * @param {String} value The value to set the property to * @param {Boolean} silent Whether the value should be set silently, without firing the property event. * @return {Boolean} True, if the set was successful, false if it failed. */ this.setProperty = function(key, value, silent) { key = key.toLowerCase(); if (this.queueInProgress && ! silent) { this.queueProperty(key,value); // Currently running through a queue... return true; } else { var property = config[key]; if (typeof property != 'undefined' && property.event) { if (property.validator && ! property.validator(value)) { // validator return false; } else { property.value = value; if (! silent) { fireEvent(key, value); this.configChangedEvent.fire([key, value]); } return true; } } else { return false; } } }; /** * Sets the value of a property and queues its event to execute. If the event is already scheduled to execute, it is * moved from its current position to the end of the queue. * @method queueProperty * @param {String} key The name of the property * @param {String} value The value to set the property to * @return {Boolean} true, if the set was successful, false if it failed. */ this.queueProperty = function(key, value) { key = key.toLowerCase(); var property = config[key]; if (typeof property != 'undefined' && property.event) { if (typeof value != 'undefined' && property.validator && ! property.validator(value)) { // validator return false; } else { if (typeof value != 'undefined') { property.value = value; } else { value = property.value; } var foundDuplicate = false; for (var i=0;iOR * @param {HTMLElement} el The element representing the Module * @param {Object} userConfig The configuration Object literal containing the configuration that should be set for this module. See configuration documentation for more details. */ YAHOO.widget.Module = function(el, userConfig) { if (el) { this.init(el, userConfig); } }; /** * Constant representing the prefix path to use for non-secure images * @property YAHOO.widget.Module.IMG_ROOT * @static * @final * @type String */ YAHOO.widget.Module.IMG_ROOT = "http://us.i1.yimg.com/us.yimg.com/i/"; /** * Constant representing the prefix path to use for securely served images * @property YAHOO.widget.Module.IMG_ROOT_SSL * @static * @final * @type String */ YAHOO.widget.Module.IMG_ROOT_SSL = "https://a248.e.akamai.net/sec.yimg.com/i/"; /** * Constant for the default CSS class name that represents a Module * @property YAHOO.widget.Module.CSS_MODULE * @static * @final * @type String */ YAHOO.widget.Module.CSS_MODULE = "module"; /** * Constant representing the module header * @property YAHOO.widget.Module.CSS_HEADER * @static * @final * @type String */ YAHOO.widget.Module.CSS_HEADER = "hd"; /** * Constant representing the module body * @property YAHOO.widget.Module.CSS_BODY * @static * @final * @type String */ YAHOO.widget.Module.CSS_BODY = "bd"; /** * Constant representing the module footer * @property YAHOO.widget.Module.CSS_FOOTER * @static * @final * @type String */ YAHOO.widget.Module.CSS_FOOTER = "ft"; /** * Constant representing the url for the "src" attribute of the iframe used to monitor changes to the browser's base font size * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL * @static * @final * @type String */ YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;"; /** * Singleton CustomEvent fired when the font size is changed in the browser. * Opera's "zoom" functionality currently does not support text size detection. * @event YAHOO.widget.Module.textResizeEvent */ YAHOO.widget.Module.textResizeEvent = new YAHOO.util.CustomEvent("textResize"); YAHOO.widget.Module.prototype = { /** * The class's constructor function * @property contructor * @type Function */ constructor : YAHOO.widget.Module, /** * The main module element that contains the header, body, and footer * @property element * @type HTMLElement */ element : null, /** * The header element, denoted with CSS class "hd" * @property header * @type HTMLElement */ header : null, /** * The body element, denoted with CSS class "bd" * @property body * @type HTMLElement */ body : null, /** * The footer element, denoted with CSS class "ft" * @property footer * @type HTMLElement */ footer : null, /** * The id of the element * @property id * @type String */ id : null, /** * The String representing the image root * @property imageRoot * @type String */ imageRoot : YAHOO.widget.Module.IMG_ROOT, /** * Initializes the custom events for Module which are fired automatically at appropriate times by the Module class. * @method initEvents */ initEvents : function() { /** * CustomEvent fired prior to class initalization. * @event beforeInitEvent * @param {class} classRef class reference of the initializing class, such as this.beforeInitEvent.fire(YAHOO.widget.Module) */ this.beforeInitEvent = new YAHOO.util.CustomEvent("beforeInit"); /** * CustomEvent fired after class initalization. * @event initEvent * @param {class} classRef class reference of the initializing class, such as this.beforeInitEvent.fire(YAHOO.widget.Module) */ this.initEvent = new YAHOO.util.CustomEvent("init"); /** * CustomEvent fired when the Module is appended to the DOM * @event appendEvent */ this.appendEvent = new YAHOO.util.CustomEvent("append"); /** * CustomEvent fired before the Module is rendered * @event beforeRenderEvent */ this.beforeRenderEvent = new YAHOO.util.CustomEvent("beforeRender"); /** * CustomEvent fired after the Module is rendered * @event renderEvent */ this.renderEvent = new YAHOO.util.CustomEvent("render"); /** * CustomEvent fired when the header content of the Module is modified * @event changeHeaderEvent * @param {String/HTMLElement} content String/element representing the new header content */ this.changeHeaderEvent = new YAHOO.util.CustomEvent("changeHeader"); /** * CustomEvent fired when the body content of the Module is modified * @event changeBodyEvent * @param {String/HTMLElement} content String/element representing the new body content */ this.changeBodyEvent = new YAHOO.util.CustomEvent("changeBody"); /** * CustomEvent fired when the footer content of the Module is modified * @event changeFooterEvent * @param {String/HTMLElement} content String/element representing the new footer content */ this.changeFooterEvent = new YAHOO.util.CustomEvent("changeFooter"); /** * CustomEvent fired when the content of the Module is modified * @event changeContentEvent */ this.changeContentEvent = new YAHOO.util.CustomEvent("changeContent"); /** * CustomEvent fired when the Module is destroyed * @event destroyEvent */ this.destroyEvent = new YAHOO.util.CustomEvent("destroy"); /** * CustomEvent fired before the Module is shown * @event beforeShowEvent */ this.beforeShowEvent = new YAHOO.util.CustomEvent("beforeShow"); /** * CustomEvent fired after the Module is shown * @event showEvent */ this.showEvent = new YAHOO.util.CustomEvent("show"); /** * CustomEvent fired before the Module is hidden * @event beforeHideEvent */ this.beforeHideEvent = new YAHOO.util.CustomEvent("beforeHide"); /** * CustomEvent fired after the Module is hidden * @event hideEvent */ this.hideEvent = new YAHOO.util.CustomEvent("hide"); }, /** * String representing the current user-agent platform * @property platform * @type String */ platform : function() { var ua = navigator.userAgent.toLowerCase(); if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) { return "windows"; } else if (ua.indexOf("macintosh") != -1) { return "mac"; } else { return false; } }(), /** * String representing the current user-agent browser * @property browser * @type String */ browser : function() { var ua = navigator.userAgent.toLowerCase(); if (ua.indexOf('opera')!=-1) { // Opera (check first in case of spoof) return 'opera'; } else if (ua.indexOf('msie 7')!=-1) { // IE7 return 'ie7'; } else if (ua.indexOf('msie') !=-1) { // IE return 'ie'; } else if (ua.indexOf('safari')!=-1) { // Safari (check before Gecko because it includes "like Gecko") return 'safari'; } else if (ua.indexOf('gecko') != -1) { // Gecko return 'gecko'; } else { return false; } }(), /** * Boolean representing whether or not the current browsing context is secure (https) * @property isSecure * @type Boolean */ isSecure : function() { if (window.location.href.toLowerCase().indexOf("https") === 0) { return true; } else { return false; } }(), /** * Initializes the custom events for Module which are fired automatically at appropriate times by the Module class. */ initDefaultConfig : function() { // Add properties // /** * Specifies whether the Module is visible on the page. * @config visible * @type Boolean * @default true */ this.cfg.addProperty("visible", { value:true, handler:this.configVisible, validator:this.cfg.checkBoolean } ); /** * Object or array of objects representing the ContainerEffect classes that are active for animating the container. * @config effect * @type Object * @default null */ this.cfg.addProperty("effect", { suppressEvent:true, supercedes:["visible"] } ); /** * Specifies whether to create a special proxy iframe to monitor for user font resizing in the document * @config monitorresize * @type Boolean * @default true */ this.cfg.addProperty("monitorresize", { value:true, handler:this.configMonitorResize } ); }, /** * The Module class's initialization method, which is executed for Module and all of its subclasses. This method is automatically called by the constructor, and sets up all DOM references for pre-existing markup, and creates required markup if it is not already present. * @method init * @param {String} el The element ID representing the Module OR * @param {HTMLElement} el The element representing the Module * @param {Object} userConfig The configuration Object literal containing the configuration that should be set for this module. See configuration documentation for more details. */ init : function(el, userConfig) { this.initEvents(); this.beforeInitEvent.fire(YAHOO.widget.Module); /** * The Module's Config object used for monitoring configuration properties. * @property cfg * @type YAHOO.util.Config */ this.cfg = new YAHOO.util.Config(this); if (this.isSecure) { this.imageRoot = YAHOO.widget.Module.IMG_ROOT_SSL; } if (typeof el == "string") { var elId = el; el = document.getElementById(el); if (! el) { el = document.createElement("DIV"); el.id = elId; } } this.element = el; if (el.id) { this.id = el.id; } var childNodes = this.element.childNodes; if (childNodes) { for (var i=0;iOR * @param {HTMLElement} headerContent The HTMLElement to append to the header */ setHeader : function(headerContent) { if (! this.header) { this.header = document.createElement("DIV"); this.header.className = YAHOO.widget.Module.CSS_HEADER; } if (typeof headerContent == "string") { this.header.innerHTML = headerContent; } else { this.header.innerHTML = ""; this.header.appendChild(headerContent); } this.changeHeaderEvent.fire(headerContent); this.changeContentEvent.fire(); }, /** * Appends the passed element to the header. If no header is present, one will be automatically created. * @method appendToHeader * @param {HTMLElement} element The element to append to the header */ appendToHeader : function(element) { if (! this.header) { this.header = document.createElement("DIV"); this.header.className = YAHOO.widget.Module.CSS_HEADER; } this.header.appendChild(element); this.changeHeaderEvent.fire(element); this.changeContentEvent.fire(); }, /** * Sets the Module's body content to the HTML specified, or appends the passed element to the body. If no body is present, one will be automatically created. * @method setBody * @param {String} bodyContent The HTML used to set the body OR * @param {HTMLElement} bodyContent The HTMLElement to append to the body */ setBody : function(bodyContent) { if (! this.body) { this.body = document.createElement("DIV"); this.body.className = YAHOO.widget.Module.CSS_BODY; } if (typeof bodyContent == "string") { this.body.innerHTML = bodyContent; } else { this.body.innerHTML = ""; this.body.appendChild(bodyContent); } this.changeBodyEvent.fire(bodyContent); this.changeContentEvent.fire(); }, /** * Appends the passed element to the body. If no body is present, one will be automatically created. * @method appendToBody * @param {HTMLElement} element The element to append to the body */ appendToBody : function(element) { if (! this.body) { this.body = document.createElement("DIV"); this.body.className = YAHOO.widget.Module.CSS_BODY; } this.body.appendChild(element); this.changeBodyEvent.fire(element); this.changeContentEvent.fire(); }, /** * Sets the Module's footer content to the HTML specified, or appends the passed element to the footer. If no footer is present, one will be automatically created. * @method setFooter * @param {String} footerContent The HTML used to set the footer OR * @param {HTMLElement} footerContent The HTMLElement to append to the footer */ setFooter : function(footerContent) { if (! this.footer) { this.footer = document.createElement("DIV"); this.footer.className = YAHOO.widget.Module.CSS_FOOTER; } if (typeof footerContent == "string") { this.footer.innerHTML = footerContent; } else { this.footer.innerHTML = ""; this.footer.appendChild(footerContent); } this.changeFooterEvent.fire(footerContent); this.changeContentEvent.fire(); }, /** * Appends the passed element to the footer. If no footer is present, one will be automatically created. * @method appendToFooter * @param {HTMLElement} element The element to append to the footer */ appendToFooter : function(element) { if (! this.footer) { this.footer = document.createElement("DIV"); this.footer.className = YAHOO.widget.Module.CSS_FOOTER; } this.footer.appendChild(element); this.changeFooterEvent.fire(element); this.changeContentEvent.fire(); }, /** * Renders the Module by inserting the elements that are not already in the main Module into their correct places. Optionally appends the Module to the specified node prior to the render's execution. NOTE: For Modules without existing markup, the appendToNode argument is REQUIRED. If this argument is ommitted and the current element is not present in the document, the function will return false, indicating that the render was a failure. * @method render * @param {String} appendToNode The element id to which the Module should be appended to prior to rendering OR * @param {HTMLElement} appendToNode The element to which the Module should be appended to prior to rendering * @param {HTMLElement} moduleElement OPTIONAL. The element that represents the actual Standard Module container. * @return {Boolean} Success or failure of the render */ render : function(appendToNode, moduleElement) { this.beforeRenderEvent.fire(); if (! moduleElement) { moduleElement = this.element; } var me = this; var appendTo = function(element) { if (typeof element == "string") { element = document.getElementById(element); } if (element) { element.appendChild(me.element); me.appendEvent.fire(); } }; if (appendToNode) { appendTo(appendToNode); } else { // No node was passed in. If the element is not pre-marked up, this fails if (! YAHOO.util.Dom.inDocument(this.element)) { return false; } } // Need to get everything into the DOM if it isn't already if (this.header && ! YAHOO.util.Dom.inDocument(this.header)) { // There is a header, but it's not in the DOM yet... need to add it var firstChild = moduleElement.firstChild; if (firstChild) { // Insert before first child if exists moduleElement.insertBefore(this.header, firstChild); } else { // Append to empty body because there are no children moduleElement.appendChild(this.header); } } if (this.body && ! YAHOO.util.Dom.inDocument(this.body)) { // There is a body, but it's not in the DOM yet... need to add it if (this.footer && YAHOO.util.Dom.isAncestor(this.moduleElement, this.footer)) { // Insert before footer if exists in DOM moduleElement.insertBefore(this.body, this.footer); } else { // Append to element because there is no footer moduleElement.appendChild(this.body); } } if (this.footer && ! YAHOO.util.Dom.inDocument(this.footer)) { // There is a footer, but it's not in the DOM yet... need to add it moduleElement.appendChild(this.footer); } this.renderEvent.fire(); return true; }, /** * Removes the Module element from the DOM and sets all child elements to null. * @method destroy */ destroy : function() { var parent; if (this.element) { YAHOO.util.Event.purgeElement(this.element, true); parent = this.element.parentNode; } if (parent) { parent.removeChild(this.element); } this.element = null; this.header = null; this.body = null; this.footer = null; for (var e in this) { if (e instanceof YAHOO.util.CustomEvent) { e.unsubscribeAll(); } } YAHOO.widget.Module.textResizeEvent.unsubscribe(this.onDomResize, this); this.destroyEvent.fire(); }, /** * Shows the Module element by setting the visible configuration property to true. Also fires two events: beforeShowEvent prior to the visibility change, and showEvent after. * @method show */ show : function() { this.cfg.setProperty("visible", true); }, /** * Hides the Module element by setting the visible configuration property to false. Also fires two events: beforeHideEvent prior to the visibility change, and hideEvent after. * @method hide */ hide : function() { this.cfg.setProperty("visible", false); }, // BUILT-IN EVENT HANDLERS FOR MODULE // /** * Default event handler for changing the visibility property of a Module. By default, this is achieved by switching the "display" style between "block" and "none". * This method is responsible for firing showEvent and hideEvent. * @param {String} type The CustomEvent type (usually the property name) * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner. * @method configVisible */ configVisible : function(type, args, obj) { var visible = args[0]; if (visible) { this.beforeShowEvent.fire(); YAHOO.util.Dom.setStyle(this.element, "display", "block"); this.showEvent.fire(); } else { this.beforeHideEvent.fire(); YAHOO.util.Dom.setStyle(this.element, "display", "none"); this.hideEvent.fire(); } }, /** * Default event handler for the "monitorresize" configuration property * @param {String} type The CustomEvent type (usually the property name) * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner. * @method configMonitorResize */ configMonitorResize : function(type, args, obj) { var monitor = args[0]; if (monitor) { this.initResizeMonitor(); } else { YAHOO.util.Event.removeListener(this.resizeMonitor, "resize", this.onDomResize); this.resizeMonitor = null; } } }; /** * Returns a String representation of the Object. * @method toString * @return {String} The string representation of the Module */ YAHOO.widget.Module.prototype.toString = function() { return "Module " + this.id; }; /** * Overlay is a Module that is absolutely positioned above the page flow. It has convenience methods for positioning and sizing, as well as options for controlling zIndex and constraining the Overlay's position to the current visible viewport. Overlay also contains a dynamicly generated IFRAME which is placed beneath it for Internet Explorer 6 and 5.x so that it will be properly rendered above SELECT elements. * @namespace YAHOO.widget * @class Overlay * @extends YAHOO.widget.Module * @param {String} el The element ID representing the Overlay OR * @param {HTMLElement} el The element representing the Overlay * @param {Object} userConfig The configuration object literal containing 10/23/2006the configuration that should be set for this Overlay. See configuration documentation for more details. * @constructor */ YAHOO.widget.Overlay = function(el, userConfig) { YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig); }; YAHOO.extend(YAHOO.widget.Overlay, YAHOO.widget.Module); /** * The URL that will be placed in the iframe * @property YAHOO.widget.Overlay.IFRAME_SRC * @static * @final * @type String */ YAHOO.widget.Overlay.IFRAME_SRC = "javascript:false;"; /** * Constant representing the top left corner of an element, used for configuring the context element alignment * @property YAHOO.widget.Overlay.TOP_LEFT * @static * @final * @type String */ YAHOO.widget.Overlay.TOP_LEFT = "tl"; /** * Constant representing the top right corner of an element, used for configuring the context element alignment * @property YAHOO.widget.Overlay.TOP_RIGHT * @static * @final * @type String */ YAHOO.widget.Overlay.TOP_RIGHT = "tr"; /** * Constant representing the top bottom left corner of an element, used for configuring the context element alignment * @property YAHOO.widget.Overlay.BOTTOM_LEFT * @static * @final * @type String */ YAHOO.widget.Overlay.BOTTOM_LEFT = "bl"; /** * Constant representing the bottom right corner of an element, used for configuring the context element alignment * @property YAHOO.widget.Overlay.BOTTOM_RIGHT * @static * @final * @type String */ YAHOO.widget.Overlay.BOTTOM_RIGHT = "br"; /** * Constant representing the default CSS class used for an Overlay * @property YAHOO.widget.Overlay.CSS_OVERLAY * @static * @final * @type String */ YAHOO.widget.Overlay.CSS_OVERLAY = "overlay"; /** * The Overlay initialization method, which is executed for Overlay and all of its subclasses. This method is automatically called by the constructor, and sets up all DOM references for pre-existing markup, and creates required markup if it is not already present. * @method init * @param {String} el The element ID representing the Overlay OR * @param {HTMLElement} el The element representing the Overlay * @param {Object} userConfig The configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details. */ YAHOO.widget.Overlay.prototype.init = function(el, userConfig) { YAHOO.widget.Overlay.superclass.init.call(this, el/*, userConfig*/); // Note that we don't pass the user config in here yet because we only want it executed once, at the lowest subclass level this.beforeInitEvent.fire(YAHOO.widget.Overlay); YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Overlay.CSS_OVERLAY); if (userConfig) { this.cfg.applyConfig(userConfig, true); } if (this.platform == "mac" && this.browser == "gecko") { if (! YAHOO.util.Config.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)) { this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true); } if (! YAHOO.util.Config.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)) { this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true); } } this.initEvent.fire(YAHOO.widget.Overlay); }; /** * Initializes the custom events for Overlay which are fired automatically at appropriate times by the Overlay class. * @method initEvents */ YAHOO.widget.Overlay.prototype.initEvents = function() { YAHOO.widget.Overlay.superclass.initEvents.call(this); /** * CustomEvent fired before the Overlay is moved. * @event beforeMoveEvent * @param {Number} x x coordinate * @param {Number} y y coordinate */ this.beforeMoveEvent = new YAHOO.util.CustomEvent("beforeMove", this); /** * CustomEvent fired after the Overlay is moved. * @event moveEvent * @param {Number} x x coordinate * @param {Number} y y coordinate */ this.moveEvent = new YAHOO.util.CustomEvent("move", this); }; /** * Initializes the class's configurable properties which can be changed using the Overlay's Config object (cfg). * @method initDefaultConfig */ YAHOO.widget.Overlay.prototype.initDefaultConfig = function() { YAHOO.widget.Overlay.superclass.initDefaultConfig.call(this); // Add overlay config properties // /** * The absolute x-coordinate position of the Overlay * @config x * @type Number * @default null */ this.cfg.addProperty("x", { handler:this.configX, validator:this.cfg.checkNumber, suppressEvent:true, supercedes:["iframe"] } ); /** * The absolute y-coordinate position of the Overlay * @config y * @type Number * @default null */ this.cfg.addProperty("y", { handler:this.configY, validator:this.cfg.checkNumber, suppressEvent:true, supercedes:["iframe"] } ); /** * An array with the absolute x and y positions of the Overlay * @config xy * @type Number[] * @default null */ this.cfg.addProperty("xy",{ handler:this.configXY, suppressEvent:true, supercedes:["iframe"] } ); /** * The array of context arguments for context-sensitive positioning. The format is: [id or element, element corner, context corner]. For example, setting this property to ["img1", "tl", "bl"] would align the Overlay's top left corner to the context element's bottom left corner. * @config context * @type Array * @default null */ this.cfg.addProperty("context", { handler:this.configContext, suppressEvent:true, supercedes:["iframe"] } ); /** * True if the Overlay should be anchored to the center of the viewport. * @config fixedcenter * @type Boolean * @default false */ this.cfg.addProperty("fixedcenter", { value:false, handler:this.configFixedCenter, validator:this.cfg.checkBoolean, supercedes:["iframe","visible"] } ); /** * CSS width of the Overlay. * @config width * @type String * @default null */ this.cfg.addProperty("width", { handler:this.configWidth, suppressEvent:true, supercedes:["iframe"] } ); /** * CSS height of the Overlay. * @config height * @type String * @default null */ this.cfg.addProperty("height", { handler:this.configHeight, suppressEvent:true, supercedes:["iframe"] } ); /** * CSS z-index of the Overlay. * @config zIndex * @type Number * @default null */ this.cfg.addProperty("zIndex", { value:null, handler:this.configzIndex } ); /** * True if the Overlay should be prevented from being positioned out of the viewport. * @config constraintoviewport * @type Boolean * @default false */ this.cfg.addProperty("constraintoviewport", { value:false, handler:this.configConstrainToViewport, validator:this.cfg.checkBoolean, supercedes:["iframe","x","y","xy"] } ); /** * True if the Overlay should have an IFRAME shim (for correcting the select z-index bug in IE6 and below). * @config iframe * @type Boolean * @default true for IE6 and below, false for all others */ this.cfg.addProperty("iframe", { value:(this.browser == "ie" ? true : false), handler:this.configIframe, validator:this.cfg.checkBoolean, supercedes:["zIndex"] } ); }; /** * Moves the Overlay to the specified position. This function is identical to calling this.cfg.setProperty("xy", [x,y]); * @method moveTo * @param {Number} x The Overlay's new x position * @param {Number} y The Overlay's new y position */ YAHOO.widget.Overlay.prototype.moveTo = function(x, y) { this.cfg.setProperty("xy",[x,y]); }; /** * Adds a special CSS class to the Overlay when Mac/Gecko is in use, to work around a Gecko bug where * scrollbars cannot be hidden. See https://bugzilla.mozilla.org/show_bug.cgi?id=187435 * @method hideMacGeckoScrollbars */ YAHOO.widget.Overlay.prototype.hideMacGeckoScrollbars = function() { YAHOO.util.Dom.removeClass(this.element, "show-scrollbars"); YAHOO.util.Dom.addClass(this.element, "hide-scrollbars"); }; /** * Removes a special CSS class from the Overlay when Mac/Gecko is in use, to work around a Gecko bug where * scrollbars cannot be hidden. See https://bugzilla.mozilla.org/show_bug.cgi?id=187435 * @method showMacGeckoScrollbars */ YAHOO.widget.Overlay.prototype.showMacGeckoScrollbars = function() { YAHOO.util.Dom.removeClass(this.element, "hide-scrollbars"); YAHOO.util.Dom.addClass(this.element, "show-scrollbars"); }; // BEGIN BUILT-IN PROPERTY EVENT HANDLERS // /** * The default event handler fired when the "visible" property is changed. This method is responsible for firing showEvent and hideEvent. * @method configVisible * @param {String} type The CustomEvent type (usually the property name) * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner. */ YAHOO.widget.Overlay.prototype.configVisible = function(type, args, obj) { var visible = args[0]; var currentVis = YAHOO.util.Dom.getStyle(this.element, "visibility"); if (currentVis == "inherit") { var e = this.element.parentNode; while (e.nodeType != 9 && e.nodeType != 11) { currentVis = YAHOO.util.Dom.getStyle(e, "visibility"); if (currentVis != "inherit") { break; } e = e.parentNode; } if (currentVis == "inherit") { currentVis = "visible"; } } var effect = this.cfg.getProperty("effect"); var effectInstances = []; if (effect) { if (effect instanceof Array) { for (var i=0;i rightConstraint) { x = rightConstraint; } if (y < topConstraint) { y = topConstraint; } else if (y > bottomConstraint) { y = bottomConstraint; } this.cfg.setProperty("x", x, true); this.cfg.setProperty("y", y, true); this.cfg.setProperty("xy", [x,y], true); }; /** * Centers the container in the viewport. * @method center */ YAHOO.widget.Overlay.prototype.center = function() { var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; var scrollY = document.documentElement.scrollTop || document.body.scrollTop; var viewPortWidth = YAHOO.util.Dom.getClientWidth(); var viewPortHeight = YAHOO.util.Dom.getClientHeight(); var elementWidth = this.element.offsetWidth; var elementHeight = this.element.offsetHeight; var x = (viewPortWidth / 2) - (elementWidth / 2) + scrollX; var y = (viewPortHeight / 2) - (elementHeight / 2) + scrollY; this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]); this.cfg.refireEvent("iframe"); }; /** * Synchronizes the Panel's "xy", "x", and "y" properties with the Panel's position in the DOM. This is primarily used to update position information during drag & drop. * @method syncPosition */ YAHOO.widget.Overlay.prototype.syncPosition = function() { var pos = YAHOO.util.Dom.getXY(this.element); this.cfg.setProperty("x", pos[0], true); this.cfg.setProperty("y", pos[1], true); this.cfg.setProperty("xy", pos, true); }; /** * Event handler fired when the resize monitor element is resized. * @method onDomResize * @param {DOMEvent} e The resize DOM event * @param {Object} obj The scope object */ YAHOO.widget.Overlay.prototype.onDomResize = function(e, obj) { YAHOO.widget.Overlay.superclass.onDomResize.call(this, e, obj); var me = this; setTimeout(function() { me.syncPosition(); me.cfg.refireEvent("iframe"); me.cfg.refireEvent("context"); }, 0); }; /** * Removes the Overlay element from the DOM and sets all child elements to null. * @method destroy */ YAHOO.widget.Overlay.prototype.destroy = function() { if (this.iframe) { this.iframe.parentNode.removeChild(this.iframe); } this.iframe = null; YAHOO.widget.Overlay.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this); YAHOO.widget.Overlay.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this); YAHOO.widget.Overlay.superclass.destroy.call(this); }; /** * Returns a String representation of the object. * @method toString * @return {String} The string representation of the Overlay. */ YAHOO.widget.Overlay.prototype.toString = function() { return "Overlay " + this.id; }; /** * A singleton CustomEvent used for reacting to the DOM event for window scroll * @event YAHOO.widget.Overlay.windowScrollEvent */ YAHOO.widget.Overlay.windowScrollEvent = new YAHOO.util.CustomEvent("windowScroll"); /** * A singleton CustomEvent used for reacting to the DOM event for window resize * @event YAHOO.widget.Overlay.windowResizeEvent */ YAHOO.widget.Overlay.windowResizeEvent = new YAHOO.util.CustomEvent("windowResize"); /** * The DOM event handler used to fire the CustomEvent for window scroll * @method YAHOO.widget.Overlay.windowScrollHandler * @static * @param {DOMEvent} e The DOM scroll event */ YAHOO.widget.Overlay.windowScrollHandler = function(e) { if (YAHOO.widget.Module.prototype.browser == "ie" || YAHOO.widget.Module.prototype.browser == "ie7") { if (! window.scrollEnd) { window.scrollEnd = -1; } clearTimeout(window.scrollEnd); window.scrollEnd = setTimeout(function() { YAHOO.widget.Overlay.windowScrollEvent.fire(); }, 1); } else { YAHOO.widget.Overlay.windowScrollEvent.fire(); } }; /** * The DOM event handler used to fire the CustomEvent for window resize * @method YAHOO.widget.Overlay.windowResizeHandler * @static * @param {DOMEvent} e The DOM resize event */ YAHOO.widget.Overlay.windowResizeHandler = function(e) { if (YAHOO.widget.Module.prototype.browser == "ie" || YAHOO.widget.Module.prototype.browser == "ie7") { if (! window.resizeEnd) { window.resizeEnd = -1; } clearTimeout(window.resizeEnd); window.resizeEnd = setTimeout(function() { YAHOO.widget.Overlay.windowResizeEvent.fire(); }, 100); } else { YAHOO.widget.Overlay.windowResizeEvent.fire(); } }; /** * A boolean that indicated whether the window resize and scroll events have already been subscribed to. * @property YAHOO.widget.Overlay._initialized * @private * @type Boolean */ YAHOO.widget.Overlay._initialized = null; if (YAHOO.widget.Overlay._initialized === null) { YAHOO.util.Event.addListener(window, "scroll", YAHOO.widget.Overlay.windowScrollHandler); YAHOO.util.Event.addListener(window, "resize", YAHOO.widget.Overlay.windowResizeHandler); YAHOO.widget.Overlay._initialized = true; } /** * OverlayManager is used for maintaining the focus status of multiple Overlays.* @namespace YAHOO.widget * @namespace YAHOO.widget * @class OverlayManager * @constructor * @param {Array} overlays Optional. A collection of Overlays to register with the manager. * @param {Object} userConfig The object literal representing the user configuration of the OverlayManager */ YAHOO.widget.OverlayManager = function(userConfig) { this.init(userConfig); }; /** * The CSS class representing a focused Overlay * @property YAHOO.widget.OverlayManager.CSS_FOCUSED * @static * @final * @type String */ YAHOO.widget.OverlayManager.CSS_FOCUSED = "focused"; YAHOO.widget.OverlayManager.prototype = { /** * The class's constructor function * @property contructor * @type Function */ constructor : YAHOO.widget.OverlayManager, /** * The array of Overlays that are currently registered * @property overlays * @type YAHOO.widget.Overlay[] */ overlays : null, /** * Initializes the default configuration of the OverlayManager * @method initDefaultConfig */ initDefaultConfig : function() { /** * The collection of registered Overlays in use by the OverlayManager * @config overlays * @type YAHOO.widget.Overlay[] * @default null */ this.cfg.addProperty("overlays", { suppressEvent:true } ); /** * The default DOM event that should be used to focus an Overlay * @config focusevent * @type String * @default "mousedown" */ this.cfg.addProperty("focusevent", { value:"mousedown" } ); }, /** * Initializes the OverlayManager * @method init * @param {YAHOO.widget.Overlay[]} overlays Optional. A collection of Overlays to register with the manager. * @param {Object} userConfig The object literal representing the user configuration of the OverlayManager */ init : function(userConfig) { /** * The OverlayManager's Config object used for monitoring configuration properties. * @property cfg * @type YAHOO.util.Config */ this.cfg = new YAHOO.util.Config(this); this.initDefaultConfig(); if (userConfig) { this.cfg.applyConfig(userConfig, true); } this.cfg.fireQueue(); /** * The currently activated Overlay * @property activeOverlay * @private * @type YAHOO.widget.Overlay */ var activeOverlay = null; /** * Returns the currently focused Overlay * @method getActive * @return {YAHOO.widget.Overlay} The currently focused Overlay */ this.getActive = function() { return activeOverlay; }; /** * Focuses the specified Overlay * @method focus * @param {YAHOO.widget.Overlay} overlay The Overlay to focus * @param {String} overlay The id of the Overlay to focus */ this.focus = function(overlay) { var o = this.find(overlay); if (o) { this.blurAll(); activeOverlay = o; YAHOO.util.Dom.addClass(activeOverlay.element, YAHOO.widget.OverlayManager.CSS_FOCUSED); this.overlays.sort(this.compareZIndexDesc); var topZIndex = YAHOO.util.Dom.getStyle(this.overlays[0].element, "zIndex"); if (! isNaN(topZIndex) && this.overlays[0] != overlay) { activeOverlay.cfg.setProperty("zIndex", (parseInt(topZIndex, 10) + 2)); } this.overlays.sort(this.compareZIndexDesc); } }; /** * Removes the specified Overlay from the manager * @method remove * @param {YAHOO.widget.Overlay} overlay The Overlay to remove * @param {String} overlay The id of the Overlay to remove */ this.remove = function(overlay) { var o = this.find(overlay); if (o) { var originalZ = YAHOO.util.Dom.getStyle(o.element, "zIndex"); o.cfg.setProperty("zIndex", -1000, true); this.overlays.sort(this.compareZIndexDesc); this.overlays = this.overlays.slice(0, this.overlays.length-1); o.cfg.setProperty("zIndex", originalZ, true); o.cfg.setProperty("manager", null); o.focusEvent = null; o.blurEvent = null; o.focus = null; o.blur = null; } }; /** * Removes focus from all registered Overlays in the manager * @method blurAll */ this.blurAll = function() { activeOverlay = null; for (var o=0;o 0) { return true; } } else { return false; } }, /** * Attempts to locate an Overlay by instance or ID. * @method find * @param {YAHOO.widget.Overlay} overlay An Overlay to locate within the manager * @param {String} overlay An Overlay id to locate within the manager * @return {YAHOO.widget.Overlay} The requested Overlay, if found, or null if it cannot be located. */ find : function(overlay) { if (overlay instanceof YAHOO.widget.Overlay) { for (var o=0;o zIndex2) { return -1; } else if (zIndex1 < zIndex2) { return 1; } else { return 0; } }, /** * Shows all Overlays in the manager. * @method showAll */ showAll : function() { for (var o=0;oOR * @param {HTMLElement} el The element representing the Tooltip * @param {Object} userConfig The configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details. */ YAHOO.widget.Tooltip = function(el, userConfig) { YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig); }; YAHOO.extend(YAHOO.widget.Tooltip, YAHOO.widget.Overlay); /** * Constant representing the Tooltip CSS class * @property YAHOO.widget.Tooltip.CSS_TOOLTIP * @static * @final * @type String */ YAHOO.widget.Tooltip.CSS_TOOLTIP = "tt"; /** * The Tooltip initialization method. This method is automatically called by the constructor. A Tooltip is automatically rendered by the init method, and it also is set to be invisible by default, and constrained to viewport by default as well. * @method init * @param {String} el The element ID representing the Tooltip OR * @param {HTMLElement} el The element representing the Tooltip * @param {Object} userConfig The configuration object literal containing the configuration that should be set for this Tooltip. See configuration documentation for more details. */ YAHOO.widget.Tooltip.prototype.init = function(el, userConfig) { if (document.readyState && document.readyState != "complete") { var deferredInit = function() { this.init(el, userConfig); }; YAHOO.util.Event.addListener(window, "load", deferredInit, this, true); } else { YAHOO.widget.Tooltip.superclass.init.call(this, el); this.beforeInitEvent.fire(YAHOO.widget.Tooltip); YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Tooltip.CSS_TOOLTIP); if (userConfig) { this.cfg.applyConfig(userConfig, true); } this.cfg.queueProperty("visible",false); this.cfg.queueProperty("constraintoviewport",true); this.setBody(""); this.render(this.cfg.getProperty("container")); this.initEvent.fire(YAHOO.widget.Tooltip); } }; /** * Initializes the class's configurable properties which can be changed using the Overlay's Config object (cfg). * @method initDefaultConfig */ YAHOO.widget.Tooltip.prototype.initDefaultConfig = function() { YAHOO.widget.Tooltip.superclass.initDefaultConfig.call(this); /** * Specifies whether the Tooltip should be kept from overlapping its context element. * @config preventoverlap * @type Boolean * @default true */ this.cfg.addProperty("preventoverlap", { value:true, validator:this.cfg.checkBoolean, supercedes:["x","y","xy"] } ); /** * The number of milliseconds to wait before showing a Tooltip on mouseover. * @config showdelay * @type Number * @default 200 */ this.cfg.addProperty("showdelay", { value:200, handler:this.configShowDelay, validator:this.cfg.checkNumber } ); /** * The number of milliseconds to wait before automatically dismissing a Tooltip after the mouse has been resting on the context element. * @config autodismissdelay * @type Number * @default 5000 */ this.cfg.addProperty("autodismissdelay", { value:5000, handler:this.configAutoDismissDelay, validator:this.cfg.checkNumber } ); /** * The number of milliseconds to wait before hiding a Tooltip on mouseover. * @config hidedelay * @type Number * @default 250 */ this.cfg.addProperty("hidedelay", { value:250, handler:this.configHideDelay, validator:this.cfg.checkNumber } ); /** * Specifies the Tooltip's text. * @config text * @type String * @default null */ this.cfg.addProperty("text", { handler:this.configText, suppressEvent:true } ); /** * Specifies the container element that the Tooltip's markup should be rendered into. * @config container * @type HTMLElement/String * @default document.body */ this.cfg.addProperty("container", { value:document.body, handler:this.configContainer } ); /** * Specifies the element or elements that the Tooltip should be anchored to on mouseover. * @config context * @type HTMLElement[]/String[] * @default null */ }; // BEGIN BUILT-IN PROPERTY EVENT HANDLERS // /** * The default event handler fired when the "text" property is changed. * @method configText * @param {String} type The CustomEvent type (usually the property name) * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner. */ YAHOO.widget.Tooltip.prototype.configText = function(type, args, obj) { var text = args[0]; if (text) { this.setBody(text); } }; /** * The default event handler fired when the "container" property is changed. * @method configContainer * @param {String} type The CustomEvent type (usually the property name) * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner. */ YAHOO.widget.Tooltip.prototype.configContainer = function(type, args, obj) { var container = args[0]; if (typeof container == 'string') { this.cfg.setProperty("container", document.getElementById(container), true); } }; /** * The default event handler fired when the "context" property is changed. * @method configContext * @param {String} type The CustomEvent type (usually the property name) * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property. * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner. */ YAHOO.widget.Tooltip.prototype.configContext = function(type, args, obj) { var context = args[0]; if (context) { // Normalize parameter into an array if (! (context instanceof Array)) { if (typeof context == "string") { this.cfg.setProperty("context", [document.getElementById(context)], true); } else { // Assuming this is an element this.cfg.setProperty("context", [context], true); } context = this.cfg.getProperty("context"); } // Remove any existing mouseover/mouseout listeners if (this._context) { for (var c=0;cOR * @param {HTMLElement} el The element representing the Panel * @param {Object} userConfig The configuration object literal containing the configuration that should be set for this Panel. See configuration documentation for more details. */ YAHOO.widget.Panel = function(el, userConfig) { YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig); }; YAHOO.extend(YAHOO.widget.Panel, YAHOO.widget.Overlay); /** * Constant representing the default CSS class used for a Panel * @property YAHOO.widget.Panel.CSS_PANEL * @static * @final * @type String */ YAHOO.widget.Panel.CSS_PANEL = "panel"; /** * Constant representing the default CSS class used for a Panel's wrapping container * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER * @static * @final * @type String */ YAHOO.widget.Panel.CSS_PANEL_CONTAINER = "panel-container"; /** * The Overlay initialization method, which is executed for Overlay and all of its subclasses. This method is automatically called by the constructor, and sets up all DOM references for pre-existing markup, and creates required markup if it is not already present. * @method init * @param {String} el The element ID representing the Overlay OR * @param {HTMLElement} el The element representing the Overlay * @param {Object} userConfig The configuration object literal containing the configuration that should be set for this Overlay. See configuration documentation for more details. */ YAHOO.widget.Panel.prototype.init = function(el, userConfig) { YAHOO.widget.Panel.superclass.init.call(this, el/*, userConfig*/); // Note that we don't pass the user config in here yet because we only want it executed once, at the lowest subclass level this.beforeInitEvent.fire(YAHOO.widget.Panel); YAHOO.util.Dom.addClass(this.element, YAHOO.widget.Panel.CSS_PANEL); this.buildWrapper(); if (userConfig) { this.cfg.applyConfig(userConfig, true); } this.beforeRenderEvent.subscribe(function() { var draggable = this.cfg.getProperty("draggable"); if (draggable) { if (! this.header) { this.setHeader(" "); } } }, this, true); var me = this; var doBlur = function() { this.blur(); }; this.showMaskEvent.subscribe(function() { var checkFocusable = function(el) { if ((el.tagName == "A" || el.tagName == "BUTTON" || el.tagName == "SELECT" || el.tagName == "INPUT" || el.tagName == "TEXTAREA" || el.tagName == "FORM") && el.type != "hidden") { if (! YAHOO.util.Dom.isAncestor(me.element, el)) { YAHOO.util.Event.addListener(el, "focus", doBlur, el, true); return true; } } else { return false; } }; this.focusableElements = YAHOO.util.Dom.getElementsBy(checkFocusable); }, this, true); this.hideMaskEvent.subscribe(function() { for (var i=0;i