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 }