/* YUI 3.5.1 (build 22) Copyright 2012 Yahoo! Inc. All rights reserved. Licensed under the BSD License. http://yuilibrary.com/license/ */ YUI.add('widget-stdmod', function(Y) { /** * Provides standard module support for Widgets through an extension. * * @module widget-stdmod */ var L = Y.Lang, Node = Y.Node, UA = Y.UA, Widget = Y.Widget, EMPTY = "", HD = "hd", BD = "bd", FT = "ft", HEADER = "header", BODY = "body", FOOTER = "footer", FILL_HEIGHT = "fillHeight", STDMOD = "stdmod", NODE_SUFFIX = "Node", CONTENT_SUFFIX = "Content", FIRST_CHILD = "firstChild", CHILD_NODES = "childNodes", OWNER_DOCUMENT = "ownerDocument", CONTENT_BOX = "contentBox", HEIGHT = "height", OFFSET_HEIGHT = "offsetHeight", AUTO = "auto", HeaderChange = "headerContentChange", BodyChange = "bodyContentChange", FooterChange = "footerContentChange", FillHeightChange = "fillHeightChange", HeightChange = "heightChange", ContentUpdate = "contentUpdate", RENDERUI = "renderUI", BINDUI = "bindUI", SYNCUI = "syncUI", APPLY_PARSED_CONFIG = "_applyParsedConfig", UI = Y.Widget.UI_SRC; /** * Widget extension, which can be used to add Standard Module support to the * base Widget class, through the Base.build * method. *

* The extension adds header, body and footer sections to the Widget's content box and * provides the corresponding methods and attributes to modify the contents of these sections. *

* @class WidgetStdMod * @param {Object} The user configuration object */ function StdMod(config) { this._stdModNode = this.get(CONTENT_BOX); Y.before(this._renderUIStdMod, this, RENDERUI); Y.before(this._bindUIStdMod, this, BINDUI); Y.before(this._syncUIStdMod, this, SYNCUI); } /** * Constant used to refer the the standard module header, in methods which expect a section specifier * * @property HEADER * @static * @type String */ StdMod.HEADER = HEADER; /** * Constant used to refer the the standard module body, in methods which expect a section specifier * * @property BODY * @static * @type String */ StdMod.BODY = BODY; /** * Constant used to refer the the standard module footer, in methods which expect a section specifier * * @property FOOTER * @static * @type String */ StdMod.FOOTER = FOOTER; /** * Constant used to specify insertion position, when adding content to sections of the standard module in * methods which expect a "where" argument. *

* Inserts new content before the sections existing content. *

* @property AFTER * @static * @type String */ StdMod.AFTER = "after"; /** * Constant used to specify insertion position, when adding content to sections of the standard module in * methods which expect a "where" argument. *

* Inserts new content before the sections existing content. *

* @property BEFORE * @static * @type String */ StdMod.BEFORE = "before"; /** * Constant used to specify insertion position, when adding content to sections of the standard module in * methods which expect a "where" argument. *

* Replaces the sections existing content, with new content. *

* @property REPLACE * @static * @type String */ StdMod.REPLACE = "replace"; var STD_HEADER = StdMod.HEADER, STD_BODY = StdMod.BODY, STD_FOOTER = StdMod.FOOTER, HEADER_CONTENT = STD_HEADER + CONTENT_SUFFIX, FOOTER_CONTENT = STD_FOOTER + CONTENT_SUFFIX, BODY_CONTENT = STD_BODY + CONTENT_SUFFIX; /** * Static property used to define the default attribute * configuration introduced by WidgetStdMod. * * @property ATTRS * @type Object * @static */ StdMod.ATTRS = { /** * @attribute headerContent * @type HTML * @default undefined * @description The content to be added to the header section. This will replace any existing content * in the header. If you want to append, or insert new content, use the setStdModContent method. */ headerContent: { value:null }, /** * @attribute footerContent * @type HTML * @default undefined * @description The content to be added to the footer section. This will replace any existing content * in the footer. If you want to append, or insert new content, use the setStdModContent method. */ footerContent: { value:null }, /** * @attribute bodyContent * @type HTML * @default undefined * @description The content to be added to the body section. This will replace any existing content * in the body. If you want to append, or insert new content, use the setStdModContent method. */ bodyContent: { value:null }, /** * @attribute fillHeight * @type {String} * @default WidgetStdMod.BODY * @description The section (WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER) which should be resized to fill the height of the standard module, when a * height is set on the Widget. If a height is not set on the widget, then all sections are sized based on * their content. */ fillHeight: { value: StdMod.BODY, validator: function(val) { return this._validateFillHeight(val); } } }; /** * The HTML parsing rules for the WidgetStdMod class. * * @property HTML_PARSER * @static * @type Object */ StdMod.HTML_PARSER = { headerContent: function(contentBox) { return this._parseStdModHTML(STD_HEADER); }, bodyContent: function(contentBox) { return this._parseStdModHTML(STD_BODY); }, footerContent : function(contentBox) { return this._parseStdModHTML(STD_FOOTER); } }; /** * Static hash of default class names used for the header, * body and footer sections of the standard module, keyed by * the section identifier (WidgetStdMod.STD_HEADER, WidgetStdMod.STD_BODY, WidgetStdMod.STD_FOOTER) * * @property SECTION_CLASS_NAMES * @static * @type Object */ StdMod.SECTION_CLASS_NAMES = { header: Widget.getClassName(HD), body: Widget.getClassName(BD), footer: Widget.getClassName(FT) }; /** * The template HTML strings for each of the standard module sections. Section entries are keyed by the section constants, * WidgetStdMod.HEADER, WidgetStdMod.BODY, WidgetStdMod.FOOTER, and contain the HTML to be added for each section. * e.g. *
     *    {
     *       header : '<div class="yui-widget-hd"></div>',
     *       body : '<div class="yui-widget-bd"></div>',
     *       footer : '<div class="yui-widget-ft"></div>'
     *    }
     * 
* @property TEMPLATES * @type Object * @static */ StdMod.TEMPLATES = { header : '
', body : '
', footer : '
' }; StdMod.prototype = { /** * Synchronizes the UI to match the Widgets standard module state. *

* This method is invoked after syncUI is invoked for the Widget class * using YUI's aop infrastructure. *

* @method _syncUIStdMod * @protected */ _syncUIStdMod : function() { var stdModParsed = this._stdModParsed; if (!stdModParsed || !stdModParsed[HEADER_CONTENT]) { this._uiSetStdMod(STD_HEADER, this.get(HEADER_CONTENT)); } if (!stdModParsed || !stdModParsed[BODY_CONTENT]) { this._uiSetStdMod(STD_BODY, this.get(BODY_CONTENT)); } if (!stdModParsed || !stdModParsed[FOOTER_CONTENT]) { this._uiSetStdMod(STD_FOOTER, this.get(FOOTER_CONTENT)); } this._uiSetFillHeight(this.get(FILL_HEIGHT)); }, /** * Creates/Initializes the DOM for standard module support. *

* This method is invoked after renderUI is invoked for the Widget class * using YUI's aop infrastructure. *

* @method _renderUIStdMod * @protected */ _renderUIStdMod : function() { this._stdModNode.addClass(Widget.getClassName(STDMOD)); this._renderStdModSections(); //This normally goes in bindUI but in order to allow setStdModContent() to work before renderUI //stage, these listeners should be set up at the earliest possible time. this.after(HeaderChange, this._afterHeaderChange); this.after(BodyChange, this._afterBodyChange); this.after(FooterChange, this._afterFooterChange); }, _renderStdModSections : function() { if (L.isValue(this.get(HEADER_CONTENT))) { this._renderStdMod(STD_HEADER); } if (L.isValue(this.get(BODY_CONTENT))) { this._renderStdMod(STD_BODY); } if (L.isValue(this.get(FOOTER_CONTENT))) { this._renderStdMod(STD_FOOTER); } }, /** * Binds event listeners responsible for updating the UI state in response to * Widget standard module related state changes. *

* This method is invoked after bindUI is invoked for the Widget class * using YUI's aop infrastructure. *

* @method _bindUIStdMod * @protected */ _bindUIStdMod : function() { // this.after(HeaderChange, this._afterHeaderChange); // this.after(BodyChange, this._afterBodyChange); // this.after(FooterChange, this._afterFooterChange); this.after(FillHeightChange, this._afterFillHeightChange); this.after(HeightChange, this._fillHeight); this.after(ContentUpdate, this._fillHeight); }, /** * Default attribute change listener for the headerContent attribute, responsible * for updating the UI, in response to attribute changes. * * @method _afterHeaderChange * @protected * @param {EventFacade} e The event facade for the attribute change */ _afterHeaderChange : function(e) { if (e.src !== UI) { this._uiSetStdMod(STD_HEADER, e.newVal, e.stdModPosition); } }, /** * Default attribute change listener for the bodyContent attribute, responsible * for updating the UI, in response to attribute changes. * * @method _afterBodyChange * @protected * @param {EventFacade} e The event facade for the attribute change */ _afterBodyChange : function(e) { if (e.src !== UI) { this._uiSetStdMod(STD_BODY, e.newVal, e.stdModPosition); } }, /** * Default attribute change listener for the footerContent attribute, responsible * for updating the UI, in response to attribute changes. * * @method _afterFooterChange * @protected * @param {EventFacade} e The event facade for the attribute change */ _afterFooterChange : function(e) { if (e.src !== UI) { this._uiSetStdMod(STD_FOOTER, e.newVal, e.stdModPosition); } }, /** * Default attribute change listener for the fillHeight attribute, responsible * for updating the UI, in response to attribute changes. * * @method _afterFillHeightChange * @protected * @param {EventFacade} e The event facade for the attribute change */ _afterFillHeightChange: function (e) { this._uiSetFillHeight(e.newVal); }, /** * Default validator for the fillHeight attribute. Verifies that the * value set is a valid section specifier - one of WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER, * or a falsey value if fillHeight is to be disabled. * * @method _validateFillHeight * @protected * @param {String} val The section which should be setup to fill height, or false/null to disable fillHeight * @return true if valid, false if not */ _validateFillHeight : function(val) { return !val || val == StdMod.BODY || val == StdMod.HEADER || val == StdMod.FOOTER; }, /** * Updates the rendered UI, to resize the provided section so that the standard module fills out * the specified widget height. Note: This method does not check whether or not a height is set * on the Widget. * * @method _uiSetFillHeight * @protected * @param {String} fillSection A valid section specifier - one of WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER */ _uiSetFillHeight : function(fillSection) { var fillNode = this.getStdModNode(fillSection); var currNode = this._currFillNode; if (currNode && fillNode !== currNode){ currNode.setStyle(HEIGHT, EMPTY); } if (fillNode) { this._currFillNode = fillNode; } this._fillHeight(); }, /** * Updates the rendered UI, to resize the current section specified by the fillHeight attribute, so * that the standard module fills out the Widget height. If a height has not been set on Widget, * the section is not resized (height is set to "auto"). * * @method _fillHeight * @private */ _fillHeight : function() { if (this.get(FILL_HEIGHT)) { var height = this.get(HEIGHT); if (height != EMPTY && height != AUTO) { this.fillHeight(this._currFillNode); } } }, /** * Updates the rendered UI, adding the provided content (either an HTML string, or node reference), * to the specified section. The content is either added before, after or replaces existing content * in the section, based on the value of the where argument. * * @method _uiSetStdMod * @protected * * @param {String} section The section to be updated. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. * @param {String | Node} content The new content (either as an HTML string, or Node reference) to add to the section * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE. * If not provided, the content will replace existing content in the section. */ _uiSetStdMod : function(section, content, where) { // Using isValue, so that "" is valid content if (L.isValue(content)) { var node = this.getStdModNode(section, true); this._addStdModContent(node, content, where); this.set(section + CONTENT_SUFFIX, this._getStdModContent(section), {src:UI}); } else { this._eraseStdMod(section); } this.fire(ContentUpdate); }, /** * Creates the DOM node for the given section, and inserts it into the correct location in the contentBox. * * @method _renderStdMod * @protected * @param {String} section The section to create/render. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. * @return {Node} A reference to the added section node */ _renderStdMod : function(section) { var contentBox = this.get(CONTENT_BOX), sectionNode = this._findStdModSection(section); if (!sectionNode) { sectionNode = this._getStdModTemplate(section); } this._insertStdModSection(contentBox, section, sectionNode); this[section + NODE_SUFFIX] = sectionNode; return this[section + NODE_SUFFIX]; }, /** * Removes the DOM node for the given section. * * @method _eraseStdMod * @protected * @param {String} section The section to remove. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. */ _eraseStdMod : function(section) { var sectionNode = this.getStdModNode(section); if (sectionNode) { sectionNode.remove(true); delete this[section + NODE_SUFFIX]; } }, /** * Helper method to insert the Node for the given section into the correct location in the contentBox. * * @method _insertStdModSection * @private * @param {Node} contentBox A reference to the Widgets content box. * @param {String} section The section to create/render. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. * @param {Node} sectionNode The Node for the section. */ _insertStdModSection : function(contentBox, section, sectionNode) { var fc = contentBox.get(FIRST_CHILD); if (section === STD_FOOTER || !fc) { contentBox.appendChild(sectionNode); } else { if (section === STD_HEADER) { contentBox.insertBefore(sectionNode, fc); } else { var footer = this[STD_FOOTER + NODE_SUFFIX]; if (footer) { contentBox.insertBefore(sectionNode, footer); } else { contentBox.appendChild(sectionNode); } } } }, /** * Gets a new Node reference for the given standard module section, by cloning * the stored template node. * * @method _getStdModTemplate * @protected * @param {String} section The section to create a new node for. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. * @return {Node} The new Node instance for the section */ _getStdModTemplate : function(section) { return Node.create(StdMod.TEMPLATES[section], this._stdModNode.get(OWNER_DOCUMENT)); }, /** * Helper method to add content to a StdMod section node. * The content is added either before, after or replaces the existing node content * based on the value of the where argument. * * @method _addStdModContent * @private * * @param {Node} node The section Node to be updated. * @param {Node|NodeList|String} children The new content Node, NodeList or String to be added to section Node provided. * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE. * If not provided, the content will replace existing content in the Node. */ _addStdModContent : function(node, children, where) { // StdMod where to Node where switch (where) { case StdMod.BEFORE: // 0 is before fistChild where = 0; break; case StdMod.AFTER: // undefined is appendChild where = undefined; break; default: // replace is replace, not specified is replace where = StdMod.REPLACE; } node.insert(children, where); }, /** * Helper method to obtain the precise height of the node provided, including padding and border. * The height could be a sub-pixel value for certain browsers, such as Firefox 3. * * @method _getPreciseHeight * @private * @param {Node} node The node for which the precise height is required. * @return {Number} The height of the Node including borders and padding, possibly a float. */ _getPreciseHeight : function(node) { var height = (node) ? node.get(OFFSET_HEIGHT) : 0, getBCR = "getBoundingClientRect"; if (node && node.hasMethod(getBCR)) { var preciseRegion = node.invoke(getBCR); if (preciseRegion) { height = preciseRegion.bottom - preciseRegion.top; } } return height; }, /** * Helper method to to find the rendered node for the given section, * if it exists. * * @method _findStdModSection * @private * @param {String} section The section for which the render Node is to be found. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. * @return {Node} The rendered node for the given section, or null if not found. */ _findStdModSection: function(section) { return this.get(CONTENT_BOX).one("> ." + StdMod.SECTION_CLASS_NAMES[section]); }, /** * Utility method, used by WidgetStdMods HTML_PARSER implementation * to extract data for each section from markup. * * @method _parseStdModHTML * @private * @param {String} section * @return {String} Inner HTML string with the contents of the section */ _parseStdModHTML : function(section) { var node = this._findStdModSection(section); if (node) { if (!this._stdModParsed) { this._stdModParsed = {}; Y.before(this._applyStdModParsedConfig, this, APPLY_PARSED_CONFIG); } this._stdModParsed[section + CONTENT_SUFFIX] = 1; return node.get("innerHTML"); } return null; }, /** * This method is injected before the _applyParsedConfig step in * the application of HTML_PARSER, and sets up the state to * identify whether or not we should remove the current DOM content * or not, based on whether or not the current content attribute value * was extracted from the DOM, or provided by the user configuration * * @method _applyStdModParsedConfig * @private */ _applyStdModParsedConfig : function(node, cfg, parsedCfg) { var parsed = this._stdModParsed; if (parsed) { parsed[HEADER_CONTENT] = !(HEADER_CONTENT in cfg) && (HEADER_CONTENT in parsed); parsed[BODY_CONTENT] = !(BODY_CONTENT in cfg) && (BODY_CONTENT in parsed); parsed[FOOTER_CONTENT] = !(FOOTER_CONTENT in cfg) && (FOOTER_CONTENT in parsed); } }, /** * Retrieves the child nodes (content) of a standard module section * * @method _getStdModContent * @private * @param {String} section The standard module section whose child nodes are to be retrieved. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. * @return {Node} The child node collection of the standard module section. */ _getStdModContent : function(section) { return (this[section + NODE_SUFFIX]) ? this[section + NODE_SUFFIX].get(CHILD_NODES) : null; }, /** * Updates the body section of the standard module with the content provided (either an HTML string, or node reference). *

* This method can be used instead of the corresponding section content attribute if you'd like to retain the current content of the section, * and insert content before or after it, by specifying the where argument. *

* @method setStdModContent * @param {String} section The standard module section whose content is to be updated. Either WidgetStdMod.HEADER, WidgetStdMod.BODY or WidgetStdMod.FOOTER. * @param {String | Node} content The content to be added, either an HTML string or a Node reference. * @param {String} where Optional. Either WidgetStdMod.AFTER, WidgetStdMod.BEFORE or WidgetStdMod.REPLACE. * If not provided, the content will replace existing content in the section. */ setStdModContent : function(section, content, where) { //var node = this.getStdModNode(section) || this._renderStdMod(section); this.set(section + CONTENT_SUFFIX, content, {stdModPosition:where}); //this._addStdModContent(node, content, where); }, /** Returns the node reference for the specified `section`. **Note:** The DOM is not queried for the node reference. The reference stored by the widget instance is returned if it was set. Passing a truthy for `forceCreate` will create the section node if it does not already exist. @method getStdModNode @param {String} section The section whose node reference is required. Either `WidgetStdMod.HEADER`, `WidgetStdMod.BODY`, or `WidgetStdMod.FOOTER`. @param {Boolean} forceCreate Whether the section node should be created if it does not already exist. @return {Node} The node reference for the `section`, or null if not set. **/ getStdModNode : function(section, forceCreate) { var node = this[section + NODE_SUFFIX] || null; if (!node && forceCreate) { node = this._renderStdMod(section); } return node; }, /** * Sets the height on the provided header, body or footer element to * fill out the height of the Widget. It determines the height of the * widgets bounding box, based on it's configured height value, and * sets the height of the provided section to fill out any * space remaining after the other standard module section heights * have been accounted for. * *

NOTE: This method is not designed to work if an explicit * height has not been set on the Widget, since for an "auto" height Widget, * the heights of the header/body/footer will drive the height of the Widget.

* * @method fillHeight * @param {Node} node The node which should be resized to fill out the height * of the Widget bounding box. Should be a standard module section node which belongs * to the widget. */ fillHeight : function(node) { if (node) { var contentBox = this.get(CONTENT_BOX), stdModNodes = [this.headerNode, this.bodyNode, this.footerNode], stdModNode, cbContentHeight, filled = 0, remaining = 0, validNode = false; for (var i = 0, l = stdModNodes.length; i < l; i++) { stdModNode = stdModNodes[i]; if (stdModNode) { if (stdModNode !== node) { filled += this._getPreciseHeight(stdModNode); } else { validNode = true; } } } if (validNode) { if (UA.ie || UA.opera) { // Need to set height to 0, to allow height to be reduced node.set(OFFSET_HEIGHT, 0); } cbContentHeight = contentBox.get(OFFSET_HEIGHT) - parseInt(contentBox.getComputedStyle("paddingTop"), 10) - parseInt(contentBox.getComputedStyle("paddingBottom"), 10) - parseInt(contentBox.getComputedStyle("borderBottomWidth"), 10) - parseInt(contentBox.getComputedStyle("borderTopWidth"), 10); if (L.isNumber(cbContentHeight)) { remaining = cbContentHeight - filled; if (remaining >= 0) { node.set(OFFSET_HEIGHT, remaining); } } } } } }; Y.WidgetStdMod = StdMod; }, '3.5.1' ,{requires:['base-build', 'widget']}); /* YUI 3.5.1 (build 22) Copyright 2012 Yahoo! Inc. All rights reserved. Licensed under the BSD License. http://yuilibrary.com/license/ */ YUI.add('widget-position', function(Y) { /** * Provides basic XY positioning support for Widgets, though an extension * * @module widget-position */ var Lang = Y.Lang, Widget = Y.Widget, XY_COORD = "xy", POSITION = "position", POSITIONED = "positioned", BOUNDING_BOX = "boundingBox", RELATIVE = "relative", RENDERUI = "renderUI", BINDUI = "bindUI", SYNCUI = "syncUI", UI = Widget.UI_SRC, XYChange = "xyChange"; /** * Widget extension, which can be used to add positioning support to the base Widget class, * through the Base.build method. * * @class WidgetPosition * @param {Object} config User configuration object */ function Position(config) { this._posNode = this.get(BOUNDING_BOX); // WIDGET METHOD OVERLAP Y.after(this._renderUIPosition, this, RENDERUI); Y.after(this._syncUIPosition, this, SYNCUI); Y.after(this._bindUIPosition, this, BINDUI); } /** * Static property used to define the default attribute * configuration introduced by WidgetPosition. * * @property ATTRS * @static * @type Object */ Position.ATTRS = { /** * @attribute x * @type number * @default 0 * * @description Page X co-ordinate for the widget. This attribute acts as a facade for the * xy attribute. Changes in position can be monitored by listening for xyChange events. */ x: { setter: function(val) { this._setX(val); }, getter: function() { return this._getX(); }, lazyAdd:false }, /** * @attribute y * @type number * @default 0 * * @description Page Y co-ordinate for the widget. This attribute acts as a facade for the * xy attribute. Changes in position can be monitored by listening for xyChange events. */ y: { setter: function(val) { this._setY(val); }, getter: function() { return this._getY(); }, lazyAdd: false }, /** * @attribute xy * @type Array * @default [0,0] * * @description Page XY co-ordinate pair for the widget. */ xy: { value:[0,0], validator: function(val) { return this._validateXY(val); } } }; /** * Default class used to mark the boundingBox of a positioned widget. * * @property POSITIONED_CLASS_NAME * @type String * @default "yui-widget-positioned" * @static */ Position.POSITIONED_CLASS_NAME = Widget.getClassName(POSITIONED); Position.prototype = { /** * Creates/Initializes the DOM to support xy page positioning. *

* This method in invoked after renderUI is invoked for the Widget class * using YUI's aop infrastructure. *

* @method _renderUIPosition * @protected */ _renderUIPosition : function() { this._posNode.addClass(Position.POSITIONED_CLASS_NAME); }, /** * Synchronizes the UI to match the Widgets xy page position state. *

* This method in invoked after syncUI is invoked for the Widget class * using YUI's aop infrastructure. *

* @method _syncUIPosition * @protected */ _syncUIPosition : function() { var posNode = this._posNode; if (posNode.getStyle(POSITION) === RELATIVE) { this.syncXY(); } this._uiSetXY(this.get(XY_COORD)); }, /** * Binds event listeners responsible for updating the UI state in response to * Widget position related state changes. *

* This method in invoked after bindUI is invoked for the Widget class * using YUI's aop infrastructure. *

* @method _bindUIPosition * @protected */ _bindUIPosition :function() { this.after(XYChange, this._afterXYChange); }, /** * Moves the Widget to the specified page xy co-ordinate position. * * @method move * * @param {Number} x The new x position * @param {Number} y The new y position *

Or

* @param {Array} x, y values passed as an array ([x, y]), to support * simple pass through of Node.getXY results */ move: function () { var args = arguments, coord = (Lang.isArray(args[0])) ? args[0] : [args[0], args[1]]; this.set(XY_COORD, coord); }, /** * Synchronizes the Panel's "xy", "x", and "y" properties with the * Widget's position in the DOM. * * @method syncXY */ syncXY : function () { this.set(XY_COORD, this._posNode.getXY(), {src: UI}); }, /** * Default validator for the XY attribute * * @method _validateXY * @protected * @param {Array} val The XY page co-ordinate value which is being set. * @return {boolean} true if valid, false if not. */ _validateXY : function(val) { return (Lang.isArray(val) && Lang.isNumber(val[0]) && Lang.isNumber(val[1])); }, /** * Default setter for the X attribute. The setter passes the X value through * to the XY attribute, which is the sole store for the XY state. * * @method _setX * @protected * @param {Number} val The X page co-ordinate value */ _setX : function(val) { this.set(XY_COORD, [val, this.get(XY_COORD)[1]]); }, /** * Default setter for the Y attribute. The setter passes the Y value through * to the XY attribute, which is the sole store for the XY state. * * @method _setY * @protected * @param {Number} val The Y page co-ordinate value */ _setY : function(val) { this.set(XY_COORD, [this.get(XY_COORD)[0], val]); }, /** * Default getter for the X attribute. The value is retrieved from * the XY attribute, which is the sole store for the XY state. * * @method _getX * @protected * @return {Number} The X page co-ordinate value */ _getX : function() { return this.get(XY_COORD)[0]; }, /** * Default getter for the Y attribute. The value is retrieved from * the XY attribute, which is the sole store for the XY state. * * @method _getY * @protected * @return {Number} The Y page co-ordinate value */ _getY : function() { return this.get(XY_COORD)[1]; }, /** * Default attribute change listener for the xy attribute, responsible * for updating the UI, in response to attribute changes. * * @method _afterXYChange * @protected * @param {EventFacade} e The event facade for the attribute change */ _afterXYChange : function(e) { if (e.src != UI) { this._uiSetXY(e.newVal); } }, /** * Updates the UI to reflect the XY page co-ordinates passed in. * * @method _uiSetXY * @protected * @param {String} val The XY page co-ordinates value to be reflected in the UI */ _uiSetXY : function(val) { this._posNode.setXY(val); } }; Y.WidgetPosition = Position; }, '3.5.1' ,{requires:['base-build', 'node-screen', 'widget']}); /* YUI 3.5.1 (build 22) Copyright 2012 Yahoo! Inc. All rights reserved. Licensed under the BSD License. http://yuilibrary.com/license/ */ YUI.add('widget-position-align', function(Y) { /** Provides extended/advanced XY positioning support for Widgets, through an extension. It builds on top of the `widget-position` module, to provide alignment and centering support. Future releases aim to add constrained and fixed positioning support. @module widget-position-align **/ var Lang = Y.Lang, ALIGN = 'align', ALIGN_ON = 'alignOn', VISIBLE = 'visible', BOUNDING_BOX = 'boundingBox', OFFSET_WIDTH = 'offsetWidth', OFFSET_HEIGHT = 'offsetHeight', REGION = 'region', VIEWPORT_REGION = 'viewportRegion'; /** Widget extension, which can be used to add extended XY positioning support to the base Widget class, through the `Base.create` method. **Note:** This extension requires that the `WidgetPosition` extension be added to the Widget (before `WidgetPositionAlign`, if part of the same extension list passed to `Base.build`). @class WidgetPositionAlign @param {Object} config User configuration object. @constructor **/ function PositionAlign (config) { if ( ! this._posNode) { Y.error('WidgetPosition needs to be added to the Widget, ' + 'before WidgetPositionAlign is added'); } Y.after(this._bindUIPosAlign, this, 'bindUI'); Y.after(this._syncUIPosAlign, this, 'syncUI'); } PositionAlign.ATTRS = { /** The alignment configuration for this widget. The `align` attribute is used to align a reference point on the widget, with the reference point on another `Node`, or the viewport. The object which `align` expects has the following properties: * __`node`__: The `Node` to which the widget is to be aligned. If set to `null`, or not provided, the widget is aligned to the viewport. * __`points`__: A two element Array, defining the two points on the widget and `Node`/viewport which are to be aligned. The first element is the point on the widget, and the second element is the point on the `Node`/viewport. Supported alignment points are defined as static properties on `WidgetPositionAlign`. @example Aligns the top-right corner of the widget with the top-left corner of the viewport: myWidget.set('align', { points: [Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.TL] }); @attribute align @type Object @default null **/ align: { value: null }, /** A convenience Attribute, which can be used as a shortcut for the `align` Attribute. If set to `true`, the widget is centered in the viewport. If set to a `Node` reference or valid selector String, the widget will be centered within the `Node`. If set to `false`, no center positioning is applied. @attribute centered @type Boolean|Node @default false **/ centered: { setter : '_setAlignCenter', lazyAdd:false, value :false }, /** An Array of Objects corresponding to the `Node`s and events that will cause the alignment of this widget to be synced to the DOM. The `alignOn` Attribute is expected to be an Array of Objects with the following properties: * __`eventName`__: The String event name to listen for. * __`node`__: The optional `Node` that will fire the event, it can be a `Node` reference or a selector String. This will default to the widget's `boundingBox`. @example Sync this widget's alignment on window resize: myWidget.set('alignOn', [ { node : Y.one('win'), eventName: 'resize' } ]); @attribute alignOn @type Array @default [] **/ alignOn: { value : [], validator: Y.Lang.isArray } }; /** Constant used to specify the top-left corner for alignment @property TL @type String @value 'tl' @static **/ PositionAlign.TL = 'tl'; /** Constant used to specify the top-right corner for alignment @property TR @type String @value 'tr' @static **/ PositionAlign.TR = 'tr'; /** Constant used to specify the bottom-left corner for alignment @property BL @type String @value 'bl' @static **/ PositionAlign.BL = 'bl'; /** Constant used to specify the bottom-right corner for alignment @property BR @type String @value 'br' @static **/ PositionAlign.BR = 'br'; /** Constant used to specify the top edge-center point for alignment @property TC @type String @value 'tc' @static **/ PositionAlign.TC = 'tc'; /** Constant used to specify the right edge, center point for alignment @property RC @type String @value 'rc' @static **/ PositionAlign.RC = 'rc'; /** Constant used to specify the bottom edge, center point for alignment @property BC @type String @value 'bc' @static **/ PositionAlign.BC = 'bc'; /** Constant used to specify the left edge, center point for alignment @property LC @type String @value 'lc' @static **/ PositionAlign.LC = 'lc'; /** Constant used to specify the center of widget/node/viewport for alignment @property CC @type String @value 'cc' @static */ PositionAlign.CC = 'cc'; PositionAlign.prototype = { // -- Protected Properties ------------------------------------------------- /** Holds the alignment-syncing event handles. @property _posAlignUIHandles @type Array @default null @protected **/ _posAlignUIHandles: null, // -- Lifecycle Methods ---------------------------------------------------- destructor: function () { this._detachPosAlignUIHandles(); }, /** Bind event listeners responsible for updating the UI state in response to the widget's position-align related state changes. This method is invoked after `bindUI` has been invoked for the `Widget` class using the AOP infrastructure. @method _bindUIPosAlign @protected **/ _bindUIPosAlign: function () { this.after('alignChange', this._afterAlignChange); this.after('alignOnChange', this._afterAlignOnChange); this.after('visibleChange', this._syncUIPosAlign); }, /** Synchronizes the current `align` Attribute value to the DOM. This method is invoked after `syncUI` has been invoked for the `Widget` class using the AOP infrastructure. @method _syncUIPosAlign @protected **/ _syncUIPosAlign: function () { var align = this.get(ALIGN); this._uiSetVisiblePosAlign(this.get(VISIBLE)); if (align) { this._uiSetAlign(align.node, align.points); } }, // -- Public Methods ------------------------------------------------------- /** Aligns this widget to the provided `Node` (or viewport) using the provided points. This method can be invoked with no arguments which will cause the widget's current `align` Attribute value to be synced to the DOM. @example Aligning to the top-left corner of the ``: myWidget.align('body', [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.TR]); @method align @param {Node|String|null} [node] A reference (or selector String) for the `Node` which with the widget is to be aligned. If null is passed in, the widget will be aligned with the viewport. @param {Array[2]} [points] A two item array specifying the points on the widget and `Node`/viewport which will to be aligned. The first entry is the point on the widget, and the second entry is the point on the `Node`/viewport. Valid point references are defined as static constants on the `WidgetPositionAlign` extension. @chainable **/ align: function (node, points) { if (arguments.length) { // Set the `align` Attribute. this.set(ALIGN, { node : node, points: points }); } else { // Sync the current `align` Attribute value to the DOM. this._syncUIPosAlign(); } return this; }, /** Centers the widget in the viewport, or if a `Node` is passed in, it will be centered to that `Node`. @method centered @param {Node|String} [node] A `Node` reference or selector String defining the `Node` which the widget should be centered. If a `Node` is not passed in, then the widget will be centered to the viewport. @chainable **/ centered: function (node) { return this.align(node, [PositionAlign.CC, PositionAlign.CC]); }, // -- Protected Methods ---------------------------------------------------- /** Default setter for `center` Attribute changes. Sets up the appropriate value, and passes it through the to the align attribute. @method _setAlignCenter @param {Boolean|Node} val The Attribute value being set. @return {Boolean|Node} the value passed in. @protected **/ _setAlignCenter: function (val) { if (val) { this.set(ALIGN, { node : val === true ? null : val, points: [PositionAlign.CC, PositionAlign.CC] }); } return val; }, /** Updates the UI to reflect the `align` value passed in. **Note:** See the `align` Attribute documentation, for the Object structure expected. @method _uiSetAlign @param {Node|String|null} [node] The node to align to, or null to indicate the viewport. @param {Array} points The alignment points. @protected **/ _uiSetAlign: function (node, points) { if ( ! Lang.isArray(points) || points.length !== 2) { Y.error('align: Invalid Points Arguments'); return; } var nodeRegion = this._getRegion(node), widgetPoint, nodePoint, xy; if ( ! nodeRegion) { // No-op, nothing to align to. return; } widgetPoint = points[0]; nodePoint = points[1]; // TODO: Optimize KWeight - Would lookup table help? switch (nodePoint) { case PositionAlign.TL: xy = [nodeRegion.left, nodeRegion.top]; break; case PositionAlign.TR: xy = [nodeRegion.right, nodeRegion.top]; break; case PositionAlign.BL: xy = [nodeRegion.left, nodeRegion.bottom]; break; case PositionAlign.BR: xy = [nodeRegion.right, nodeRegion.bottom]; break; case PositionAlign.TC: xy = [ nodeRegion.left + Math.floor(nodeRegion.width / 2), nodeRegion.top ]; break; case PositionAlign.BC: xy = [ nodeRegion.left + Math.floor(nodeRegion.width / 2), nodeRegion.bottom ]; break; case PositionAlign.LC: xy = [ nodeRegion.left, nodeRegion.top + Math.floor(nodeRegion.height / 2) ]; break; case PositionAlign.RC: xy = [ nodeRegion.right, nodeRegion.top + Math.floor(nodeRegion.height / 2) ]; break; case PositionAlign.CC: xy = [ nodeRegion.left + Math.floor(nodeRegion.width / 2), nodeRegion.top + Math.floor(nodeRegion.height / 2) ]; break; default: break; } if (xy) { this._doAlign(widgetPoint, xy[0], xy[1]); } }, /** Attaches or detaches alignment-syncing event handlers based on the widget's `visible` Attribute state. @method _uiSetVisiblePosAlign @param {Boolean} visible The current value of the widget's `visible` Attribute. @protected **/ _uiSetVisiblePosAlign: function (visible) { if (visible) { this._attachPosAlignUIHandles(); } else { this._detachPosAlignUIHandles(); } }, /** Attaches the alignment-syncing event handlers. @method _attachPosAlignUIHandles @protected **/ _attachPosAlignUIHandles: function () { if (this._posAlignUIHandles) { // No-op if we have already setup the event handlers. return; } var bb = this.get(BOUNDING_BOX), syncAlign = Y.bind(this._syncUIPosAlign, this), handles = []; Y.Array.each(this.get(ALIGN_ON), function (o) { var event = o.eventName, node = Y.one(o.node) || bb; if (event) { handles.push(node.on(event, syncAlign)); } }); this._posAlignUIHandles = handles; }, /** Detaches the alignment-syncing event handlers. @method _detachPosAlignUIHandles @protected **/ _detachPosAlignUIHandles: function () { var handles = this._posAlignUIHandles; if (handles) { new Y.EventHandle(handles).detach(); this._posAlignUIHandles = null; } }, // -- Private Methods ------------------------------------------------------ /** Helper method, used to align the given point on the widget, with the XY page coordinates provided. @method _doAlign @param {String} widgetPoint Supported point constant (e.g. WidgetPositionAlign.TL) @param {Number} x X page coordinate to align to. @param {Number} y Y page coordinate to align to. @private **/ _doAlign: function (widgetPoint, x, y) { var widgetNode = this._posNode, xy; switch (widgetPoint) { case PositionAlign.TL: xy = [x, y]; break; case PositionAlign.TR: xy = [ x - widgetNode.get(OFFSET_WIDTH), y ]; break; case PositionAlign.BL: xy = [ x, y - widgetNode.get(OFFSET_HEIGHT) ]; break; case PositionAlign.BR: xy = [ x - widgetNode.get(OFFSET_WIDTH), y - widgetNode.get(OFFSET_HEIGHT) ]; break; case PositionAlign.TC: xy = [ x - (widgetNode.get(OFFSET_WIDTH) / 2), y ]; break; case PositionAlign.BC: xy = [ x - (widgetNode.get(OFFSET_WIDTH) / 2), y - widgetNode.get(OFFSET_HEIGHT) ]; break; case PositionAlign.LC: xy = [ x, y - (widgetNode.get(OFFSET_HEIGHT) / 2) ]; break; case PositionAlign.RC: xy = [ x - widgetNode.get(OFFSET_WIDTH), y - (widgetNode.get(OFFSET_HEIGHT) / 2) ]; break; case PositionAlign.CC: xy = [ x - (widgetNode.get(OFFSET_WIDTH) / 2), y - (widgetNode.get(OFFSET_HEIGHT) / 2) ]; break; default: break; } if (xy) { this.move(xy); } }, /** Returns the region of the passed-in `Node`, or the viewport region if calling with passing in a `Node`. @method _getRegion @param {Node} [node] The node to get the region of. @return {Object} The node's region. @private **/ _getRegion: function (node) { var nodeRegion; if ( ! node) { nodeRegion = this._posNode.get(VIEWPORT_REGION); } else { node = Y.Node.one(node); if (node) { nodeRegion = node.get(REGION); } } return nodeRegion; }, // -- Protected Event Handlers --------------------------------------------- /** Handles `alignChange` events by updating the UI in response to `align` Attribute changes. @method _afterAlignChange @param {EventFacade} e @protected **/ _afterAlignChange: function (e) { var align = e.newVal; if (align) { this._uiSetAlign(align.node, align.points); } }, /** Handles `alignOnChange` events by updating the alignment-syncing event handlers. @method _afterAlignOnChange @param {EventFacade} e @protected **/ _afterAlignOnChange: function(e) { this._detachPosAlignUIHandles(); if (this.get(VISIBLE)) { this._attachPosAlignUIHandles(); } } }; Y.WidgetPositionAlign = PositionAlign; }, '3.5.1' ,{requires:['widget-position']}); /* YUI 3.5.1 (build 22) Copyright 2012 Yahoo! Inc. All rights reserved. Licensed under the BSD License. http://yuilibrary.com/license/ */ YUI.add('widget-stack', function(Y) { /** * Provides stackable (z-index) support for Widgets through an extension. * * @module widget-stack */ var L = Y.Lang, UA = Y.UA, Node = Y.Node, Widget = Y.Widget, ZINDEX = "zIndex", SHIM = "shim", VISIBLE = "visible", BOUNDING_BOX = "boundingBox", RENDER_UI = "renderUI", BIND_UI = "bindUI", SYNC_UI = "syncUI", OFFSET_WIDTH = "offsetWidth", OFFSET_HEIGHT = "offsetHeight", PARENT_NODE = "parentNode", FIRST_CHILD = "firstChild", OWNER_DOCUMENT = "ownerDocument", WIDTH = "width", HEIGHT = "height", PX = "px", // HANDLE KEYS SHIM_DEFERRED = "shimdeferred", SHIM_RESIZE = "shimresize", // Events VisibleChange = "visibleChange", WidthChange = "widthChange", HeightChange = "heightChange", ShimChange = "shimChange", ZIndexChange = "zIndexChange", ContentUpdate = "contentUpdate", // CSS STACKED = "stacked"; /** * Widget extension, which can be used to add stackable (z-index) support to the * base Widget class along with a shimming solution, through the * Base.build method. * * @class WidgetStack * @param {Object} User configuration object */ function Stack(config) { this._stackNode = this.get(BOUNDING_BOX); this._stackHandles = {}; // WIDGET METHOD OVERLAP Y.after(this._renderUIStack, this, RENDER_UI); Y.after(this._syncUIStack, this, SYNC_UI); Y.after(this._bindUIStack, this, BIND_UI); } // Static Properties /** * Static property used to define the default attribute * configuration introduced by WidgetStack. * * @property ATTRS * @type Object * @static */ Stack.ATTRS = { /** * @attribute shim * @type boolean * @default false, for all browsers other than IE6, for which a shim is enabled by default. * * @description Boolean flag to indicate whether or not a shim should be added to the Widgets * boundingBox, to protect it from select box bleedthrough. */ shim: { value: (UA.ie == 6) }, /** * @attribute zIndex * @type number * @default 0 * @description The z-index to apply to the Widgets boundingBox. Non-numerical values for * zIndex will be converted to 0 */ zIndex: { value : 0, setter: '_setZIndex' } }; /** * The HTML parsing rules for the WidgetStack class. * * @property HTML_PARSER * @static * @type Object */ Stack.HTML_PARSER = { zIndex: function (srcNode) { return this._parseZIndex(srcNode); } }; /** * Default class used to mark the shim element * * @property SHIM_CLASS_NAME * @type String * @static * @default "yui3-widget-shim" */ Stack.SHIM_CLASS_NAME = Widget.getClassName(SHIM); /** * Default class used to mark the boundingBox of a stacked widget. * * @property STACKED_CLASS_NAME * @type String * @static * @default "yui3-widget-stacked" */ Stack.STACKED_CLASS_NAME = Widget.getClassName(STACKED); /** * Default markup template used to generate the shim element. * * @property SHIM_TEMPLATE * @type String * @static */ Stack.SHIM_TEMPLATE = ''; Stack.prototype = { /** * Synchronizes the UI to match the Widgets stack state. This method in * invoked after syncUI is invoked for the Widget class using YUI's aop infrastructure. * * @method _syncUIStack * @protected */ _syncUIStack: function() { this._uiSetShim(this.get(SHIM)); this._uiSetZIndex(this.get(ZINDEX)); }, /** * Binds event listeners responsible for updating the UI state in response to * Widget stack related state changes. *

* This method is invoked after bindUI is invoked for the Widget class * using YUI's aop infrastructure. *

* @method _bindUIStack * @protected */ _bindUIStack: function() { this.after(ShimChange, this._afterShimChange); this.after(ZIndexChange, this._afterZIndexChange); }, /** * Creates/Initializes the DOM to support stackability. *

* This method in invoked after renderUI is invoked for the Widget class * using YUI's aop infrastructure. *

* @method _renderUIStack * @protected */ _renderUIStack: function() { this._stackNode.addClass(Stack.STACKED_CLASS_NAME); }, /** Parses a `zIndex` attribute value from this widget's `srcNode`. @method _parseZIndex @param {Node} srcNode The node to parse a `zIndex` value from. @return {Mixed} The parsed `zIndex` value. @protected **/ _parseZIndex: function (srcNode) { var zIndex; // Prefers how WebKit handles `z-index` which better matches the // spec: // // * http://www.w3.org/TR/CSS2/visuren.html#z-index // * https://bugs.webkit.org/show_bug.cgi?id=15562 // // When a node isn't rendered in the document, and/or when a // node is not positioned, then it doesn't have a context to derive // a valid `z-index` value from. if (!srcNode.inDoc() || srcNode.getStyle('position') === 'static') { zIndex = 'auto'; } else { // Uses `getComputedStyle()` because it has greater accuracy in // more browsers than `getStyle()` does for `z-index`. zIndex = srcNode.getComputedStyle('zIndex'); } // This extension adds a stacking context to widgets, therefore a // `srcNode` witout a stacking context (i.e. "auto") will return // `null` from this DOM parser. This way the widget's default or // user provided value for `zIndex` will be used. return zIndex === 'auto' ? null : zIndex; }, /** * Default setter for zIndex attribute changes. Normalizes zIndex values to * numbers, converting non-numerical values to 0. * * @method _setZIndex * @protected * @param {String | Number} zIndex * @return {Number} Normalized zIndex */ _setZIndex: function(zIndex) { if (L.isString(zIndex)) { zIndex = parseInt(zIndex, 10); } if (!L.isNumber(zIndex)) { zIndex = 0; } return zIndex; }, /** * Default attribute change listener for the shim attribute, responsible * for updating the UI, in response to attribute changes. * * @method _afterShimChange * @protected * @param {EventFacade} e The event facade for the attribute change */ _afterShimChange : function(e) { this._uiSetShim(e.newVal); }, /** * Default attribute change listener for the zIndex attribute, responsible * for updating the UI, in response to attribute changes. * * @method _afterZIndexChange * @protected * @param {EventFacade} e The event facade for the attribute change */ _afterZIndexChange : function(e) { this._uiSetZIndex(e.newVal); }, /** * Updates the UI to reflect the zIndex value passed in. * * @method _uiSetZIndex * @protected * @param {number} zIndex The zindex to be reflected in the UI */ _uiSetZIndex: function (zIndex) { this._stackNode.setStyle(ZINDEX, zIndex); }, /** * Updates the UI to enable/disable the shim. If the widget is not currently visible, * creation of the shim is deferred until it is made visible, for performance reasons. * * @method _uiSetShim * @protected * @param {boolean} enable If true, creates/renders the shim, if false, removes it. */ _uiSetShim: function (enable) { if (enable) { // Lazy creation if (this.get(VISIBLE)) { this._renderShim(); } else { this._renderShimDeferred(); } // Eagerly attach resize handlers // // Required because of Event stack behavior, commit ref: cd8dddc // Should be revisted after Ticket #2531067 is resolved. if (UA.ie == 6) { this._addShimResizeHandlers(); } } else { this._destroyShim(); } }, /** * Sets up change handlers for the visible attribute, to defer shim creation/rendering * until the Widget is made visible. * * @method _renderShimDeferred * @private */ _renderShimDeferred : function() { this._stackHandles[SHIM_DEFERRED] = this._stackHandles[SHIM_DEFERRED] || []; var handles = this._stackHandles[SHIM_DEFERRED], createBeforeVisible = function(e) { if (e.newVal) { this._renderShim(); } }; handles.push(this.on(VisibleChange, createBeforeVisible)); // Depending how how Ticket #2531067 is resolved, a reversal of // commit ref: cd8dddc could lead to a more elagent solution, with // the addition of this line here: // // handles.push(this.after(VisibleChange, this.sizeShim)); }, /** * Sets up event listeners to resize the shim when the size of the Widget changes. *

* NOTE: This method is only used for IE6 currently, since IE6 doesn't support a way to * resize the shim purely through CSS, when the Widget does not have an explicit width/height * set. *

* @method _addShimResizeHandlers * @private */ _addShimResizeHandlers : function() { this._stackHandles[SHIM_RESIZE] = this._stackHandles[SHIM_RESIZE] || []; var sizeShim = this.sizeShim, handles = this._stackHandles[SHIM_RESIZE]; handles.push(this.after(VisibleChange, sizeShim)); handles.push(this.after(WidthChange, sizeShim)); handles.push(this.after(HeightChange, sizeShim)); handles.push(this.after(ContentUpdate, sizeShim)); }, /** * Detaches any handles stored for the provided key * * @method _detachStackHandles * @param String handleKey The key defining the group of handles which should be detached * @private */ _detachStackHandles : function(handleKey) { var handles = this._stackHandles[handleKey], handle; if (handles && handles.length > 0) { while((handle = handles.pop())) { handle.detach(); } } }, /** * Creates the shim element and adds it to the DOM * * @method _renderShim * @private */ _renderShim : function() { var shimEl = this._shimNode, stackEl = this._stackNode; if (!shimEl) { shimEl = this._shimNode = this._getShimTemplate(); stackEl.insertBefore(shimEl, stackEl.get(FIRST_CHILD)); this._detachStackHandles(SHIM_DEFERRED); this.sizeShim(); } }, /** * Removes the shim from the DOM, and detaches any related event * listeners. * * @method _destroyShim * @private */ _destroyShim : function() { if (this._shimNode) { this._shimNode.get(PARENT_NODE).removeChild(this._shimNode); this._shimNode = null; this._detachStackHandles(SHIM_DEFERRED); this._detachStackHandles(SHIM_RESIZE); } }, /** * For IE6, synchronizes the size and position of iframe shim to that of * Widget bounding box which it is protecting. For all other browsers, * this method does not do anything. * * @method sizeShim */ sizeShim: function () { var shim = this._shimNode, node = this._stackNode; if (shim && UA.ie === 6 && this.get(VISIBLE)) { shim.setStyle(WIDTH, node.get(OFFSET_WIDTH) + PX); shim.setStyle(HEIGHT, node.get(OFFSET_HEIGHT) + PX); } }, /** * Creates a cloned shim node, using the SHIM_TEMPLATE html template, for use on a new instance. * * @method _getShimTemplate * @private * @return {Node} node A new shim Node instance. */ _getShimTemplate : function() { return Node.create(Stack.SHIM_TEMPLATE, this._stackNode.get(OWNER_DOCUMENT)); } }; Y.WidgetStack = Stack; }, '3.5.1' ,{requires:['base-build', 'widget']}); /* YUI 3.5.1 (build 22) Copyright 2012 Yahoo! Inc. All rights reserved. Licensed under the BSD License. http://yuilibrary.com/license/ */ YUI.add('widget-position-constrain', function(Y) { /** * Provides constrained xy positioning support for Widgets, through an extension. * * It builds on top of the widget-position module, to provide constrained positioning support. * * @module widget-position-constrain */ var CONSTRAIN = "constrain", CONSTRAIN_XYCHANGE = "constrain|xyChange", CONSTRAIN_CHANGE = "constrainChange", PREVENT_OVERLAP = "preventOverlap", ALIGN = "align", EMPTY_STR = "", BINDUI = "bindUI", XY = "xy", X_COORD = "x", Y_COORD = "y", Node = Y.Node, VIEWPORT_REGION = "viewportRegion", REGION = "region", PREVENT_OVERLAP_MAP; /** * A widget extension, which can be used to add constrained xy positioning support to the base Widget class, * through the Base.build method. This extension requires that * the WidgetPosition extension be added to the Widget (before WidgetPositionConstrain, if part of the same * extension list passed to Base.build). * * @class WidgetPositionConstrain * @param {Object} User configuration object */ function PositionConstrain(config) { if (!this._posNode) { Y.error("WidgetPosition needs to be added to the Widget, before WidgetPositionConstrain is added"); } Y.after(this._bindUIPosConstrained, this, BINDUI); } /** * Static property used to define the default attribute * configuration introduced by WidgetPositionConstrain. * * @property ATTRS * @type Object * @static */ PositionConstrain.ATTRS = { /** * @attribute constrain * @type boolean | Node * @default null * @description The node to constrain the widget's bounding box to, when setting xy. Can also be * set to true, to constrain to the viewport. */ constrain : { value: null, setter: "_setConstrain" }, /** * @attribute preventOverlap * @type boolean * @description If set to true, and WidgetPositionAlign is also added to the Widget, * constrained positioning will attempt to prevent the widget's bounding box from overlapping * the element to which it has been aligned, by flipping the orientation of the alignment * for corner based alignments */ preventOverlap : { value:false } }; /** * @property _PREVENT_OVERLAP * @static * @protected * @type Object * @description The set of positions for which to prevent * overlap. */ PREVENT_OVERLAP_MAP = PositionConstrain._PREVENT_OVERLAP = { x: { "tltr": 1, "blbr": 1, "brbl": 1, "trtl": 1 }, y : { "trbr": 1, "tlbl": 1, "bltl": 1, "brtr": 1 } }; PositionConstrain.prototype = { /** * Calculates the constrained positions for the XY positions provided, using * the provided node argument is passed in. If no node value is passed in, the value of * the "constrain" attribute is used. * * @method getConstrainedXY * @param {Array} xy The xy values to constrain * @param {Node | boolean} node Optional. The node to constrain to, or true for the viewport * @return {Array} The constrained xy values */ getConstrainedXY : function(xy, node) { node = node || this.get(CONSTRAIN); var constrainingRegion = this._getRegion((node === true) ? null : node), nodeRegion = this._posNode.get(REGION); return [ this._constrain(xy[0], X_COORD, nodeRegion, constrainingRegion), this._constrain(xy[1], Y_COORD, nodeRegion, constrainingRegion) ]; }, /** * Constrains the widget's bounding box to a node (or the viewport). If xy or node are not * passed in, the current position and the value of "constrain" will be used respectively. * * The widget's position will be changed to the constrained position. * * @method constrain * @param {Array} xy Optional. The xy values to constrain * @param {Node | boolean} node Optional. The node to constrain to, or true for the viewport */ constrain : function(xy, node) { var currentXY, constrainedXY, constraint = node || this.get(CONSTRAIN); if (constraint) { currentXY = xy || this.get(XY); constrainedXY = this.getConstrainedXY(currentXY, constraint); if (constrainedXY[0] !== currentXY[0] || constrainedXY[1] !== currentXY[1]) { this.set(XY, constrainedXY, { constrained:true }); } } }, /** * The setter implementation for the "constrain" attribute. * * @method _setConstrain * @protected * @param {Node | boolean} val The attribute value */ _setConstrain : function(val) { return (val === true) ? val : Node.one(val); }, /** * The method which performs the actual constrain calculations for a given axis ("x" or "y") based * on the regions provided. * * @method _constrain * @protected * * @param {Number} val The value to constrain * @param {String} axis The axis to use for constrainment * @param {Region} nodeRegion The region of the node to constrain * @param {Region} constrainingRegion The region of the node (or viewport) to constrain to * * @return {Number} The constrained value */ _constrain: function(val, axis, nodeRegion, constrainingRegion) { if (constrainingRegion) { if (this.get(PREVENT_OVERLAP)) { val = this._preventOverlap(val, axis, nodeRegion, constrainingRegion); } var x = (axis == X_COORD), regionSize = (x) ? constrainingRegion.width : constrainingRegion.height, nodeSize = (x) ? nodeRegion.width : nodeRegion.height, minConstraint = (x) ? constrainingRegion.left : constrainingRegion.top, maxConstraint = (x) ? constrainingRegion.right - nodeSize : constrainingRegion.bottom - nodeSize; if (val < minConstraint || val > maxConstraint) { if (nodeSize < regionSize) { if (val < minConstraint) { val = minConstraint; } else if (val > maxConstraint) { val = maxConstraint; } } else { val = minConstraint; } } } return val; }, /** * The method which performs the preventOverlap calculations for a given axis ("x" or "y") based * on the value and regions provided. * * @method _preventOverlap * @protected * * @param {Number} val The value being constrain * @param {String} axis The axis to being constrained * @param {Region} nodeRegion The region of the node being constrained * @param {Region} constrainingRegion The region of the node (or viewport) we need to constrain to * * @return {Number} The constrained value */ _preventOverlap : function(val, axis, nodeRegion, constrainingRegion) { var align = this.get(ALIGN), x = (axis === X_COORD), nodeSize, alignRegion, nearEdge, farEdge, spaceOnNearSide, spaceOnFarSide; if (align && align.points && PREVENT_OVERLAP_MAP[axis][align.points.join(EMPTY_STR)]) { alignRegion = this._getRegion(align.node); if (alignRegion) { nodeSize = (x) ? nodeRegion.width : nodeRegion.height; nearEdge = (x) ? alignRegion.left : alignRegion.top; farEdge = (x) ? alignRegion.right : alignRegion.bottom; spaceOnNearSide = (x) ? alignRegion.left - constrainingRegion.left : alignRegion.top - constrainingRegion.top; spaceOnFarSide = (x) ? constrainingRegion.right - alignRegion.right : constrainingRegion.bottom - alignRegion.bottom; } if (val > nearEdge) { if (spaceOnFarSide < nodeSize && spaceOnNearSide > nodeSize) { val = nearEdge - nodeSize; } } else { if (spaceOnNearSide < nodeSize && spaceOnFarSide > nodeSize) { val = farEdge; } } } return val; }, /** * Binds event listeners responsible for updating the UI state in response to * Widget constrained positioning related state changes. *

* This method is invoked after bindUI is invoked for the Widget class * using YUI's aop infrastructure. *

* * @method _bindUIPosConstrained * @protected */ _bindUIPosConstrained : function() { this.after(CONSTRAIN_CHANGE, this._afterConstrainChange); this._enableConstraints(this.get(CONSTRAIN)); }, /** * After change listener for the "constrain" attribute, responsible * for updating the UI, in response to attribute changes. * * @method _afterConstrainChange * @protected * @param {EventFacade} e The event facade */ _afterConstrainChange : function(e) { this._enableConstraints(e.newVal); }, /** * Updates the UI if enabling constraints, and sets up the xyChange event listeners * to constrain whenever the widget is moved. Disabling constraints removes the listeners. * * @method enable or disable constraints listeners * @private * @param {boolean} enable Enable or disable constraints */ _enableConstraints : function(enable) { if (enable) { this.constrain(); this._cxyHandle = this._cxyHandle || this.on(CONSTRAIN_XYCHANGE, this._constrainOnXYChange); } else if (this._cxyHandle) { this._cxyHandle.detach(); this._cxyHandle = null; } }, /** * The on change listener for the "xy" attribute. Modifies the event facade's * newVal property with the constrained XY value. * * @method _constrainOnXYChange * @protected * @param {EventFacade} e The event facade for the attribute change */ _constrainOnXYChange : function(e) { if (!e.constrained) { e.newVal = this.getConstrainedXY(e.newVal); } }, /** * Utility method to normalize region retrieval from a node instance, * or the viewport, if no node is provided. * * @method _getRegion * @private * @param {Node} node Optional. */ _getRegion : function(node) { var region; if (!node) { region = this._posNode.get(VIEWPORT_REGION); } else { node = Node.one(node); if (node) { region = node.get(REGION); } } return region; } }; Y.WidgetPositionConstrain = PositionConstrain; }, '3.5.1' ,{requires:['widget-position']}); /* YUI 3.5.1 (build 22) Copyright 2012 Yahoo! Inc. All rights reserved. Licensed under the BSD License. http://yuilibrary.com/license/ */ YUI.add('overlay', function(Y) { /** * Provides a basic Overlay widget, with Standard Module content support. The Overlay widget * provides Page XY positioning support, alignment and centering support along with basic * stackable support (z-index and shimming). * * @module overlay */ /** * A basic Overlay Widget, which can be positioned based on Page XY co-ordinates and is stackable (z-index support). * It also provides alignment and centering support and uses a standard module format for it's content, with header, * body and footer section support. * * @class Overlay * @constructor * @extends Widget * @uses WidgetStdMod * @uses WidgetPosition * @uses WidgetStack * @uses WidgetPositionAlign * @uses WidgetPositionConstrain * @param {Object} object The user configuration for the instance. */ Y.Overlay = Y.Base.create("overlay", Y.Widget, [Y.WidgetStdMod, Y.WidgetPosition, Y.WidgetStack, Y.WidgetPositionAlign, Y.WidgetPositionConstrain]); }, '3.5.1' ,{requires:['widget', 'widget-stdmod', 'widget-position', 'widget-stack', 'widget-position-align', 'widget-position-constrain']});