3
Copyright 2011 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('widget-stack', function(Y) {
10
* Provides stackable (z-index) support for Widgets through an extension.
12
* @module widget-stack
23
BOUNDING_BOX = "boundingBox",
25
RENDER_UI = "renderUI",
29
OFFSET_WIDTH = "offsetWidth",
30
OFFSET_HEIGHT = "offsetHeight",
31
PARENT_NODE = "parentNode",
32
FIRST_CHILD = "firstChild",
33
OWNER_DOCUMENT = "ownerDocument",
40
SHIM_DEFERRED = "shimdeferred",
41
SHIM_RESIZE = "shimresize",
44
VisibleChange = "visibleChange",
45
WidthChange = "widthChange",
46
HeightChange = "heightChange",
47
ShimChange = "shimChange",
48
ZIndexChange = "zIndexChange",
49
ContentUpdate = "contentUpdate",
55
* Widget extension, which can be used to add stackable (z-index) support to the
56
* base Widget class along with a shimming solution, through the
57
* <a href="Base.html#method_build">Base.build</a> method.
60
* @param {Object} User configuration object
62
function Stack(config) {
63
this._stackNode = this.get(BOUNDING_BOX);
64
this._stackHandles = {};
66
// WIDGET METHOD OVERLAP
67
Y.after(this._renderUIStack, this, RENDER_UI);
68
Y.after(this._syncUIStack, this, SYNC_UI);
69
Y.after(this._bindUIStack, this, BIND_UI);
74
* Static property used to define the default attribute
75
* configuration introduced by WidgetStack.
85
* @default false, for all browsers other than IE6, for which a shim is enabled by default.
87
* @description Boolean flag to indicate whether or not a shim should be added to the Widgets
88
* boundingBox, to protect it from select box bleedthrough.
98
* @description The z-index to apply to the Widgets boundingBox. Non-numerical values for
99
* zIndex will be converted to 0
103
setter: function(val) {
104
return this._setZIndex(val);
110
* The HTML parsing rules for the WidgetStack class.
112
* @property HTML_PARSER
116
Stack.HTML_PARSER = {
117
zIndex: function(contentBox) {
118
return contentBox.getStyle(ZINDEX);
123
* Default class used to mark the shim element
125
* @property SHIM_CLASS_NAME
128
* @default "yui3-widget-shim"
130
Stack.SHIM_CLASS_NAME = Widget.getClassName(SHIM);
133
* Default class used to mark the boundingBox of a stacked widget.
135
* @property STACKED_CLASS_NAME
138
* @default "yui3-widget-stacked"
140
Stack.STACKED_CLASS_NAME = Widget.getClassName(STACKED);
143
* Default markup template used to generate the shim element.
145
* @property SHIM_TEMPLATE
149
Stack.SHIM_TEMPLATE = '<iframe class="' + Stack.SHIM_CLASS_NAME + '" frameborder="0" title="Widget Stacking Shim" src="javascript:false" tabindex="-1" role="presentation"></iframe>';
154
* Synchronizes the UI to match the Widgets stack state. This method in
155
* invoked after syncUI is invoked for the Widget class using YUI's aop infrastructure.
157
* @method _syncUIStack
160
_syncUIStack: function() {
161
this._uiSetShim(this.get(SHIM));
162
this._uiSetZIndex(this.get(ZINDEX));
166
* Binds event listeners responsible for updating the UI state in response to
167
* Widget stack related state changes.
169
* This method is invoked after bindUI is invoked for the Widget class
170
* using YUI's aop infrastructure.
172
* @method _bindUIStack
175
_bindUIStack: function() {
176
this.after(ShimChange, this._afterShimChange);
177
this.after(ZIndexChange, this._afterZIndexChange);
181
* Creates/Initializes the DOM to support stackability.
183
* This method in invoked after renderUI is invoked for the Widget class
184
* using YUI's aop infrastructure.
186
* @method _renderUIStack
189
_renderUIStack: function() {
190
this._stackNode.addClass(Stack.STACKED_CLASS_NAME);
194
* Default setter for zIndex attribute changes. Normalizes zIndex values to
195
* numbers, converting non-numerical values to 0.
199
* @param {String | Number} zIndex
200
* @return {Number} Normalized zIndex
202
_setZIndex: function(zIndex) {
203
if (L.isString(zIndex)) {
204
zIndex = parseInt(zIndex, 10);
206
if (!L.isNumber(zIndex)) {
213
* Default attribute change listener for the shim attribute, responsible
214
* for updating the UI, in response to attribute changes.
216
* @method _afterShimChange
218
* @param {EventFacade} e The event facade for the attribute change
220
_afterShimChange : function(e) {
221
this._uiSetShim(e.newVal);
225
* Default attribute change listener for the zIndex attribute, responsible
226
* for updating the UI, in response to attribute changes.
228
* @method _afterZIndexChange
230
* @param {EventFacade} e The event facade for the attribute change
232
_afterZIndexChange : function(e) {
233
this._uiSetZIndex(e.newVal);
237
* Updates the UI to reflect the zIndex value passed in.
239
* @method _uiSetZIndex
241
* @param {number} zIndex The zindex to be reflected in the UI
243
_uiSetZIndex: function (zIndex) {
244
this._stackNode.setStyle(ZINDEX, zIndex);
248
* Updates the UI to enable/disable the shim. If the widget is not currently visible,
249
* creation of the shim is deferred until it is made visible, for performance reasons.
253
* @param {boolean} enable If true, creates/renders the shim, if false, removes it.
255
_uiSetShim: function (enable) {
258
if (this.get(VISIBLE)) {
261
this._renderShimDeferred();
264
// Eagerly attach resize handlers
266
// Required because of Event stack behavior, commit ref: cd8dddc
267
// Should be revisted after Ticket #2531067 is resolved.
269
this._addShimResizeHandlers();
277
* Sets up change handlers for the visible attribute, to defer shim creation/rendering
278
* until the Widget is made visible.
280
* @method _renderShimDeferred
283
_renderShimDeferred : function() {
285
this._stackHandles[SHIM_DEFERRED] = this._stackHandles[SHIM_DEFERRED] || [];
287
var handles = this._stackHandles[SHIM_DEFERRED],
288
createBeforeVisible = function(e) {
294
handles.push(this.on(VisibleChange, createBeforeVisible));
295
// Depending how how Ticket #2531067 is resolved, a reversal of
296
// commit ref: cd8dddc could lead to a more elagent solution, with
297
// the addition of this line here:
299
// handles.push(this.after(VisibleChange, this.sizeShim));
303
* Sets up event listeners to resize the shim when the size of the Widget changes.
305
* NOTE: This method is only used for IE6 currently, since IE6 doesn't support a way to
306
* resize the shim purely through CSS, when the Widget does not have an explicit width/height
309
* @method _addShimResizeHandlers
312
_addShimResizeHandlers : function() {
314
this._stackHandles[SHIM_RESIZE] = this._stackHandles[SHIM_RESIZE] || [];
316
var sizeShim = this.sizeShim,
317
handles = this._stackHandles[SHIM_RESIZE];
319
handles.push(this.after(VisibleChange, sizeShim));
320
handles.push(this.after(WidthChange, sizeShim));
321
handles.push(this.after(HeightChange, sizeShim));
322
handles.push(this.after(ContentUpdate, sizeShim));
326
* Detaches any handles stored for the provided key
328
* @method _detachStackHandles
329
* @param String handleKey The key defining the group of handles which should be detached
332
_detachStackHandles : function(handleKey) {
333
var handles = this._stackHandles[handleKey],
336
if (handles && handles.length > 0) {
337
while((handle = handles.pop())) {
344
* Creates the shim element and adds it to the DOM
346
* @method _renderShim
349
_renderShim : function() {
350
var shimEl = this._shimNode,
351
stackEl = this._stackNode;
354
shimEl = this._shimNode = this._getShimTemplate();
355
stackEl.insertBefore(shimEl, stackEl.get(FIRST_CHILD));
357
this._detachStackHandles(SHIM_DEFERRED);
363
* Removes the shim from the DOM, and detaches any related event
366
* @method _destroyShim
369
_destroyShim : function() {
370
if (this._shimNode) {
371
this._shimNode.get(PARENT_NODE).removeChild(this._shimNode);
372
this._shimNode = null;
374
this._detachStackHandles(SHIM_DEFERRED);
375
this._detachStackHandles(SHIM_RESIZE);
380
* For IE6, synchronizes the size and position of iframe shim to that of
381
* Widget bounding box which it is protecting. For all other browsers,
382
* this method does not do anything.
386
sizeShim: function () {
387
var shim = this._shimNode,
388
node = this._stackNode;
390
if (shim && UA.ie === 6 && this.get(VISIBLE)) {
391
shim.setStyle(WIDTH, node.get(OFFSET_WIDTH) + PX);
392
shim.setStyle(HEIGHT, node.get(OFFSET_HEIGHT) + PX);
397
* Creates a cloned shim node, using the SHIM_TEMPLATE html template, for use on a new instance.
399
* @method _getShimTemplate
401
* @return {Node} node A new shim Node instance.
403
_getShimTemplate : function() {
404
return Node.create(Stack.SHIM_TEMPLATE, this._stackNode.get(OWNER_DOCUMENT));
408
Y.WidgetStack = Stack;
411
}, '3.4.1' ,{requires:['base-build', 'widget']});