diff --git a/src/dom/dom.js b/src/dom/dom.js index 0f0e247c3..4ecb83f6e 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -1041,35 +1041,6 @@ Element.Methods = { return element; }, - /** - * Element.getDimensions(@element) -> Object - * - * Finds the computed width and height of `element` and returns them as - * key/value pairs of an object. - **/ - getDimensions: function(element) { - element = $(element); - var display = Element.getStyle(element, 'display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, /** * Element.makePositioned(@element) -> Element diff --git a/src/dom/layout.js b/src/dom/layout.js index 7f235f455..aae2c2941 100644 --- a/src/dom/layout.js +++ b/src/dom/layout.js @@ -639,8 +639,42 @@ **/ function measure(element, property) { return $(element).getLayout().get(property); + } + + /** + * Element.getDimensions(@element) -> Object + * + * Finds the computed width and height of `element` and returns them as + * key/value pairs of an object. + **/ + function getDimensions(element) { + var layout = $(element).getLayout(); + return { + width: layout.measure('width'), + height: layout.measure('height') + }; } + /** + * Element.getOffsetParent(@element) -> Element + * + * Returns `element`'s closest _positioned_ ancestor. If none is found, the + * `body` element is returned. + **/ + function getOffsetParent(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element === document.body) return $(element); + + while ((element = element.parentNode) && element !== document.body) { + if (Element.getStyle(element, 'position') !== 'static') { + return (element.nodeName === 'HTML') ? $(document.body) : $(element); + } + } + + return $(document.body); + } + + /** * Element.cumulativeOffset(@element) -> Element.Offset * @@ -731,17 +765,79 @@ return new Element.Offset(valueL, valueT); } + /** + * Element.absolutize(@element) -> Element + * + * Turns `element` into an absolutely-positioned element _without_ + * changing its position in the page layout. + **/ + function absolutize(element) { + element = $(element); + + if (Element.getStyle(element, 'position') === 'absolute') { + return element; + } + + var offsetParent = getOffsetParent(element); + var eOffset = element.viewportOffset(), pOffset = + offsetParent.viewportOffset(); + + var offset = eOffset.relativeTo(pOffset); + var layout = element.get('layout'); + + element.store('prototype_absolutize_original_styles', { + left: element.getStyle('left'), + top: element.getStyle('top'), + width: element.getStyle('width'), + height: element.getStyle('height') + }); + + element.setStyle({ + position: 'absolute', + top: offset.top + 'px', + left: offset.left + 'px', + width: layout.get('width') + 'px', + height: layout.get('height') + 'px' + }); + } + + /** + * Element.relativize(@element) -> Element + * + * Turns `element` into a relatively-positioned element without changing + * its position in the page layout. + * + * Used to undo a call to [[Element.absolutize]]. + **/ + function relativize(element) { + element = $(element); + if (Element.getStyle(element, 'position') === 'relative') { + return element; + } + + // Restore the original styles as captured by Element#absolutize. + var originalStyles = + element.retrieve('prototype_absolutize_original_styles'); + + if (originalStyles) element.setStyle(originalStyles); + return element; + } + Element.addMethods({ getLayout: getLayout, measure: measure, + getDimensions: getDimensions, + getOffsetParent: getOffsetParent, cumulativeOffset: cumulativeOffset, positionedOffset: positionedOffset, cumulativeScrollOffset: cumulativeScrollOffset, - viewportOffset: viewportOffset + viewportOffset: viewportOffset, + absolutize: absolutize, + relativize: relativize }); function isBody(element) { - return $w('BODY HTML').include(element.nodeName.toUpperCase()); + return element.nodeName.toUpperCase() === 'BODY'; } // If the browser supports the nonstandard `getBoundingClientRect`