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: import com.google.gwt.user.client.EventListener;
021:
022: /**
023: * Native implementation associated with {@link com.google.gwt.user.client.DOM}.
024: */
025: public abstract class DOMImpl {
026:
027: protected static boolean eventSystemIsInitialized;
028:
029: public native void appendChild(Element parent, Element child) /*-{
030: parent.appendChild(child);
031: }-*/;
032:
033: public abstract boolean compare(Element elem1, Element elem2);
034:
035: public native Element createElement(String tag) /*-{
036: return $doc.createElement(tag);
037: }-*/;
038:
039: public native Element createInputElement(String type) /*-{
040: var e = $doc.createElement("INPUT");
041: e.type = type;
042: return e;
043: }-*/;
044:
045: public abstract Element createInputRadioElement(String name);
046:
047: public Element createSelectElement(boolean multiple) {
048: Element select = createElement("select");
049: if (multiple) {
050: setElementPropertyBoolean(select, "multiple", true);
051: }
052: return select;
053: }
054:
055: public native void eventCancelBubble(Event evt, boolean cancel) /*-{
056: evt.cancelBubble = cancel;
057: }-*/;
058:
059: public native boolean eventGetAltKey(Event evt) /*-{
060: return !!evt.altKey;
061: }-*/;
062:
063: public native int eventGetButton(Event evt) /*-{
064: return evt.button || -1;
065: }-*/;
066:
067: public native int eventGetClientX(Event evt) /*-{
068: return evt.clientX || -1;
069: }-*/;
070:
071: public native int eventGetClientY(Event evt) /*-{
072: return evt.clientY || -1;
073: }-*/;
074:
075: public native boolean eventGetCtrlKey(Event evt) /*-{
076: return !!evt.ctrlKey;
077: }-*/;
078:
079: public native Element eventGetCurrentTarget(Event evt) /*-{
080: return evt.currentTarget;
081: }-*/;
082:
083: public abstract Element eventGetFromElement(Event evt);
084:
085: public native int eventGetKeyCode(Event evt) /*-{
086: // 'which' gives the right key value, except when it doesn't -- in which
087: // case, keyCode gives the right value on all browsers.
088: // If all else fails, return an error code
089: return evt.which || evt.keyCode || -1;
090: }-*/;
091:
092: public native boolean eventGetMetaKey(Event evt) /*-{
093: return !!evt.metaKey;
094: }-*/;
095:
096: public abstract int eventGetMouseWheelVelocityY(Event evt);
097:
098: public native boolean eventGetRepeat(Event evt) /*-{
099: return !!evt.repeat;
100: }-*/;
101:
102: public native int eventGetScreenX(Event evt) /*-{
103: return evt.screenX || -1;
104: }-*/;
105:
106: public native int eventGetScreenY(Event evt) /*-{
107: return evt.screenY || -1;
108: }-*/;
109:
110: public native boolean eventGetShiftKey(Event evt) /*-{
111: return !!evt.shiftKey;
112: }-*/;
113:
114: public abstract Element eventGetTarget(Event evt);
115:
116: public abstract Element eventGetToElement(Event evt);
117:
118: public native String eventGetType(Event evt) /*-{
119: return evt.type;
120: }-*/;
121:
122: public native int eventGetTypeInt(Event evt) /*-{
123: switch (evt.type) {
124: case "blur": return 0x01000;
125: case "change": return 0x00400;
126: case "click": return 0x00001;
127: case "dblclick": return 0x00002;
128: case "focus": return 0x00800;
129: case "keydown": return 0x00080;
130: case "keypress": return 0x00100;
131: case "keyup": return 0x00200;
132: case "load": return 0x08000;
133: case "losecapture": return 0x02000;
134: case "mousedown": return 0x00004;
135: case "mousemove": return 0x00040;
136: case "mouseout": return 0x00020;
137: case "mouseover": return 0x00010;
138: case "mouseup": return 0x00008;
139: case "scroll": return 0x04000;
140: case "error": return 0x10000;
141: case "mousewheel": return 0x20000;
142: case "DOMMouseScroll": return 0x20000;
143: }
144: }-*/;
145:
146: public abstract void eventPreventDefault(Event evt);
147:
148: public native void eventSetKeyCode(Event evt, char key) /*-{
149: evt.keyCode = key;
150: }-*/;
151:
152: public abstract String eventToString(Event evt);
153:
154: public native int getAbsoluteLeft(Element elem) /*-{
155: var left = 0;
156: var curr = elem;
157: // This intentionally excludes body which has a null offsetParent.
158: while (curr.offsetParent) {
159: left -= curr.scrollLeft;
160: curr = curr.parentNode;
161: }
162: while (elem) {
163: left += elem.offsetLeft;
164: elem = elem.offsetParent;
165: }
166: return left;
167: }-*/;
168:
169: public native int getAbsoluteTop(Element elem) /*-{
170: var top = 0;
171: var curr = elem;
172: // This intentionally excludes body which has a null offsetParent.
173: while (curr.offsetParent) {
174: top -= curr.scrollTop;
175: curr = curr.parentNode;
176: }
177: while (elem) {
178: top += elem.offsetTop;
179: elem = elem.offsetParent;
180: }
181: return top;
182: }-*/;
183:
184: public abstract Element getChild(Element elem, int index);
185:
186: public abstract int getChildCount(Element elem);
187:
188: public abstract int getChildIndex(Element parent, Element child);
189:
190: public native String getElementAttribute(Element elem, String attr) /*-{
191: var ret = elem.getAttribute(attr);
192: return (ret == null) ? null : ret;
193: }-*/;
194:
195: public native Element getElementById(String id) /*-{
196: return $doc.getElementById(id) || null;
197: }-*/;
198:
199: public native String getElementProperty(Element elem, String prop) /*-{
200: var ret = elem[prop];
201: return (ret == null) ? null : String(ret);
202: }-*/;
203:
204: public native boolean getElementPropertyBoolean(Element elem,
205: String prop) /*-{
206: return !!elem[prop];
207: }-*/;
208:
209: public native int getElementPropertyInt(Element elem, String prop) /*-{
210: return parseInt(elem[prop]) || 0;
211: }-*/;
212:
213: public native int getEventsSunk(Element elem) /*-{
214: return elem.__eventBits || 0;
215: }-*/;
216:
217: public abstract Element getFirstChild(Element elem);
218:
219: public native String getImgSrc(Element img) /*-{
220: return img.src;
221: }-*/;
222:
223: public native String getInnerHTML(Element elem) /*-{
224: var ret = elem.innerHTML;
225: return (ret == null) ? null : ret;
226: }-*/;
227:
228: public native String getInnerText(Element node) /*-{
229: // To mimic IE's 'innerText' property in the W3C DOM, we need to recursively
230: // concatenate all child text nodes (depth first).
231: var text = '', child = node.firstChild;
232: while (child) {
233: // 1 == Element node
234: if (child.nodeType == 1) {
235: text += this.@com.google.gwt.user.client.impl.DOMImpl::getInnerText(Lcom/google/gwt/user/client/Element;)(child);
236: } else if (child.nodeValue) {
237: text += child.nodeValue;
238: }
239: child = child.nextSibling;
240: }
241: return text;
242: }-*/;
243:
244: public native int getIntStyleAttribute(Element elem, String attr) /*-{
245: return parseInt(elem.style[attr]) || 0;
246: }-*/;
247:
248: public abstract Element getNextSibling(Element elem);
249:
250: public abstract Element getParent(Element elem);
251:
252: public native String getStyleAttribute(Element elem, String attr) /*-{
253: var ret = elem.style[attr];
254: return (ret == null) ? null : ret;
255: }-*/;
256:
257: public native void insertBefore(Element parent, Element child,
258: Element before) /*-{
259: parent.insertBefore(child, before);
260: }-*/;
261:
262: public abstract void insertChild(Element parent, Element child,
263: int index);
264:
265: /**
266: * @see com.google.gwt.user.client.DOM#insertListItem(Element, String, String,
267: * int)
268: */
269: public native void insertListItem(Element select, String item,
270: String value, int index) /*-{
271: var option = new $wnd.Option(item, value);
272: if (index == -1 || index > select.options.length - 1) {
273: select.add(option, null);
274: } else {
275: select.add(option, select.options[index]);
276: }
277: }-*/;
278:
279: public abstract boolean isOrHasChild(Element parent, Element child);
280:
281: public abstract void releaseCapture(Element elem);
282:
283: public native void removeChild(Element parent, Element child) /*-{
284: parent.removeChild(child);
285: }-*/;
286:
287: public native void removeElementAttribute(Element elem, String attr) /*-{
288: elem.removeAttribute(attr);
289: }-*/;
290:
291: public native void scrollIntoView(Element elem) /*-{
292: var left = elem.offsetLeft, top = elem.offsetTop;
293: var width = elem.offsetWidth, height = elem.offsetHeight;
294:
295: if (elem.parentNode != elem.offsetParent) {
296: left -= elem.parentNode.offsetLeft;
297: top -= elem.parentNode.offsetTop;
298: }
299:
300: var cur = elem.parentNode;
301: while (cur && (cur.nodeType == 1)) {
302: // body tags are implicitly scrollable
303: if ((cur.style.overflow == 'auto') || (cur.style.overflow == 'scroll') ||
304: (cur.tagName == 'BODY')) {
305:
306: if (left < cur.scrollLeft) {
307: cur.scrollLeft = left;
308: }
309: if (left + width > cur.scrollLeft + cur.clientWidth) {
310: cur.scrollLeft = (left + width) - cur.clientWidth;
311: }
312: if (top < cur.scrollTop) {
313: cur.scrollTop = top;
314: }
315: if (top + height > cur.scrollTop + cur.clientHeight) {
316: cur.scrollTop = (top + height) - cur.clientHeight;
317: }
318: }
319:
320: var offsetLeft = cur.offsetLeft, offsetTop = cur.offsetTop;
321: if (cur.parentNode != cur.offsetParent) {
322: offsetLeft -= cur.parentNode.offsetLeft;
323: offsetTop -= cur.parentNode.offsetTop;
324: }
325:
326: left += offsetLeft - cur.scrollLeft;
327: top += offsetTop - cur.scrollTop;
328: cur = cur.parentNode;
329: }
330: }-*/;
331:
332: public abstract void setCapture(Element elem);
333:
334: public native void setElementAttribute(Element elem, String attr,
335: String value) /*-{
336: elem.setAttribute(attr, value);
337: }-*/;
338:
339: public native void setElementProperty(Element elem, String prop,
340: String value) /*-{
341: elem[prop] = value;
342: }-*/;
343:
344: public native void setElementPropertyBoolean(Element elem,
345: String prop, boolean value) /*-{
346: elem[prop] = value;
347: }-*/;
348:
349: public native void setElementPropertyInt(Element elem, String prop,
350: int value) /*-{
351: elem[prop] = value;
352: }-*/;
353:
354: public native void setEventListener(Element elem,
355: EventListener listener) /*-{
356: elem.__listener = listener;
357: }-*/;
358:
359: public native void setImgSrc(Element img, String src) /*-{
360: img.src = src;
361: }-*/;
362:
363: public native void setInnerHTML(Element elem, String html) /*-{
364: if (!html) {
365: html = '';
366: }
367: elem.innerHTML = html;
368: }-*/;
369:
370: public native void setInnerText(Element elem, String text) /*-{
371: // Remove all children first.
372: while (elem.firstChild) {
373: elem.removeChild(elem.firstChild);
374: }
375: // Add a new text node.
376: if (text != null) {
377: elem.appendChild($doc.createTextNode(text));
378: }
379: }-*/;
380:
381: public native void setIntStyleAttribute(Element elem, String attr,
382: int value) /*-{
383: elem.style[attr] = value;
384: }-*/;
385:
386: public native void setOptionText(Element select, String text,
387: int index) /*-{
388: // IE doesn't properly update the screen when you use
389: // setAttribute("option", text), so we instead directly assign to the
390: // 'option' property, which works correctly on all browsers.
391: var option = select.options[index];
392: option.text = text;
393: }-*/;
394:
395: public native void setStyleAttribute(Element elem, String attr,
396: String value) /*-{
397: elem.style[attr] = value;
398: }-*/;
399:
400: public abstract void sinkEvents(Element elem, int eventBits);
401:
402: public native String toString(Element elem) /*-{
403: return elem.outerHTML;
404: }-*/;
405:
406: /**
407: * Gets the height of the browser window's client area excluding the scroll
408: * bar.
409: *
410: * @return the window's client height
411: */
412: public abstract int windowGetClientHeight();
413:
414: /**
415: * Gets the width of the browser window's client area excluding the vertical
416: * scroll bar.
417: *
418: * @return the window's client width
419: */
420: public abstract int windowGetClientWidth();
421:
422: /**
423: * Initializes the event dispatch system.
424: */
425: protected abstract void initEventSystem();
426:
427: /**
428: * Initialize the event system if it has not already been initialized.
429: */
430: protected void maybeInitializeEventSystem() {
431: if (!eventSystemIsInitialized) {
432: initEventSystem();
433: eventSystemIsInitialized = true;
434: }
435: }
436: }
|