/*
* Copyright 2014 cruxframework.org.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.cruxframework.crux.core.client.utils;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.user.client.ui.IsWidget;
/**
* @author Thiago da Rosa de Bustamante
*
*/
public class DOMUtils
{
/**
* Return the rectangle describing the elements bounds (top, left, right and bottom)
* @param element
* @return
*/
public static native TextRectangle getBoundingClientRect(Element element)/*-{
return element.getBoundingClientRect();
}-*/;
public static class TextRectangle extends JavaScriptObject
{
protected TextRectangle(){}
public native final int getTop()/*-{
return this.top;
}-*/;
public native final int getLeft()/*-{
return this.left;
}-*/;
public native final int getRight()/*-{
return this.right;
}-*/;
public native final int getBottom()/*-{
return this.bottom;
}-*/;
}
public static boolean isAttached(Element element)
{
boolean attached = false;
Element documentElement = element.getOwnerDocument().getDocumentElement();
while (element.getParentNode() != null)
{
if (element.equals(documentElement))
{
attached = true;
break;
}
element = element.getParentElement();
}
return attached;
}
public static boolean isRootNode(Element e)
{
return "html".equalsIgnoreCase(e.getTagName()) || e == Document.get().getBody();
}
public static double getMarginLeft(Element e)
{
return getMargin(e.getStyle().getMarginLeft());
}
public static double getMarginTop(Element e)
{
return getMargin(e.getStyle().getMarginTop());
}
public static double getBorderWidth(Element e)
{
return getMargin(e.getStyle().getBorderWidth());
}
private static double getMargin(String val)
{
if (StringUtils.isEmpty(val))
{
return 0;
}
if ("thick".equalsIgnoreCase(val))
{
return (5);
}
else if ("medium".equalsIgnoreCase(val))
{
return (3);
}
else if ("thin".equalsIgnoreCase(val))
{
return (1);
}
val = val.trim().replaceAll("[^\\d\\.\\-]+.*$", "");
return val.length() == 0 ? 0 : Double.parseDouble(val);
}
public static Element getScrollParent(final Element element)
{
Element scrollParent = null;
String pos = element.getStyle().getPosition();
Position position = (pos == null? null : Position.valueOf(pos));
if (Position.FIXED == position)
{
return Document.get().getBody();
}
Element parent = element.getParentElement();
Element root = Document.get().getDocumentElement();
while (parent != root)
{
pos = parent.getStyle().getPosition();
Position parentPosition = (pos!= null ? Position.valueOf(pos):null);
if (isOverflowEnabled(parent))
{
if (position == Position.ABSOLUTE)
{
if (parentPosition == Position.RELATIVE || parentPosition == Position.ABSOLUTE || parentPosition == Position.FIXED)
{
scrollParent = parent;
break;
}
}
else
{
scrollParent = parent;
break;
}
}
parent = parent.getParentElement();
}
return scrollParent != null ? scrollParent : Document.get().getBody();
}
public static boolean isOverflowEnabled(Element e)
{
Style style = e.getStyle();
String overflow = style.getOverflow() + style.getOverflowX() + style.getOverflowY();
return overflow.contains("auto") || overflow.contains("scroll");
}
public static native void addOneTimeHandler(Element el, String eventName, EvtHandler evtHandler)/*-{
var func;
func = function(evt)
{
el.removeEventListener(eventName, func);
evtHandler.@org.cruxframework.crux.core.client.utils.DOMUtils.EvtHandler::onEvent(Lcom/google/gwt/dom/client/NativeEvent;)(evt);
};
el.addEventListener(eventName, func);
}-*/;
public static interface EvtHandler
{
void onEvent(NativeEvent evt);
}
public static native NodeList<Element> getElementsByClassName(Element el, String classname)/*-{
return el.getElementsByClassName(classname);
}-*/;
public static Element getElementById(IsWidget parent, String id)
{
if (parent == null)
{
return null;
}
if (parent.asWidget().isAttached())
{
return Document.get().getElementById(id);
}
return searchElementById(parent.asWidget().getElement(), id);
}
public static Element searchElementById(Element parent, String id)
{
NodeList<Node> children = parent.getChildNodes();
for (int i = 0; i < children.getLength(); i++)
{
Node item = children.getItem(i);
if (item.getNodeType() == Node.ELEMENT_NODE)
{
Element element = Element.as(item);
String candidateId = element.getId();
if (candidateId != null && StringUtils.unsafeEquals(candidateId, id))
{
return element;
}
else
{
Element childElem = searchElementById(element, id);
if (childElem != null)
{
return childElem;
}
}
}
}
return null;
}
}