2
YUI 3.10.3 (build 2fb5187)
3
Copyright 2013 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
8
YUI.add('widget-stack', function (Y, NAME) {
11
* Provides stackable (z-index) support for Widgets through an extension.
13
* @module widget-stack
24
BOUNDING_BOX = "boundingBox",
26
RENDER_UI = "renderUI",
30
OFFSET_WIDTH = "offsetWidth",
31
OFFSET_HEIGHT = "offsetHeight",
32
PARENT_NODE = "parentNode",
33
FIRST_CHILD = "firstChild",
34
OWNER_DOCUMENT = "ownerDocument",
41
SHIM_DEFERRED = "shimdeferred",
42
SHIM_RESIZE = "shimresize",
45
VisibleChange = "visibleChange",
46
WidthChange = "widthChange",
47
HeightChange = "heightChange",
48
ShimChange = "shimChange",
49
ZIndexChange = "zIndexChange",
50
ContentUpdate = "contentUpdate",
56
* Widget extension, which can be used to add stackable (z-index) support to the
57
* base Widget class along with a shimming solution, through the
58
* <a href="Base.html#method_build">Base.build</a> method.
61
* @param {Object} User configuration object
63
function Stack(config) {
64
this._stackNode = this.get(BOUNDING_BOX);
65
this._stackHandles = {};
67
// WIDGET METHOD OVERLAP
68
Y.after(this._renderUIStack, this, RENDER_UI);
69
Y.after(this._syncUIStack, this, SYNC_UI);
70
Y.after(this._bindUIStack, this, BIND_UI);
75
* Static property used to define the default attribute
76
* configuration introduced by WidgetStack.
86
* @default false, for all browsers other than IE6, for which a shim is enabled by default.
88
* @description Boolean flag to indicate whether or not a shim should be added to the Widgets
89
* boundingBox, to protect it from select box bleedthrough.
99
* @description The z-index to apply to the Widgets boundingBox. Non-numerical values for
100
* zIndex will be converted to 0
109
* The HTML parsing rules for the WidgetStack class.
111
* @property HTML_PARSER
115
Stack.HTML_PARSER = {
116
zIndex: function (srcNode) {
117
return this._parseZIndex(srcNode);
122
* Default class used to mark the shim element
124
* @property SHIM_CLASS_NAME
127
* @default "yui3-widget-shim"
129
Stack.SHIM_CLASS_NAME = Widget.getClassName(SHIM);
132
* Default class used to mark the boundingBox of a stacked widget.
134
* @property STACKED_CLASS_NAME
137
* @default "yui3-widget-stacked"
139
Stack.STACKED_CLASS_NAME = Widget.getClassName(STACKED);
142
* Default markup template used to generate the shim element.
144
* @property SHIM_TEMPLATE
148
Stack.SHIM_TEMPLATE = '<iframe class="' + Stack.SHIM_CLASS_NAME + '" frameborder="0" title="Widget Stacking Shim" src="javascript:false" tabindex="-1" role="presentation"></iframe>';
153
* Synchronizes the UI to match the Widgets stack state. This method in
154
* invoked after syncUI is invoked for the Widget class using YUI's aop infrastructure.
156
* @method _syncUIStack
159
_syncUIStack: function() {
160
this._uiSetShim(this.get(SHIM));
161
this._uiSetZIndex(this.get(ZINDEX));
165
* Binds event listeners responsible for updating the UI state in response to
166
* Widget stack related state changes.
168
* This method is invoked after bindUI is invoked for the Widget class
169
* using YUI's aop infrastructure.
171
* @method _bindUIStack
174
_bindUIStack: function() {
175
this.after(ShimChange, this._afterShimChange);
176
this.after(ZIndexChange, this._afterZIndexChange);
180
* Creates/Initializes the DOM to support stackability.
182
* This method in invoked after renderUI is invoked for the Widget class
183
* using YUI's aop infrastructure.
185
* @method _renderUIStack
188
_renderUIStack: function() {
189
this._stackNode.addClass(Stack.STACKED_CLASS_NAME);
193
Parses a `zIndex` attribute value from this widget's `srcNode`.
196
@param {Node} srcNode The node to parse a `zIndex` value from.
197
@return {Mixed} The parsed `zIndex` value.
200
_parseZIndex: function (srcNode) {
203
// Prefers how WebKit handles `z-index` which better matches the
206
// * http://www.w3.org/TR/CSS2/visuren.html#z-index
207
// * https://bugs.webkit.org/show_bug.cgi?id=15562
209
// When a node isn't rendered in the document, and/or when a
210
// node is not positioned, then it doesn't have a context to derive
211
// a valid `z-index` value from.
212
if (!srcNode.inDoc() || srcNode.getStyle('position') === 'static') {
215
// Uses `getComputedStyle()` because it has greater accuracy in
216
// more browsers than `getStyle()` does for `z-index`.
217
zIndex = srcNode.getComputedStyle('zIndex');
220
// This extension adds a stacking context to widgets, therefore a
221
// `srcNode` witout a stacking context (i.e. "auto") will return
222
// `null` from this DOM parser. This way the widget's default or
223
// user provided value for `zIndex` will be used.
224
return zIndex === 'auto' ? null : zIndex;
228
* Default setter for zIndex attribute changes. Normalizes zIndex values to
229
* numbers, converting non-numerical values to 0.
233
* @param {String | Number} zIndex
234
* @return {Number} Normalized zIndex
236
_setZIndex: function(zIndex) {
237
if (L.isString(zIndex)) {
238
zIndex = parseInt(zIndex, 10);
240
if (!L.isNumber(zIndex)) {
247
* Default attribute change listener for the shim attribute, responsible
248
* for updating the UI, in response to attribute changes.
250
* @method _afterShimChange
252
* @param {EventFacade} e The event facade for the attribute change
254
_afterShimChange : function(e) {
255
this._uiSetShim(e.newVal);
259
* Default attribute change listener for the zIndex attribute, responsible
260
* for updating the UI, in response to attribute changes.
262
* @method _afterZIndexChange
264
* @param {EventFacade} e The event facade for the attribute change
266
_afterZIndexChange : function(e) {
267
this._uiSetZIndex(e.newVal);
271
* Updates the UI to reflect the zIndex value passed in.
273
* @method _uiSetZIndex
275
* @param {number} zIndex The zindex to be reflected in the UI
277
_uiSetZIndex: function (zIndex) {
278
this._stackNode.setStyle(ZINDEX, zIndex);
282
* Updates the UI to enable/disable the shim. If the widget is not currently visible,
283
* creation of the shim is deferred until it is made visible, for performance reasons.
287
* @param {boolean} enable If true, creates/renders the shim, if false, removes it.
289
_uiSetShim: function (enable) {
292
if (this.get(VISIBLE)) {
295
this._renderShimDeferred();
298
// Eagerly attach resize handlers
300
// Required because of Event stack behavior, commit ref: cd8dddc
301
// Should be revisted after Ticket #2531067 is resolved.
303
this._addShimResizeHandlers();
311
* Sets up change handlers for the visible attribute, to defer shim creation/rendering
312
* until the Widget is made visible.
314
* @method _renderShimDeferred
317
_renderShimDeferred : function() {
319
this._stackHandles[SHIM_DEFERRED] = this._stackHandles[SHIM_DEFERRED] || [];
321
var handles = this._stackHandles[SHIM_DEFERRED],
322
createBeforeVisible = function(e) {
328
handles.push(this.on(VisibleChange, createBeforeVisible));
329
// Depending how how Ticket #2531067 is resolved, a reversal of
330
// commit ref: cd8dddc could lead to a more elagent solution, with
331
// the addition of this line here:
333
// handles.push(this.after(VisibleChange, this.sizeShim));
337
* Sets up event listeners to resize the shim when the size of the Widget changes.
339
* NOTE: This method is only used for IE6 currently, since IE6 doesn't support a way to
340
* resize the shim purely through CSS, when the Widget does not have an explicit width/height
343
* @method _addShimResizeHandlers
346
_addShimResizeHandlers : function() {
348
this._stackHandles[SHIM_RESIZE] = this._stackHandles[SHIM_RESIZE] || [];
350
var sizeShim = this.sizeShim,
351
handles = this._stackHandles[SHIM_RESIZE];
353
handles.push(this.after(VisibleChange, sizeShim));
354
handles.push(this.after(WidthChange, sizeShim));
355
handles.push(this.after(HeightChange, sizeShim));
356
handles.push(this.after(ContentUpdate, sizeShim));
360
* Detaches any handles stored for the provided key
362
* @method _detachStackHandles
363
* @param String handleKey The key defining the group of handles which should be detached
366
_detachStackHandles : function(handleKey) {
367
var handles = this._stackHandles[handleKey],
370
if (handles && handles.length > 0) {
371
while((handle = handles.pop())) {
378
* Creates the shim element and adds it to the DOM
380
* @method _renderShim
383
_renderShim : function() {
384
var shimEl = this._shimNode,
385
stackEl = this._stackNode;
388
shimEl = this._shimNode = this._getShimTemplate();
389
stackEl.insertBefore(shimEl, stackEl.get(FIRST_CHILD));
391
this._detachStackHandles(SHIM_DEFERRED);
397
* Removes the shim from the DOM, and detaches any related event
400
* @method _destroyShim
403
_destroyShim : function() {
404
if (this._shimNode) {
405
this._shimNode.get(PARENT_NODE).removeChild(this._shimNode);
406
this._shimNode = null;
408
this._detachStackHandles(SHIM_DEFERRED);
409
this._detachStackHandles(SHIM_RESIZE);
414
* For IE6, synchronizes the size and position of iframe shim to that of
415
* Widget bounding box which it is protecting. For all other browsers,
416
* this method does not do anything.
420
sizeShim: function () {
421
var shim = this._shimNode,
422
node = this._stackNode;
424
if (shim && UA.ie === 6 && this.get(VISIBLE)) {
425
shim.setStyle(WIDTH, node.get(OFFSET_WIDTH) + PX);
426
shim.setStyle(HEIGHT, node.get(OFFSET_HEIGHT) + PX);
431
* Creates a cloned shim node, using the SHIM_TEMPLATE html template, for use on a new instance.
433
* @method _getShimTemplate
435
* @return {Node} node A new shim Node instance.
437
_getShimTemplate : function() {
438
return Node.create(Stack.SHIM_TEMPLATE, this._stackNode.get(OWNER_DOCUMENT));
442
Y.WidgetStack = Stack;
445
}, '3.10.3', {"requires": ["base-build", "widget"], "skinnable": true});