| /* |
| * Copyright 2011 Google Inc. |
| * |
| * 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 com.google.gwt.dom.client; |
| |
| import com.google.gwt.core.client.JavaScriptObject; |
| |
| /** |
| * StandardBase implementation of {@link com.google.gwt.user.client.impl.DOMImpl}. |
| */ |
| class DOMImplStandardBase extends DOMImplStandard { |
| |
| private static class ClientRect extends JavaScriptObject { |
| |
| protected ClientRect() { |
| } |
| |
| public final int getLeft() { |
| return toInt32(getSubPixelLeft()); |
| } |
| |
| public final int getTop() { |
| return toInt32(getSubPixelTop()); |
| } |
| |
| private final native double getSubPixelLeft() /*-{ |
| return this.left; |
| }-*/; |
| |
| private final native double getSubPixelTop() /*-{ |
| return this.top; |
| }-*/; |
| } |
| |
| private static native double getAbsoluteLeftUsingOffsets(Element elem) /*-{ |
| // Unattached elements and elements (or their ancestors) with style |
| // 'display: none' have no offsetLeft. |
| if (elem.offsetLeft == null) { |
| return 0; |
| } |
| |
| var left = 0; |
| var doc = elem.ownerDocument; |
| var curr = elem.parentNode; |
| if (curr) { |
| // This intentionally excludes body which has a null offsetParent. |
| while (curr.offsetParent) { |
| left -= curr.scrollLeft; |
| |
| // In RTL mode, offsetLeft is relative to the left edge of the |
| // scrollable area when scrolled all the way to the right, so we need |
| // to add back that difference. |
| if (doc.defaultView.getComputedStyle(curr, '').getPropertyValue('direction') == 'rtl') { |
| left += (curr.scrollWidth - curr.clientWidth); |
| } |
| |
| curr = curr.parentNode; |
| } |
| } |
| |
| while (elem) { |
| left += elem.offsetLeft; |
| |
| if (doc.defaultView.getComputedStyle(elem, '')['position'] == 'fixed') { |
| left += doc.body.scrollLeft; |
| return left; |
| } |
| |
| // Safari 3 does not include borders with offsetLeft, so we need to add |
| // the borders of the parent manually. |
| var parent = elem.offsetParent; |
| if (parent && $wnd.devicePixelRatio) { |
| left += parseInt(doc.defaultView.getComputedStyle(parent, '').getPropertyValue('border-left-width')); |
| } |
| |
| // Safari bug: a top-level absolutely positioned element includes the |
| // body's offset position already. |
| if (parent && (parent.tagName == 'BODY') && |
| (elem.style.position == 'absolute')) { |
| break; |
| } |
| |
| elem = parent; |
| } |
| return left; |
| }-*/; |
| |
| private static native double getAbsoluteTopUsingOffsets(Element elem) /*-{ |
| // Unattached elements and elements (or their ancestors) with style |
| // 'display: none' have no offsetTop. |
| if (elem.offsetTop == null) { |
| return 0; |
| } |
| |
| var top = 0; |
| var doc = elem.ownerDocument; |
| var curr = elem.parentNode; |
| if (curr) { |
| // This intentionally excludes body which has a null offsetParent. |
| while (curr.offsetParent) { |
| top -= curr.scrollTop; |
| curr = curr.parentNode; |
| } |
| } |
| |
| while (elem) { |
| top += elem.offsetTop; |
| |
| if (doc.defaultView.getComputedStyle(elem, '')['position'] == 'fixed') { |
| top += doc.body.scrollTop; |
| return top; |
| } |
| |
| // Safari 3 does not include borders with offsetTop, so we need to add the |
| // borders of the parent manually. |
| var parent = elem.offsetParent; |
| if (parent && $wnd.devicePixelRatio) { |
| top += parseInt(doc.defaultView.getComputedStyle(parent, '').getPropertyValue('border-top-width')); |
| } |
| |
| // Safari bug: a top-level absolutely positioned element includes the |
| // body's offset position already. |
| if (parent && (parent.tagName == 'BODY') && |
| (elem.style.position == 'absolute')) { |
| break; |
| } |
| |
| elem = parent; |
| } |
| return top; |
| }-*/; |
| |
| private static native ClientRect getBoundingClientRect(Element element) /*-{ |
| return element.getBoundingClientRect && element.getBoundingClientRect(); |
| }-*/; |
| |
| /** |
| * The type property on a button element is read-only in safari, so we need to |
| * set it using setAttribute. |
| */ |
| @Override |
| public native ButtonElement createButtonElement(Document doc, String type) /*-{ |
| var e = doc.createElement("BUTTON"); |
| e.setAttribute('type', type); |
| return e; |
| }-*/; |
| |
| @Override |
| public native NativeEvent createKeyCodeEvent(Document doc, String type, |
| boolean ctrlKey, boolean altKey, boolean shiftKey, boolean metaKey, |
| int keyCode) /*-{ |
| var evt = this.@com.google.gwt.dom.client.DOMImplStandardBase::createKeyEvent(Lcom/google/gwt/dom/client/Document;Ljava/lang/String;ZZZZZZ)(doc, type, true, true, ctrlKey, altKey, shiftKey, metaKey) |
| evt.keyCode = keyCode; |
| return evt; |
| }-*/; |
| |
| @Override |
| @Deprecated |
| public native NativeEvent createKeyEvent(Document doc, String type, |
| boolean canBubble, boolean cancelable, boolean ctrlKey, boolean altKey, |
| boolean shiftKey, boolean metaKey, int keyCode, int charCode) /*-{ |
| var evt = this.@com.google.gwt.dom.client.DOMImplStandardBase::createKeyEvent(Lcom/google/gwt/dom/client/Document;Ljava/lang/String;ZZZZZZ)(doc, type, canBubble, cancelable, ctrlKey, altKey, shiftKey, metaKey) |
| evt.keyCode = keyCode; |
| evt.charCode = charCode; |
| return evt; |
| }-*/; |
| |
| @Override |
| public native NativeEvent createKeyPressEvent(Document doc, |
| boolean ctrlKey, boolean altKey, boolean shiftKey, boolean metaKey, |
| int charCode) /*-{ |
| var evt = this.@com.google.gwt.dom.client.DOMImplStandardBase::createKeyEvent(Lcom/google/gwt/dom/client/Document;Ljava/lang/String;ZZZZZZ)(doc, 'keypress', true, true, ctrlKey, altKey, shiftKey, metaKey) |
| evt.charCode = charCode; |
| return evt; |
| }-*/; |
| |
| /** |
| * Safari 2 does not support {@link ScriptElement#setText(String)}. |
| */ |
| @Override |
| public ScriptElement createScriptElement(Document doc, String source) { |
| ScriptElement elem = (ScriptElement) createElement(doc, "script"); |
| elem.setInnerText(source); |
| return elem; |
| } |
| |
| @Override |
| public native EventTarget eventGetCurrentTarget(NativeEvent event) /*-{ |
| return event.currentTarget || $wnd; |
| }-*/; |
| |
| @Override |
| public native int eventGetMouseWheelVelocityY(NativeEvent evt) /*-{ |
| return Math.round(-evt.wheelDelta / 40) || 0; |
| }-*/; |
| |
| @Override |
| public int getAbsoluteLeft(Element elem) { |
| ClientRect rect = getBoundingClientRect(elem); |
| double left = rect != null ? rect.getSubPixelLeft() |
| + getScrollLeft(elem.getOwnerDocument()) |
| : getAbsoluteLeftUsingOffsets(elem); |
| return toInt32(left); |
| } |
| |
| @Override |
| public int getAbsoluteTop(Element elem) { |
| ClientRect rect = getBoundingClientRect(elem); |
| double top = rect != null ? rect.getSubPixelTop() |
| + getScrollTop(elem.getOwnerDocument()) |
| : getAbsoluteTopUsingOffsets(elem); |
| return toInt32(top); |
| } |
| |
| @Override |
| public int getScrollLeft(Element elem) { |
| if (!elem.hasTagName(BodyElement.TAG) && isRTL(elem)) { |
| return super.getScrollLeft(elem) |
| - (elem.getScrollWidth() - elem.getClientWidth()); |
| } |
| return super.getScrollLeft(elem); |
| } |
| |
| @Override |
| public native int getTabIndex(Element elem) /*-{ |
| // tabIndex is undefined for divs and other non-focusable elements prior to |
| // Safari 4. |
| return typeof elem.tabIndex != 'undefined' ? elem.tabIndex : -1; |
| }-*/; |
| |
| @Override |
| public void setScrollLeft(Element elem, int left) { |
| if (!elem.hasTagName(BodyElement.TAG) && isRTL(elem)) { |
| left += elem.getScrollWidth() - elem.getClientWidth(); |
| } |
| super.setScrollLeft(elem, left); |
| } |
| |
| protected native boolean isRTL(Element elem) /*-{ |
| return elem.ownerDocument.defaultView.getComputedStyle(elem, '').direction == 'rtl'; |
| }-*/; |
| |
| private native NativeEvent createKeyEvent(Document doc, String type, |
| boolean canBubble, boolean cancelable, boolean ctrlKey, boolean altKey, |
| boolean shiftKey, boolean metaKey) /*-{ |
| // WebKit's KeyboardEvent cannot set or even initialize charCode, keyCode, etc. |
| // And UIEvent's charCode and keyCode are read-only. |
| // So we "fake" an event using a raw Event and expandos |
| var evt = doc.createEvent('Event'); |
| evt.initEvent(type, canBubble, cancelable); |
| evt.ctrlKey = ctrlKey; |
| evt.altKey = altKey; |
| evt.shiftKey = shiftKey; |
| evt.metaKey = metaKey; |
| return evt; |
| }-*/; |
| } |
| |