001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.client.impl;
017:
018: import com.google.gwt.user.client.Element;
019: import com.google.gwt.user.client.Event;
020:
021: /**
022: * Mozilla implementation of StandardBrowser. The main difference between
023: * Mozilla and others is that element comparison must be done using isSameNode()
024: * (== comparison doesn't always give you the right answer, probably because of
025: * its JavaScript wrappers for xpcom dom nodes).
026: */
027: class DOMImplMozilla extends DOMImplStandard {
028:
029: @Override
030: public native boolean compare(Element elem1, Element elem2) /*-{
031: if (!elem1 && !elem2) {
032: return true;
033: } else if (!elem1 || !elem2) {
034: return false;
035: }
036: return (elem1.isSameNode(elem2));
037: }-*/;
038:
039: @Override
040: public native int eventGetButton(Event evt) /*-{
041: // Mozilla and IE disagree on what the button codes for buttons should be.
042: // Translating to match IE standard.
043: var button = evt.button;
044: if(button == 0) {
045: return 1;
046: } else if (button == 1) {
047: return 4;
048: }
049: return button || -1;
050: }-*/;
051:
052: @Override
053: public native int eventGetMouseWheelVelocityY(Event evt) /*-{
054: return evt.detail || -1;
055: }-*/;
056:
057: @Override
058: public native int getAbsoluteLeft(Element elem) /*-{
059: // We cannot use DOMImpl here because offsetLeft/Top return erroneous
060: // values when overflow is not visible. We have to difference screenX
061: // here due to a change in getBoxObjectFor which causes inconsistencies
062: // on whether the calculations are inside or outside of the element's
063: // border.
064: return $doc.getBoxObjectFor(elem).screenX
065: - $doc.getBoxObjectFor($doc.documentElement).screenX;
066: }-*/;
067:
068: @Override
069: public native int getAbsoluteTop(Element elem) /*-{
070: // We cannot use DOMImpl here because offsetLeft/Top return erroneous
071: // values when overflow is not visible. We have to difference screenY
072: // here due to a change in getBoxObjectFor which causes inconsistencies
073: // on whether the calculations are inside or outside of the element's
074: // border.
075: return $doc.getBoxObjectFor(elem).screenY
076: - $doc.getBoxObjectFor($doc.documentElement).screenY;
077: }-*/;
078:
079: @Override
080: public native int getChildIndex(Element parent, Element toFind) /*-{
081: var count = 0, child = parent.firstChild;
082: while (child) {
083: if (child.isSameNode(toFind)) {
084: return count;
085: }
086: if (child.nodeType == 1) {
087: ++count;
088: }
089: child = child.nextSibling;
090: }
091: return -1;
092: }-*/;
093:
094: @Override
095: public native boolean isOrHasChild(Element parent, Element child) /*-{
096: while (child) {
097: if (parent.isSameNode(child)) {
098: return true;
099: }
100:
101: try {
102: child = child.parentNode;
103: } catch(e) {
104: // Give up on 'Permission denied to get property
105: // HTMLDivElement.parentNode'
106: // See https://bugzilla.mozilla.org/show_bug.cgi?id=208427
107: return false;
108: }
109:
110: if (child && (child.nodeType != 1)) {
111: child = null;
112: }
113: }
114: return false;
115: }-*/;
116:
117: @Override
118: public void releaseCapture(Element elem) {
119: maybeInitializeEventSystem();
120: releaseCaptureImpl(elem);
121: }
122:
123: @Override
124: public void sinkEvents(Element elem, int bits) {
125: super .sinkEvents(elem, bits);
126: sinkEventsMozilla(elem, bits);
127: }
128:
129: public native void sinkEventsMozilla(Element elem, int bits) /*-{
130: if (bits & 0x20000) {
131: elem.addEventListener('DOMMouseScroll', $wnd.__dispatchEvent, false);
132: }
133: }-*/;
134:
135: @Override
136: public native String toString(Element elem) /*-{
137: // Basic idea is to use the innerHTML property by copying the node into a
138: // div and getting the innerHTML
139: var temp = elem.cloneNode(true);
140: var tempDiv = $doc.createElement("DIV");
141: tempDiv.appendChild(temp);
142: outer = tempDiv.innerHTML;
143: temp.innerHTML = "";
144: return outer;
145: }-*/;
146:
147: @Override
148: public native int windowGetClientHeight() /*-{
149: // Standards mode:
150: // doc.body.clientHeight --> client height with scrollbars.
151: // doc.documentElement.clientHeight --> client height without scrollbars.
152: // Quirks mode:
153: // doc.body.clientHeight --> client height without scrollbars.
154: // doc.documentElement.clientHeight --> document height.
155: // So, must switch value on compatMode.
156: return ($doc.compatMode == 'BackCompat')?
157: $doc.body.clientHeight:
158: $doc.documentElement.clientHeight;
159: }-*/;
160:
161: @Override
162: public native int windowGetClientWidth() /*-{
163: // See comment for windowGetClientHeight.
164: return ($doc.compatMode == 'BackCompat')?
165: $doc.body.clientWidth:
166: $doc.documentElement.clientWidth;
167: }-*/;
168:
169: @Override
170: protected void initEventSystem() {
171: super .initEventSystem();
172: initSyntheticMouseUpEvents();
173: }
174:
175: private native void initSyntheticMouseUpEvents() /*-{
176: $wnd.addEventListener(
177: 'mouseout',
178: function(evt) {
179: var cap = $wnd.__captureElem;
180: if (cap && !evt.relatedTarget) {
181: // Mozilla has the interesting habit of sending a mouseout event
182: // with an 'html' element as the target when the mouse is released
183: // outside of the browser window.
184: if ('html' == evt.target.tagName.toLowerCase()) {
185: // When this occurs, we synthesize a mouseup event, which is
186: // useful for all sorts of dragging code (like in DialogBox).
187: var muEvent = $doc.createEvent('MouseEvents');
188: muEvent.initMouseEvent('mouseup', true, true, $wnd, 0,
189: evt.screenX, evt.screenY, evt.clientX, evt.clientY, evt.ctrlKey,
190: evt.altKey, evt.shiftKey, evt.metaKey, evt.button, null);
191: cap.dispatchEvent(muEvent);
192: }
193: }
194: },
195: true
196: );
197:
198: $wnd.addEventListener('DOMMouseScroll', $wnd.__dispatchCapturedMouseEvent,
199: true);
200: }-*/;
201:
202: private native void releaseCaptureImpl(Element elem) /*-{
203: if (elem.isSameNode($wnd.__captureElem)) {
204: $wnd.__captureElem = null;
205: }
206: }-*/;
207: }
|