Version 3.17.2

APIs

  • Begin typing in the search box above to see results.
Show:

File: widget-stack/js/Widget-Stack.js

/**
 * 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
 * <a href="Base.html#method_build">Base.build</a> method.
 *
 * @class WidgetStack
 * @param {Object} User configuration object
 */
 function Stack(config) {}
 // 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 = '<iframe class="' + Stack.SHIM_CLASS_NAME + '" frameborder="0" title="Widget Stacking Shim" src="javascript:false" tabindex="-1" role="presentation"></iframe>';
 Stack.prototype = {
 initializer : function() {
 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);
 },
 /**
 * 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.
 * <p>
 * This method is invoked after bindUI is invoked for the Widget class
 * using YUI's aop infrastructure.
 * </p>
 * @method _bindUIStack
 * @protected
 */
 _bindUIStack: function() {
 this.after(ShimChange, this._afterShimChange);
 this.after(ZIndexChange, this._afterZIndexChange);
 },
 /**
 * Creates/Initializes the DOM to support stackability.
 * <p>
 * This method in invoked after renderUI is invoked for the Widget class
 * using YUI's aop infrastructure.
 * </p>
 * @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.
 * <p>
 * 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.
 * </p>
 * @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;
 

AltStyle によって変換されたページ (->オリジナル) /