![JAR search and dependency download from the Maven repository](/logo.png)
rwt.html.Location.js Maven / Gradle / Ivy
/*******************************************************************************
* Copyright: 2004, 2016 1&1 Internet AG, Germany, http://www.1und1.de,
* and EclipseSource
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this
* distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* 1&1 Internet AG and others - original API and implementation
* EclipseSource - adaptation for the Eclipse Remote Application Platform
*
* This class contains code based on the following work:
*
* * jQuery Dimension Plugin
* http://jquery.com/
* Version 1.1.3
*
* Copyright:
* (c) 2007, Paul Bakaus & Brandon Aaron
*
* License:
* MIT: http://www.opensource.org/licenses/mit-license.php
*
* Authors:
* Paul Bakaus
* Brandon Aaron
*
******************************************************************************/
/**
* Query the location of an arbitrary DOM element in relation to its top
* level body element. Works in all major browsers:
*
* * Mozilla 1.5 + 2.0
* * Internet Explorer 6.0 + 7.0 (both standard & quirks mode)
* * Opera 9.2
* * Safari 3.0 beta
*/
rwt.qx.Class.define("rwt.html.Location",
{
statics :
{
/**
* Queries a style property for the given element
*
* @type static
* @param elem {Element} DOM element to query
* @param style {String} Style property
* @return {String} Value of given style property
*/
__style : function( elem, style ) {
return rwt.html.Style.getStyleProperty( elem, style );
},
/**
* Queries a style property for the given element and parses it to a integer value
*
* @type static
* @param elem {Element} DOM element to query
* @param style {String} Style property
* @return {Integer} Value of given style property
*/
__num : function(elem, style) {
var value = rwt.html.Style.getStyleProperty( elem, style );
var result = Math.round( parseFloat( value ,10 ) );
return result || 0;
},
/**
* Computes the scroll offset of the given element relative to the document
* body
.
*
* @type static
* @param elem {Element} DOM element to query
* @return {Map} Map which contains the left
and top
scroll offsets
*/
__computeScroll : function( elem ) {
var left = 0, top = 0;
if( elem.getBoundingClientRect ) {
var win = rwt.html.Nodes.getWindow( elem );
// getBoundingClientRect works in relation to the viewport, not - as desired - the document
left -= rwt.html.Viewport.getScrollLeft( win );
top -= rwt.html.Viewport.getScrollTop( win );
} else {
var body = rwt.html.Nodes.getDocument( elem ).body;
elem = elem.parentNode;
while( elem && elem != body ) {
left += elem.scrollLeft;
top += elem.scrollTop;
elem = elem.parentNode;
}
}
return {
left : Math.ceil( left ),
top : Math.ceil( top )
};
},
/**
* Computes the offset of the given element relative to the document
* body
.
*
* @type static
* @param elem {Element} DOM element to query
* @return {Map} Map which contains the left
and top
offsets
*/
__computeBody : rwt.util.Variant.select( "qx.client", {
"webkit|blink" : function( elem ) {
// Find body element
var doc = rwt.html.Nodes.getDocument(elem);
var body = doc.body;
// Start with the offset
var left = body.offsetLeft;
var top = body.offsetTop;
// Correct substracted border
left += this.__num(body, "borderLeftWidth");
top += this.__num(body, "borderTopWidth");
// Add the margin when running in standard mode
if (doc.compatMode === "CSS1Compat")
{
left += this.__num(body, "marginLeft");
top += this.__num(body, "marginTop");
}
return {
left : Math.ceil( left ),
top : Math.ceil( top )
};
},
"gecko" : function( elem ) {
// Find body element
var body = rwt.html.Nodes.getDocument(elem).body;
// Start with the offset
var left = body.offsetLeft;
var top = body.offsetTop;
// Correct substracted border (only in content-box mode)
if (rwt.widgets.base.ClientDocument.BOXSIZING !== "border-box")
{
left += this.__num(body, "borderLeftWidth");
top += this.__num(body, "borderTopWidth");
// For some unknown reason we must add the border two times
// when there is no absolute positioned element in the DOM tree
// This is not neededd if the offset is computed using
// getBoundingClientRect
if (!elem.getBoundingClientRect)
{
var hasAbs;
while (elem)
{
if (this.__style(elem, "position") === "absolute" || this.__style(elem, "position") === "fixed")
{
hasAbs = true;
break;
}
elem = elem.offsetParent;
}
if (!hasAbs)
{
left += this.__num(body, "borderLeftWidth");
top += this.__num(body, "borderTopWidth");
}
}
}
return {
left : Math.ceil( left ),
top : Math.ceil( top )
};
},
// At the moment only correctly supported by Opera
"default" : function( elem ) {
// Find body element
var body = rwt.html.Nodes.getDocument(elem).body;
// Start with the offset
var left = body.offsetLeft;
var top = body.offsetTop;
return {
left : Math.ceil( left ),
top : Math.ceil( top )
};
}
} ),
/**
* Computes the sum of all offsets of the given element node.
*
* Traditionally this is a loop which goes up the whole parent tree
* and sums up all found offsets.
*
* @type static
* @signature function(elem)
* @param elem {Element} DOM element to query
* @return {Map} Map which contains the left
and top
offsets
*/
__computeOffset : rwt.util.Variant.select( "qx.client", {
"trident|webkit|blink" : function( elem ) {
var doc = rwt.html.Nodes.getDocument(elem);
// TODO: Check if all supported browser have getBoundingClientRect
if (elem.getBoundingClientRect)
{
var rect = elem.getBoundingClientRect();
var left = rect.left;
var top = rect.top;
}
else
{
// Offset of the incoming element
var left = elem.offsetLeft;
var top = elem.offsetTop;
// Start with the first offset parent
elem = elem.offsetParent;
// Stop at the body
var body = doc.body;
// Border correction is only needed for each parent
// not for the incoming element itself
while (elem && elem != body)
{
// Add node offsets
left += elem.offsetLeft;
top += elem.offsetTop;
// Fix missing border
left += this.__num(elem, "borderLeftWidth");
top += this.__num(elem, "borderTopWidth");
// One level up (offset hierarchy)
elem = elem.offsetParent;
}
}
return {
left : Math.ceil( left ),
top : Math.ceil( top )
};
},
"gecko" : function( elem ) {
// Use faster getBoundingClientRect() if available (gecko >= 1.9)
if (elem.getBoundingClientRect)
{
var rect = elem.getBoundingClientRect();
// Firefox 3.0 alpha 6 (gecko 1.9) returns floating point numbers
// use Math.round() to round them to style compatible numbers
var left = Math.round(rect.left);
var top = Math.round(rect.top);
}
else
{
var left = 0;
var top = 0;
// Stop at the body
var body = rwt.html.Nodes.getDocument(elem).body;
var box = rwt.widgets.base.ClientDocument.BOXSIZING;
if( box !== "border-box" ) {
left -= this.__num(elem, "borderLeftWidth");
top -= this.__num(elem, "borderTopWidth");
}
while (elem && elem !== body)
{
// Add node offsets
left += elem.offsetLeft;
top += elem.offsetTop;
// Mozilla does not add the borders to the offset
// when using box-sizing=content-box
if( box !== "border-box" ) {
left += this.__num(elem, "borderLeftWidth");
top += this.__num(elem, "borderTopWidth");
}
// Mozilla does not add the border for a parent that has
// overflow set to anything but visible
if (elem.parentNode && this.__style(elem.parentNode, "overflow") != "visible")
{
left += this.__num(elem.parentNode, "borderLeftWidth");
top += this.__num(elem.parentNode, "borderTopWidth");
}
// One level up (offset hierarchy)
elem = elem.offsetParent;
}
}
return {
left : Math.ceil( left ),
top : Math.ceil( top )
};
},
// At the moment only correctly supported by Opera
"default" : function( elem ) {
var left = 0;
var top = 0;
// Stop at the body
var body = rwt.html.Nodes.getDocument(elem).body;
// Add all offsets of parent hierarchy, do not include
// body element.
while (elem && elem !== body)
{
// Add node offsets
left += elem.offsetLeft;
top += elem.offsetTop;
// One level up (offset hierarchy)
elem = elem.offsetParent;
}
return {
left : Math.ceil( left ),
top : Math.ceil( top )
};
}
} ),
/**
* Computes the location of the given element in context of
* the document dimensions.
*
* Supported modes:
*
* * margin
: Calculate from the margin box of the element (bigger than the visual appearance: including margins of given element)
* * box
: Calculates the offset box of the element (default, uses the same size as visible)
* * border
: Calculate the border box (useful to align to border edges of two elements).
* * scroll
: Calculate the scroll box (relevant for absolute positioned content).
* * padding
: Calculate the padding box (relevant for static/relative positioned content).
*
* @type static
* @param elem {Element} DOM element to query
* @param mode {String} A supported option. See comment above.
* @return {Map} Returns a map with left
, top
,
* right
and bottom
which contains the distance
* of the element relative to the document.
*/
get : function(elem, mode)
{
var body = this.__computeBody(elem);
var isBody = elem.tagName == "BODY";
if (isBody)
{
var left = body.left;
var top = body.top;
}
else
{
var offset = this.__computeOffset(elem);
var scroll = this.__computeScroll(elem);
var left = offset.left + body.left - scroll.left;
var top = offset.top + body.top - scroll.top;
}
var right = left + elem.offsetWidth;
var bottom = top + elem.offsetHeight;
if (mode)
{
// In this modes we want the size as seen from a child what means that we want the full width/height
// which may be higher than the outer width/height when the element has scrollbars.
if (mode == "padding" || mode == "scroll")
{
var overX = rwt.html.Overflow.getX(elem);
if (overX == "scroll" || overX == "auto") {
right += elem.scrollWidth - elem.offsetWidth + this.__num(elem, "borderLeftWidth") + this.__num(elem, "borderRightWidth");
}
var overY = rwt.html.Overflow.getY(elem);
if (overY == "scroll" || overY == "auto") {
bottom += elem.scrollHeight - elem.offsetHeight + this.__num(elem, "borderTopWidth") + this.__num(elem, "borderBottomWidth");
}
}
if( mode === "padding" ) {
left += this.__num(elem, "paddingLeft");
top += this.__num(elem, "paddingTop");
right -= this.__num(elem, "paddingRight");
bottom -= this.__num(elem, "paddingBottom");
}
if( mode === "padding" || mode === "scroll" ) {
left -= isBody ? rwt.html.Viewport.getScrollLeft() : elem.scrollLeft;
top -= isBody ? rwt.html.Viewport.getScrollTop() : elem.scrollTop;
right -= isBody ? rwt.html.Viewport.getScrollLeft() : elem.scrollLeft;
bottom -= isBody ? rwt.html.Viewport.getScrollTop() : elem.scrollTop;
}
if( mode === "padding" || mode === "scroll" || mode === "border" ) {
left += this.__num(elem, "borderLeftWidth");
top += this.__num(elem, "borderTopWidth");
right -= this.__num(elem, "borderRightWidth");
bottom -= this.__num(elem, "borderBottomWidth");
}
if( mode === "margin" ) {
left -= this.__num(elem, "marginLeft");
top -= this.__num(elem, "marginTop");
right += this.__num(elem, "marginRight");
bottom += this.__num(elem, "marginBottom");
}
}
return {
left : left,
top : top,
right : right,
bottom : bottom
};
},
/**
* Computes the location of the given element in context of
* the document dimensions. For supported modes please
* have a look at the {@link rwt.html.Location#get} method.
*
* @type static
* @param elem {Element} DOM element to query
* @param mode {String} A supported option. See comment above.
* @return {Integer} The left distance
* of the element relative to the document.
*/
getLeft : function(elem, mode) {
return this.get(elem, mode).left;
},
/**
* Computes the location of the given element in context of
* the document dimensions.For supported modes please
* have a look at the {@link rwt.html.Location#get} method.
*
* @type static
* @param elem {Element} DOM element to query
* @param mode {String} A supported option. See comment above.
* @return {Integer} The top distance
* of the element relative to the document.
*/
getTop : function(elem, mode) {
return this.get(elem, mode).top;
},
/**
* Computes the location of the given element in context of
* the document dimenions.For supported modes please
* have a look at the {@link rwt.html.Location#get} method.
*
* @type static
* @param elem {Element} DOM element to query
* @param mode {String} A supported option. See comment above.
* @return {Integer} The right distance
* of the element relative to the document.
*/
getRight : function(elem, mode) {
return this.get(elem, mode).right;
},
/**
* Computes the location of the given element in context of
* the document dimenions.For supported modes please
* have a look at the {@link rwt.html.Location#get} method.
*
* @type static
* @param elem {Element} DOM element to query
* @param mode {String} A supported option. See comment above.
* @return {Integer} The bottom distance
* of the element relative to the document.
*/
getBottom : function(elem, mode) {
return this.get(elem, mode).bottom;
},
/**
* Returns the distance between two DOM elements. For supported modes please
* have a look at the {@link rwt.html.Location#get} method.
*
* @type static
* @param elem1 {Element} First element
* @param elem2 {Element} Second element
* @param mode1 {String?null} Mode for first element
* @param mode2 {String?null} Mode for second element
* @return {Map} Returns a map with left
and top
* which contains the distance of the elements from each other.
*/
getRelative : function(elem1, elem2, mode1, mode2)
{
var loc1 = this.get(elem1, mode1);
var loc2 = this.get(elem2, mode2);
return {
left : loc1.left - loc2.left,
top : loc1.top - loc2.top,
right : loc1.right - loc2.right,
bottom : loc1.bottom - loc2.bottom
};
}
}
});
© 2015 - 2025 Weber Informatics LLC | Privacy Policy