/** * A class that provides an underlay element which displays behind an absolutely positioned * target element and tracks its size and position. Abstract base class for * {@link Ext.dom.Shadow} and {@link Ext.dom.Shim} * * * @private * @abstract */Ext.define('Ext.dom.Underlay', { requires: [ 'Ext.dom.UnderlayPool' ], /** * @cfg {Ext.dom.Element} target * The target element */ /** * @cfg {Number} zIndex * The CSS z-index to use for this underlay. Defaults to the z-index of {@link #target}. */ constructor: function(config) { Ext.apply(this, config); }, /** * @method * @protected * Called before the underlay is shown, immediately after its element is retrieved * from the pool */ beforeShow: Ext.emptyFn, /** * @protected * Returns the dom element that this underlay should be inserted before. * Defaults to the target element * @return {Ext.dom.Element} */ getInsertionTarget: function() { return this.target; }, /** * @protected * @return {Ext.dom.UnderlayPool} */ getPool: function() { return this.pool || (this.self.prototype.pool = new Ext.dom.UnderlayPool(this.elementConfig)); }, /** * Hides the underlay */ hide: function() { var me = this, el = me.el; if (el) { if (el.dom) { el.hide(); me.getPool().checkIn(el); } me.el = null; } me.hidden = true; }, /** * Aligns the underlay to its target element * @param {Number} [x] The x position of the target element. If not provided, the * x position will be read from the DOM. * @param {Number} [y] The y position of the target element. If not provided, the * y position will be read from the DOM. * @param {Number} [width] The width of the target element. If not provided, the * width will be read from the DOM. * @param {Number} [height] The height of the target element. If not provided, the * height will be read from the DOM. */ realign: function(x, y, width, height) { var me = this, el = me.el, target = me.target, offsets = me.offsets, max = Math.max; if (el) { if (x == null) { x = target.getX(); } if (y == null) { y = target.getY(); } if (width == null) { width = target.getWidth(); } if (height == null) { height = target.getHeight(); } if (offsets) { x = x + offsets.x; y = y + offsets.y; width = max(width + offsets.w, 0); height = max(height + offsets.h, 0); } el.setXY([x, y]); el.setSize(width, height); } }, /** * Adjust the z-index of this underlay * @param {Number} zIndex The new z-index */ setZIndex: function(zIndex) { this.zIndex = zIndex; if (this.el) { this.el.setStyle("z-index", zIndex); } }, /** * Shows the underlay */ show: function() { var me = this, target = me.target, zIndex = me.zIndex, el = me.el, insertionTarget = me.getInsertionTarget().dom, dom; if (!el) { el = me.el = me.getPool().checkOut(); } me.beforeShow(); if (zIndex == null) { // For best results, we need the underlay to be as close as possible to its // target element in the z-index stacking order without overlaying the target // element. Since the UnderlayPool inserted the underlay as high as possible // in the dom tree when we checked the underlay out of the pool, we can assume // that it comes before the target element in the dom tree, and therefore can // give it the exact same index as the target element. zIndex = (parseInt(target.getStyle("z-index"), 10)); } if (zIndex) { el.setStyle("z-index", zIndex); } // Overlay elements are shared, so fix position to match current owner el.setStyle('position', me.fixed ? 'fixed' : ''); dom = el.dom; if (dom.nextSibling !== insertionTarget) { // inserting the underlay as the previous sibling of the target ensures that // it will show behind the target, as long as its z-index is less than or equal // to the z-index of the target element. target.dom.parentNode.insertBefore(dom, insertionTarget); } el.show(); me.realign(); me.hidden = false; } });