1 /**********************************************
2 * Copyright (C) 2010 Lukas Laag
3 * This file is part of lib-gwt-svg.
4 *
5 * libgwtsvg is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * libgwtsvg is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with libgwtsvg. If not, see http://www.gnu.org/licenses/
17 **********************************************/
18 /*
19 * Copyright (c) 2004 World Wide Web Consortium,
20 *
21 * (Massachusetts Institute of Technology, European Research Consortium for
22 * Informatics and Mathematics, Keio University). All Rights Reserved. This
23 * work is distributed under the W3C(r) Software License [1] in the hope that
24 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
25 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26 *
27 * [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
28 */
29 package org.vectomatic.dom.svg;
30
31 import org.vectomatic.dom.svg.impl.DOMEventBus;
32 import org.vectomatic.dom.svg.utils.DOMHelper;
33 import org.w3c.dom.DOMException;
34
35 import com.google.gwt.core.client.JavaScriptException;
36 import com.google.gwt.core.client.JavaScriptObject;
37 import com.google.gwt.dom.client.Document;
38 import com.google.gwt.dom.client.NativeEvent;
39 import com.google.gwt.dom.client.Node;
40 import com.google.gwt.event.dom.client.DomEvent;
41 import com.google.gwt.event.shared.EventBus;
42 import com.google.gwt.event.shared.EventHandler;
43 import com.google.gwt.event.shared.GwtEvent;
44 import com.google.gwt.event.shared.HandlerRegistration;
45 import com.google.gwt.event.shared.HasHandlers;
46 import com.google.gwt.event.shared.UmbrellaException;
47 import com.google.gwt.user.client.Element;
48
49 /**
50 * Wrapper class for DOM Node. Wrapper classes decorate native
51 * DOM objects with java-like capabilities: capability to implement
52 * interfaces, notably event handler interfaces.
53 * @author laaglu
54 * @author Michael Allan
55 */
56 public class OMNode implements HasHandlers {
57 /**
58 * The DOM native overlay type wrapped by this object
59 */
60 protected final Node ot;
61 /**
62 * The event bus shared by all SVG objects
63 */
64 static protected EventBus eventBus = new DOMEventBus();
65
66 /**
67 * Constructor
68 * @param node The node to wrap
69 */
70 protected OMNode(Node node) {
71 assert getWrapper(node) == null : "node was already wrapped";
72 setWrapper(node, this);
73 this.ot = node;
74 }
75
76 /**
77 * Sets the __wrapper property of the node.
78 */
79 private static native void setWrapper(Node node, OMNode wrapper) /*-{
80 node.__wrapper = wrapper;
81 }-*/;
82
83 /**
84 * Returns the __wrapper property of the node.
85 */
86 private static native OMNode getWrapper(Node node) /*-{
87 return node.__wrapper;
88 }-*/;
89
90 /**
91 * Cleanup method for wrapper objects which are
92 * not needed by the application any more. It
93 * breaks the back-reference the native DOM object
94 * maintains on this wrapper type, in order to
95 * facilitate garbage collection. Use only if
96 * your code needs to run in a browser which is
97 * not equipped with an automatic DOM object-native
98 * object cycle collector.
99 */
100 public void cleanup() {
101 setWrapper(ot, null);
102 }
103
104 /**
105 * Returns the event bus shared by all SVG objects
106 * @return the event bus shared by all SVG objects
107 */
108 public static EventBus getEventBus() {
109 return eventBus;
110 }
111 /**
112 * Fires the given event to the handlers listening to the event's type.
113 * <p>
114 * Any exceptions thrown by handlers will be bundled into a
115 * {@link UmbrellaException} and then re-thrown after all handlers have
116 * completed. An exception thrown by a handler will not prevent other handlers
117 * from executing.
118 * @param event the event
119 */
120 public void fireEvent(GwtEvent<?> event) {
121 revive(event);
122 eventBus.fireEventFromSource(event, this);
123 }
124 /**
125 * Revive the event. GWT does it by taking advantage of the
126 * fact that HandlerManager has package access to GwtEvent.
127 * Here we use a JSNI call to bypass scope restrictions
128 */
129 private static final native void revive(GwtEvent<?> event) /*-{
130 event.@com.google.gwt.event.shared.GwtEvent::revive()();
131 }-*/;
132
133 /**
134 * Dispatches the specified event to this node
135 * event handlers
136 * @param event The event to dispatch
137 */
138 public void dispatch(NativeEvent event) {
139 // This call wraps the native event into a DomEvent
140 // and invokes fireEvent
141 DomEvent.fireNativeEvent(event, this, (Element)event.getCurrentEventTarget().cast());
142 }
143
144 /**
145 * Adds a DOM handler to this node's list of handlers
146 * @param <H> The handler type
147 * @param handler The DOM handler
148 * @param type The event type
149 * @return {@link HandlerRegistration} used to remove this handler
150 */
151 public final <H extends EventHandler> HandlerRegistration addDomHandler(
152 final H handler, DomEvent.Type<H> type) {
153 assert handler != null : "handler must not be null";
154 assert type != null : "type must not be null";
155 DOMHelper.bindEventListener((Element)ot.cast(), type.getName());
156 return eventBus.addHandlerToSource(type, this, handler);
157 }
158
159 /**
160 * Adds a handler to this node's list of handlers
161 * @param <H> The handler type
162 * @param handler The handler
163 * @param type The event type
164 * @return {@link HandlerRegistration} used to remove this handler
165 */
166 public final <H extends EventHandler> HandlerRegistration addHandler(
167 final H handler, GwtEvent.Type<H> type) {
168 return eventBus.addHandlerToSource(type, this, handler);
169 }
170
171 private static class Conversion<T extends OMNode> {
172 static {
173 initialize();
174 }
175 private static final native void initialize() /*-{
176 if ($wnd.otToWrapper == null) {
177 $wnd.otToWrapper = new Object();
178 }
179 $wnd.otToWrapper["SVGAElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAElement::new(Lorg/vectomatic/dom/svg/impl/SVGAElement;)(elem); };
180 $wnd.otToWrapper["SVGAltGlyphDefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphDefElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphDefElement;)(elem); };
181 $wnd.otToWrapper["SVGAltGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphElement;)(elem); };
182 $wnd.otToWrapper["SVGAltGlyphItemElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphItemElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphItemElement;)(elem); };
183 $wnd.otToWrapper["SVGAnimateColorElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateColorElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateColorElement;)(elem); };
184 $wnd.otToWrapper["SVGAnimateElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateElement;)(elem); };
185 $wnd.otToWrapper["SVGAnimateMotionElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateMotionElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateMotionElement;)(elem); };
186 $wnd.otToWrapper["SVGAnimateTransformElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateTransformElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateTransformElement;)(elem); };
187 $wnd.otToWrapper["SVGCircleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGCircleElement::new(Lorg/vectomatic/dom/svg/impl/SVGCircleElement;)(elem); };
188 $wnd.otToWrapper["SVGClipPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGClipPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGClipPathElement;)(elem); };
189 $wnd.otToWrapper["SVGColorProfileElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGColorProfileElement::new(Lorg/vectomatic/dom/svg/impl/SVGColorProfileElement;)(elem); };
190 $wnd.otToWrapper["SVGCursorElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGCursorElement::new(Lorg/vectomatic/dom/svg/impl/SVGCursorElement;)(elem); };
191 $wnd.otToWrapper["SVGDefsElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDefsElement::new(Lorg/vectomatic/dom/svg/impl/SVGDefsElement;)(elem); };
192 $wnd.otToWrapper["SVGDescElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDescElement::new(Lorg/vectomatic/dom/svg/impl/SVGDescElement;)(elem); };
193 $wnd.otToWrapper["SVGDocument"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDocument::new(Lorg/vectomatic/dom/svg/impl/SVGDocument;)(elem); };
194 $wnd.otToWrapper["SVGEllipseElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGEllipseElement::new(Lorg/vectomatic/dom/svg/impl/SVGEllipseElement;)(elem); };
195 $wnd.otToWrapper["SVGFEBlendElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEBlendElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEBlendElement;)(elem); };
196 $wnd.otToWrapper["SVGFEColorMatrixElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEColorMatrixElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEColorMatrixElement;)(elem); };
197 $wnd.otToWrapper["SVGFEComponentTransferElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEComponentTransferElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEComponentTransferElement;)(elem); };
198 $wnd.otToWrapper["SVGFECompositeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFECompositeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFECompositeElement;)(elem); };
199 $wnd.otToWrapper["SVGFEConvolveMatrixElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEConvolveMatrixElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEConvolveMatrixElement;)(elem); };
200 $wnd.otToWrapper["SVGFEDiffuseLightingElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDiffuseLightingElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDiffuseLightingElement;)(elem); };
201 $wnd.otToWrapper["SVGFEDisplacementMapElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDisplacementMapElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDisplacementMapElement;)(elem); };
202 $wnd.otToWrapper["SVGFEDistantLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDistantLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDistantLightElement;)(elem); };
203 $wnd.otToWrapper["SVGFEFloodElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFloodElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFloodElement;)(elem); };
204 $wnd.otToWrapper["SVGFEFuncAElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncAElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncAElement;)(elem); };
205 $wnd.otToWrapper["SVGFEFuncBElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncBElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncBElement;)(elem); };
206 $wnd.otToWrapper["SVGFEFuncGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncGElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncGElement;)(elem); };
207 $wnd.otToWrapper["SVGFEFuncRElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncRElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncRElement;)(elem); };
208 $wnd.otToWrapper["SVGFEGaussianBlurElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEGaussianBlurElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEGaussianBlurElement;)(elem); };
209 $wnd.otToWrapper["SVGFEImageElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEImageElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEImageElement;)(elem); };
210 $wnd.otToWrapper["SVGFEMergeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMergeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMergeElement;)(elem); };
211 $wnd.otToWrapper["SVGFEMergeNodeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMergeNodeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMergeNodeElement;)(elem); };
212 $wnd.otToWrapper["SVGFEMorphologyElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMorphologyElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMorphologyElement;)(elem); };
213 $wnd.otToWrapper["SVGFEOffsetElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEOffsetElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEOffsetElement;)(elem); };
214 $wnd.otToWrapper["SVGFEPointLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEPointLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEPointLightElement;)(elem); };
215 $wnd.otToWrapper["SVGFESpecularLightingElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFESpecularLightingElement::new(Lorg/vectomatic/dom/svg/impl/SVGFESpecularLightingElement;)(elem); };
216 $wnd.otToWrapper["SVGFESpotLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFESpotLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFESpotLightElement;)(elem); };
217 $wnd.otToWrapper["SVGFETileElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFETileElement::new(Lorg/vectomatic/dom/svg/impl/SVGFETileElement;)(elem); };
218 $wnd.otToWrapper["SVGFETurbulenceElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFETurbulenceElement::new(Lorg/vectomatic/dom/svg/impl/SVGFETurbulenceElement;)(elem); };
219 $wnd.otToWrapper["SVGFilterElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFilterElement::new(Lorg/vectomatic/dom/svg/impl/SVGFilterElement;)(elem); };
220 $wnd.otToWrapper["SVGFontElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontElement;)(elem); };
221 $wnd.otToWrapper["SVGFontFaceElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceElement;)(elem); };
222 $wnd.otToWrapper["SVGFontFaceFormatElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceFormatElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceFormatElement;)(elem); };
223 $wnd.otToWrapper["SVGFontFaceNameElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceNameElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceNameElement;)(elem); };
224 $wnd.otToWrapper["SVGFontFaceSrcElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceSrcElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceSrcElement;)(elem); };
225 $wnd.otToWrapper["SVGFontFaceUriElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceUriElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceUriElement;)(elem); };
226 $wnd.otToWrapper["SVGForeignObjectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGForeignObjectElement::new(Lorg/vectomatic/dom/svg/impl/SVGForeignObjectElement;)(elem); };
227 $wnd.otToWrapper["SVGGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGElement::new(Lorg/vectomatic/dom/svg/impl/SVGGElement;)(elem); };
228 $wnd.otToWrapper["SVGGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGGlyphElement;)(elem); };
229 $wnd.otToWrapper["SVGGlyphRefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGlyphRefElement::new(Lorg/vectomatic/dom/svg/impl/SVGGlyphRefElement;)(elem); };
230 $wnd.otToWrapper["SVGHKernElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGHKernElement::new(Lorg/vectomatic/dom/svg/impl/SVGHKernElement;)(elem); };
231 $wnd.otToWrapper["SVGImageElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGImageElement::new(Lorg/vectomatic/dom/svg/impl/SVGImageElement;)(elem); };
232 $wnd.otToWrapper["SVGLinearGradientElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLinearGradientElement::new(Lorg/vectomatic/dom/svg/impl/SVGLinearGradientElement;)(elem); };
233 $wnd.otToWrapper["SVGLineElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLineElement::new(Lorg/vectomatic/dom/svg/impl/SVGLineElement;)(elem); };
234 $wnd.otToWrapper["SVGMarkerElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMarkerElement::new(Lorg/vectomatic/dom/svg/impl/SVGMarkerElement;)(elem); };
235 $wnd.otToWrapper["SVGMaskElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMaskElement::new(Lorg/vectomatic/dom/svg/impl/SVGMaskElement;)(elem); };
236 $wnd.otToWrapper["SVGMetadataElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMetadataElement::new(Lorg/vectomatic/dom/svg/impl/SVGMetadataElement;)(elem); };
237 $wnd.otToWrapper["SVGMissingGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMissingGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGMissingGlyphElement;)(elem); };
238 $wnd.otToWrapper["SVGMPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGMPathElement;)(elem); };
239 $wnd.otToWrapper["SVGPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGPathElement;)(elem); };
240 $wnd.otToWrapper["SVGPatternElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPatternElement::new(Lorg/vectomatic/dom/svg/impl/SVGPatternElement;)(elem); };
241 $wnd.otToWrapper["SVGPolygonElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPolygonElement::new(Lorg/vectomatic/dom/svg/impl/SVGPolygonElement;)(elem); };
242 $wnd.otToWrapper["SVGPolylineElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPolylineElement::new(Lorg/vectomatic/dom/svg/impl/SVGPolylineElement;)(elem); };
243 $wnd.otToWrapper["SVGRadialGradientElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRadialGradientElement::new(Lorg/vectomatic/dom/svg/impl/SVGRadialGradientElement;)(elem); };
244 $wnd.otToWrapper["SVGRectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRectElement::new(Lorg/vectomatic/dom/svg/impl/SVGRectElement;)(elem); };
245 $wnd.otToWrapper["SVGRectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRectElement::new(Lorg/vectomatic/dom/svg/impl/SVGRectElement;)(elem); };
246 $wnd.otToWrapper["SVGScriptElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGScriptElement::new(Lorg/vectomatic/dom/svg/impl/SVGScriptElement;)(elem); };
247 $wnd.otToWrapper["SVGSetElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSetElement::new(Lorg/vectomatic/dom/svg/impl/SVGSetElement;)(elem); };
248 $wnd.otToWrapper["SVGStopElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStopElement::new(Lorg/vectomatic/dom/svg/impl/SVGStopElement;)(elem); };
249 $wnd.otToWrapper["SVGStyleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStyleElement::new(Lorg/vectomatic/dom/svg/impl/SVGStyleElement;)(elem); };
250 $wnd.otToWrapper["SVGSVGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSVGElement::new(Lorg/vectomatic/dom/svg/impl/SVGSVGElement;)(elem); };
251 $wnd.otToWrapper["SVGSwitchElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSwitchElement::new(Lorg/vectomatic/dom/svg/impl/SVGSwitchElement;)(elem); };
252 $wnd.otToWrapper["SVGSymbolElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSymbolElement::new(Lorg/vectomatic/dom/svg/impl/SVGSymbolElement;)(elem); };
253 $wnd.otToWrapper["SVGTextElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTextElement::new(Lorg/vectomatic/dom/svg/impl/SVGTextElement;)(elem); };
254 $wnd.otToWrapper["SVGTextPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTextPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGTextPathElement;)(elem); };
255 $wnd.otToWrapper["SVGTitleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTitleElement::new(Lorg/vectomatic/dom/svg/impl/SVGTitleElement;)(elem); };
256 $wnd.otToWrapper["SVGTRefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTRefElement::new(Lorg/vectomatic/dom/svg/impl/SVGTRefElement;)(elem); };
257 $wnd.otToWrapper["SVGTSpanElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTSpanElement::new(Lorg/vectomatic/dom/svg/impl/SVGTSpanElement;)(elem); };
258 $wnd.otToWrapper["SVGUseElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGUseElement::new(Lorg/vectomatic/dom/svg/impl/SVGUseElement;)(elem); };
259 $wnd.otToWrapper["SVGViewElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGViewElement::new(Lorg/vectomatic/dom/svg/impl/SVGViewElement;)(elem); };
260 $wnd.otToWrapper["SVGVKernElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGVKernElement::new(Lorg/vectomatic/dom/svg/impl/SVGVKernElement;)(elem); };
261 }-*/;
262 T result;
263 Conversion(Node node) {
264 convert(node);
265 }
266 private final native void convert(Node node) /*-{
267 var wrapper = null;
268 if (node != null) {
269 var type = @org.vectomatic.dom.svg.utils.DOMHelper::getType(Lcom/google/gwt/core/client/JavaScriptObject;)(node);
270 if (type) {
271 var ctor = $wnd.otToWrapper[type];
272 if (ctor != null) {
273 wrapper = ctor(node);
274 } else {
275 if (node.nodeType == 1) {
276 wrapper = @org.vectomatic.dom.svg.OMElement::new(Lcom/google/gwt/dom/client/Element;)(node);
277 } else if (node.nodeType == 2) {
278 wrapper = @org.vectomatic.dom.svg.OMAttr::new(Lorg/vectomatic/dom/svg/impl/Attr;)(node);
279 } else if (node.nodeType == 3) {
280 wrapper = @org.vectomatic.dom.svg.OMText::new(Lcom/google/gwt/dom/client/Text;)(node);
281 } else if (node.nodeType == 9) {
282 wrapper = @org.vectomatic.dom.svg.OMSVGDocument::new(Lorg/vectomatic/dom/svg/impl/SVGDocument;)(node);
283 } else {
284 wrapper = @org.vectomatic.dom.svg.OMNode::new(Lcom/google/gwt/dom/client/Node;)(node);
285 }
286 }
287 }
288 }
289 this.@org.vectomatic.dom.svg.OMNode.Conversion::result = wrapper;
290 }-*/;
291 }
292
293 /**
294 * Returns the wrapper for the specified overlay type node, automatically constructing
295 * a new wrapper if the node was previously unwrapped.
296 * @param <T> the node type
297 * @param obj The overlay type node
298 * @return The node wrapper
299 */
300 public static <T extends OMNode> T convert(Node obj) {
301 // Misleading to parametize by T here, because we cannot guarantee type safety.
302 // The explicit cast below is liable to failure, and so is the implicit cast in
303 // Conversion. Instead we might try overloading the convert methods, as with a
304 // convert(Element) that safely casts to OMElement. (Later)
305 @SuppressWarnings("unchecked") T wrapper = (T)getWrapper(obj);
306 if (wrapper == null) wrapper = new Conversion<T>(obj).result;
307 return wrapper;
308 }
309
310 private static class ListConversion<T extends Iterable<? extends OMNode>> {
311 static {
312 initialize();
313 }
314 private static final native void initialize() /*-{
315 if ($wnd.otToWrapper == null) {
316 $wnd.otToWrapper = new Object();
317 }
318 $wnd.otToWrapper["NodeList"] = function(elem) { return @org.vectomatic.dom.svg.OMNodeList::new(Lcom/google/gwt/dom/client/NodeList;)(elem); };
319 $wnd.otToWrapper["SVGLengthList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLengthList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
320 $wnd.otToWrapper["SVGNumberList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGNumberList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
321 $wnd.otToWrapper["SVGPathSegList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPathSegList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
322 $wnd.otToWrapper["SVGPointList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPointList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
323 $wnd.otToWrapper["SVGStringList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStringList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
324 $wnd.otToWrapper["SVGTransformList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTransformList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
325 }-*/;
326 T result;
327 ListConversion(JavaScriptObject list) {
328 convert(list);
329 }
330 private final native void convert(JavaScriptObject list) /*-{
331 var wrapper = null;
332 var type = @org.vectomatic.dom.svg.utils.DOMHelper::getType(Lcom/google/gwt/core/client/JavaScriptObject;)(list);
333 if (type) {
334 var ctor = $wnd.otToWrapper[type];
335 if (ctor != null) {
336 wrapper = ctor(list);
337 }
338 }
339 this.@org.vectomatic.dom.svg.OMNode.ListConversion::result = wrapper;
340 }-*/;
341 }
342
343 /**
344 * Generates a wrapper around an overlay type list
345 * @param <T> the list type
346 * @param obj The overlay type list
347 * @return The list wrapper
348 */
349 public static <T extends Iterable<? extends OMNode>> T convertList(JavaScriptObject obj) {
350 return new ListConversion<T>(obj).result;
351 }
352
353 /**
354 * Returns the wrapped node
355 * @return the wrapped node
356 */
357 public Node getNode() {
358 return ot;
359 }
360
361 // Implementation of the dom::Node W3C IDL interface
362 /**
363 * The name of this node, depending on its type.
364 * @return name of this node
365 */
366 public final String getNodeName() {
367 return ot.getNodeName();
368 }
369
370 /**
371 * The value of this node, depending on its type.
372 * When it is defined to be <code>null</code>, setting it has no effect,
373 * including if the node is read-only.
374 */
375 public final String getNodeValue() {
376 return ot.getNodeValue();
377 }
378
379 /**
380 * The value of this node, depending on its type; see the table above.
381 * When it is defined to be <code>null</code>, setting it has no effect,
382 * including if the node is read-only.
383 * @param value The node value
384 * @exception DOMException
385 * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly and if
386 * it is not defined to be <code>null</code>.
387 */
388 public final void setNodeValue(String value) throws JavaScriptException {
389 ot.setNodeValue(value);
390 }
391
392 /**
393 * A code representing the type of the underlying object.
394 * @return A code representing the type of the underlying object
395 */
396 public final short getNodeType() {
397 return ot.getNodeType();
398 }
399
400 /**
401 * The parent of this node. All nodes, except <code>OMAttr</code>,
402 * <code>OMDocument</code> may have a parent.
403 * However, if a node has just been created and not yet added to the
404 * tree, or if it has been removed from the tree, this is
405 * <code>null</code>.
406 * @return The parent of this node
407 */
408 public final OMNode getParentNode() {
409 Node parentNode = ot.getParentNode();
410 return (parentNode != null) ? convert(parentNode) : null;
411 }
412
413 /**
414 * A <code>OMNodeList</code> that contains all children of this node. If
415 * there are no children, this is a <code>OMNodeList</code> containing no
416 * nodes.
417 * @return A <code>OMNodeList</code> that contains all children of this node. If
418 */
419 public final <T extends OMNode> OMNodeList<T> getChildNodes() {
420 return new OMNodeList<T>(ot.getChildNodes());
421 }
422
423 /**
424 * The first child of this node. If there is no such node, this returns
425 * <code>null</code>.
426 * @return The first child of this node.
427 */
428 public final OMNode getFirstChild() {
429 Node firstChild = ot.getFirstChild();
430 return (firstChild != null) ? convert(firstChild) : null;
431 }
432
433 /**
434 * The last child of this node. If there is no such node, this returns
435 * <code>null</code>.
436 * @return The last child of this node.
437 */
438 public final OMNode getLastChild() {
439 Node lastChild = ot.getLastChild();
440 return (lastChild != null) ? convert(lastChild) : null;
441 }
442
443 /**
444 * Returns the local part of the qualified name of this node.
445 * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and
446 * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1
447 * method, such as <code>Document.createElement()</code>, this is always
448 * <code>null</code>.
449 * @return The local part of the qualified name of this node
450 */
451 public final String getLocalName() {
452 return DOMHelper.getLocalName(ot);
453 }
454
455 /**
456 * The node immediately preceding this node. If there is no such node,
457 * this returns <code>null</code>.
458 * @return The node immediately preceding this node.
459 */
460 public final OMNode getPreviousSibling() {
461 Node previousSibling = ot.getPreviousSibling();
462 return (previousSibling != null) ? convert(previousSibling) : null;
463 }
464
465 /**
466 * The namespace URI of the specified node, or <code>null</code> if it is
467 * unspecified (see ).
468 * <br>This is not a computed value that is the result of a namespace
469 * lookup based on an examination of the namespace declarations in
470 * scope. It is merely the namespace URI given at creation time.
471 * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and
472 * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1
473 * method, such as <code>Document.createElement()</code>, this is always
474 * <code>null</code>.
475 * <p ><b>Note:</b> Per the <em>Namespaces in XML</em> Specification [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
476 * an attribute does not inherit its namespace from the element it is
477 * attached to. If an attribute is not explicitly given a namespace, it
478 * simply has no namespace.
479 * @return The namespace URI of this node
480 */
481 public String getNamespaceURI() {
482 return DOMHelper.getNamespaceURI(ot);
483 }
484 /**
485 * The node immediately following this node. If there is no such node,
486 * this returns <code>null</code>.
487 * @return The node immediately following this node.
488 */
489 public final OMNode getNextSibling() {
490 Node nextSibling = ot.getNextSibling();
491 return (nextSibling != null) ? convert(nextSibling) : null;
492 }
493
494 /**
495 * The <code>OMDocument</code> object associated with this node. This is
496 * also the <code>OMDocument</code> object used to create new nodes. When
497 * this node is a <code>OMNode</code>
498 * which is not used with any <code>OMDocument</code> yet, this is
499 * <code>null</code>.
500 * @return The <code>OMDocument</code> object associated with this node.
501 */
502 public final OMDocument getOwnerDocument() {
503 Document document = ot.getOwnerDocument();
504 return (document != null) ? (OMDocument)convert(document) : null;
505 }
506
507 /**
508 * Inserts the node <code>newChild</code> before the existing child node
509 * <code>refChild</code>. If <code>refChild</code> is <code>null</code>,
510 * insert <code>newChild</code> at the end of the list of children.
511 * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object,
512 * all of its children are inserted, in the same order, before
513 * <code>refChild</code>. If the <code>newChild</code> is already in the
514 * tree, it is first removed.
515 * <p ><b>Note:</b> Inserting a node before itself is implementation
516 * dependent.
517 * @param newChild The node to insert.
518 * @param refChild The reference node, i.e., the node before which the
519 * new node must be inserted.
520 * @return The node being inserted.
521 * @exception DOMException
522 * HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not
523 * allow children of the type of the <code>newChild</code> node, or if
524 * the node to insert is one of this node's ancestors or this node
525 * itself, or if this node is of type <code>Document</code> and the
526 * DOM application attempts to insert a second
527 * <code>DocumentType</code> or <code>Element</code> node.
528 * <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created
529 * from a different document than the one that created this node.
530 * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or
531 * if the parent of the node being inserted is readonly.
532 * <br>NOT_FOUND_ERR: Raised if <code>refChild</code> is not a child of
533 * this node.
534 * <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>,
535 * this exception might be raised if the DOM implementation doesn't
536 * support the insertion of a <code>DocumentType</code> or
537 * <code>Element</code> node.
538 */
539 public final OMNode insertBefore(OMNode newChild, OMNode refChild) throws JavaScriptException {
540 ot.insertBefore(newChild.ot, refChild != null ? refChild.ot : null);
541 return newChild;
542 }
543
544 /**
545 * Replaces the child node <code>oldChild</code> with <code>newChild</code>
546 * in the list of children, and returns the <code>oldChild</code> node.
547 * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object,
548 * <code>oldChild</code> is replaced by all of the
549 * <code>DocumentFragment</code> children, which are inserted in the
550 * same order. If the <code>newChild</code> is already in the tree, it
551 * is first removed.
552 * <p ><b>Note:</b> Replacing a node with itself is implementation
553 * dependent.
554 * @param newChild The new node to put in the child list.
555 * @param oldChild The node being replaced in the list.
556 * @return The node replaced.
557 * @exception DOMException
558 * HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not
559 * allow children of the type of the <code>newChild</code> node, or if
560 * the node to put in is one of this node's ancestors or this node
561 * itself, or if this node is of type <code>Document</code> and the
562 * result of the replacement operation would add a second
563 * <code>DocumentType</code> or <code>Element</code> on the
564 * <code>Document</code> node.
565 * <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created
566 * from a different document than the one that created this node.
567 * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node or the parent of
568 * the new node is readonly.
569 * <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of
570 * this node.
571 * <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>,
572 * this exception might be raised if the DOM implementation doesn't
573 * support the replacement of the <code>DocumentType</code> child or
574 * <code>Element</code> child.
575 */
576 public final OMNode replaceChild(OMNode newChild, OMNode oldChild) throws JavaScriptException {
577 ot.replaceChild(newChild.ot, oldChild.ot);
578 return oldChild;
579 }
580
581 /**
582 * Removes the child node indicated by <code>oldChild</code> from the list
583 * of children, and returns it.
584 * @param oldChild The node being removed.
585 * @return The node removed.
586 * @exception DOMException
587 * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
588 * <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of
589 * this node.
590 * <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>,
591 * this exception might be raised if the DOM implementation doesn't
592 * support the removal of the <code>DocumentType</code> child or the
593 * <code>Element</code> child.
594 */
595 public final OMNode removeChild(OMNode oldChild) throws JavaScriptException {
596 ot.removeChild(oldChild.ot);
597 return oldChild;
598 }
599
600 /**
601 * Adds the node <code>newChild</code> to the end of the list of children
602 * of this node. If the <code>newChild</code> is already in the tree, it
603 * is first removed.
604 * @param newChild The node to add.If it is a
605 * <code>DocumentFragment</code> object, the entire contents of the
606 * document fragment are moved into the child list of this node
607 * @return The node added.
608 * @exception DOMException
609 * HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not
610 * allow children of the type of the <code>newChild</code> node, or if
611 * the node to append is one of this node's ancestors or this node
612 * itself, or if this node is of type <code>Document</code> and the
613 * DOM application attempts to append a second
614 * <code>DocumentType</code> or <code>Element</code> node.
615 * <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created
616 * from a different document than the one that created this node.
617 * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or
618 * if the previous parent of the node being inserted is readonly.
619 * <br>NOT_SUPPORTED_ERR: if the <code>newChild</code> node is a child
620 * of the <code>Document</code> node, this exception might be raised
621 * if the DOM implementation doesn't support the removal of the
622 * <code>DocumentType</code> child or <code>Element</code> child.
623 */
624 public final OMNode appendChild(OMNode newChild) throws JavaScriptException {
625 ot.appendChild(newChild.ot);
626 return newChild;
627 }
628
629 /**
630 * Returns whether this node has any children.
631 * @return Returns <code>true</code> if this node has any children,
632 * <code>false</code> otherwise.
633 */
634 public final boolean hasChildNodes() {
635 return ot.hasChildNodes();
636 }
637
638 /**
639 * Returns a duplicate of this node, i.e., serves as a generic copy
640 * constructor for nodes. The duplicate node has no parent (
641 * <code>parentNode</code> is <code>null</code>) and no user data. User
642 * data associated to the imported node is not carried over. However, if
643 * any <code>UserDataHandlers</code> has been specified along with the
644 * associated data these handlers will be called with the appropriate
645 * parameters before this method returns.
646 * <br>Cloning an <code>Element</code> copies all attributes and their
647 * values, including those generated by the XML processor to represent
648 * defaulted attributes, but this method does not copy any children it
649 * contains unless it is a deep clone. This includes text contained in
650 * an the <code>Element</code> since the text is contained in a child
651 * <code>Text</code> node. Cloning an <code>Attr</code> directly, as
652 * opposed to be cloned as part of an <code>Element</code> cloning
653 * operation, returns a specified attribute (<code>specified</code> is
654 * <code>true</code>). Cloning an <code>Attr</code> always clones its
655 * children, since they represent its value, no matter whether this is a
656 * deep clone or not. Cloning an <code>EntityReference</code>
657 * automatically constructs its subtree if a corresponding
658 * <code>Entity</code> is available, no matter whether this is a deep
659 * clone or not. Cloning any other type of node simply returns a copy of
660 * this node.
661 * <br>Note that cloning an immutable subtree results in a mutable copy,
662 * but the children of an <code>EntityReference</code> clone are readonly
663 * . In addition, clones of unspecified <code>Attr</code> nodes are
664 * specified. And, cloning <code>Document</code>,
665 * <code>DocumentType</code>, <code>Entity</code>, and
666 * <code>Notation</code> nodes is implementation dependent.
667 * @param deep If <code>true</code>, recursively clone the subtree under
668 * the specified node; if <code>false</code>, clone only the node
669 * itself (and its attributes, if it is an <code>Element</code>).
670 * @return The duplicate node.
671 */
672 public final OMNode cloneNode(boolean deep) {
673 return convert(ot.cloneNode(deep));
674 }
675
676 /**
677 * Puts all <code>Text</code> nodes in the full depth of the sub-tree
678 * underneath this <code>Node</code>, including attribute nodes, into a
679 * "normal" form where only structure (e.g., elements, comments,
680 * processing instructions, CDATA sections, and entity references)
681 * separates <code>Text</code> nodes, i.e., there are neither adjacent
682 * <code>Text</code> nodes nor empty <code>Text</code> nodes. This can
683 * be used to ensure that the DOM view of a document is the same as if
684 * it were saved and re-loaded, and is useful when operations (such as
685 * XPointer [<a href='http://www.w3.org/TR/2003/REC-xptr-framework-20030325/'>XPointer</a>]
686 * lookups) that depend on a particular document tree structure are to
687 * be used. If the parameter "normalize-characters" of the
688 * <code>DOMConfiguration</code> object attached to the
689 * <code>Node.ownerDocument</code> is <code>true</code>, this method
690 * will also fully normalize the characters of the <code>Text</code>
691 * nodes.
692 * <p ><b>Note:</b> In cases where the document contains
693 * <code>CDATASections</code>, the normalize operation alone may not be
694 * sufficient, since XPointers do not differentiate between
695 * <code>Text</code> nodes and <code>CDATASection</code> nodes.
696 */
697 public final void normalize() {
698 DOMHelper.normalize(ot);
699 }
700
701 @Override
702 public String toString() {
703 return ot.toString();
704 }
705 }