From e8f5ab2311db093dc79ef15201c4802238760f91 Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Fri, 10 Jan 2014 12:55:59 -0500 Subject: [PATCH] Fix issue with SVGElementInstance --- build.json | 3 + shadowdom.js | 3 + src/wrappers.js | 9 ++- src/wrappers/SVGElement.js | 16 +++++ src/wrappers/SVGElementInstance.js | 67 ++++++++++++++++++++ src/wrappers/SVGUseElement.js | 46 ++++++++++++++ test/js/SVGElementInstance.js | 99 ++++++++++++++++++++++++++++++ test/test.main.js | 3 +- 8 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 src/wrappers/SVGElement.js create mode 100644 src/wrappers/SVGElementInstance.js create mode 100644 src/wrappers/SVGUseElement.js create mode 100644 test/js/SVGElementInstance.js diff --git a/build.json b/build.json index 6287b48..922db75 100644 --- a/build.json +++ b/build.json @@ -21,6 +21,9 @@ "src/wrappers/HTMLAudioElement.js", "src/wrappers/HTMLOptionElement.js", "src/wrappers/HTMLUnknownElement.js", + "src/wrappers/SVGElement.js", + "src/wrappers/SVGUseElement.js", + "src/wrappers/SVGElementInstance.js", "src/wrappers/CanvasRenderingContext2D.js", "src/wrappers/WebGLRenderingContext.js", "src/wrappers/Range.js", diff --git a/shadowdom.js b/shadowdom.js index e07d7b8..3ccb75a 100644 --- a/shadowdom.js +++ b/shadowdom.js @@ -37,6 +37,9 @@ 'src/wrappers/HTMLAudioElement.js', 'src/wrappers/HTMLOptionElement.js', 'src/wrappers/HTMLUnknownElement.js', + 'src/wrappers/SVGElement.js', + 'src/wrappers/SVGUseElement.js', + 'src/wrappers/SVGElementInstance.js', 'src/wrappers/CanvasRenderingContext2D.js', 'src/wrappers/WebGLRenderingContext.js', 'src/wrappers/Range.js', diff --git a/src/wrappers.js b/src/wrappers.js index a704015..c4738a4 100644 --- a/src/wrappers.js +++ b/src/wrappers.js @@ -249,12 +249,14 @@ window.ShadowDOMPolyfill = {}; } var OriginalDOMImplementation = window.DOMImplementation; + var OriginalEventTarget = window.EventTarget; var OriginalEvent = window.Event; var OriginalNode = window.Node; var OriginalWindow = window.Window; var OriginalRange = window.Range; var OriginalCanvasRenderingContext2D = window.CanvasRenderingContext2D; var OriginalWebGLRenderingContext = window.WebGLRenderingContext; + var OriginalSVGElementInstance = window.SVGElementInstance; function isWrapper(object) { return object instanceof wrappers.EventTarget || @@ -267,14 +269,17 @@ window.ShadowDOMPolyfill = {}; } function isNative(object) { - return object instanceof OriginalNode || + return OriginalEventTarget && object instanceof OriginalEventTarget || + object instanceof OriginalNode || object instanceof OriginalEvent || object instanceof OriginalWindow || object instanceof OriginalRange || object instanceof OriginalDOMImplementation || object instanceof OriginalCanvasRenderingContext2D || OriginalWebGLRenderingContext && - object instanceof OriginalWebGLRenderingContext; + object instanceof OriginalWebGLRenderingContext || + OriginalSVGElementInstance && + object instanceof OriginalSVGElementInstance; } /** diff --git a/src/wrappers/SVGElement.js b/src/wrappers/SVGElement.js new file mode 100644 index 0000000..1c2a767 --- /dev/null +++ b/src/wrappers/SVGElement.js @@ -0,0 +1,16 @@ +// Copyright 2014 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var registerObject = scope.registerObject; + + var SVG_NS = 'http://www.w3.org/2000/svg'; + var svgTitleElement = document.createElementNS(SVG_NS, 'title'); + var SVGTitleElement = registerObject(svgTitleElement); + var SVGElement = Object.getPrototypeOf(SVGTitleElement.prototype).constructor; + + scope.wrappers.SVGElement = SVGElement; +})(window.ShadowDOMPolyfill); diff --git a/src/wrappers/SVGElementInstance.js b/src/wrappers/SVGElementInstance.js new file mode 100644 index 0000000..bca4719 --- /dev/null +++ b/src/wrappers/SVGElementInstance.js @@ -0,0 +1,67 @@ +// Copyright 2014 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var EventTarget = scope.wrappers.EventTarget; + var mixin = scope.mixin; + var registerWrapper = scope.registerWrapper; + var wrap = scope.wrap; + + var OriginalSVGElementInstance = window.SVGElementInstance; + if (!OriginalSVGElementInstance) + return; + + function SVGElementInstance(impl) { + EventTarget.call(this, impl); + } + + SVGElementInstance.prototype = Object.create(EventTarget.prototype); + mixin(SVGElementInstance.prototype, { + /** @type {SVGElement} */ + get correspondingElement() { + return wrap(this.impl.correspondingElement); + }, + + /** @type {SVGUseElement} */ + get correspondingUseElement() { + return wrap(this.impl.correspondingUseElement); + }, + + /** @type {SVGElementInstance} */ + get parentNode() { + return wrap(this.impl.parentNode); + }, + + /** @type {SVGElementInstanceList} */ + get childNodes() { + throw new Error('Not implemented'); + }, + + /** @type {SVGElementInstance} */ + get firstChild() { + return wrap(this.impl.firstChild); + }, + + /** @type {SVGElementInstance} */ + get lastChild() { + return wrap(this.impl.lastChild); + }, + + /** @type {SVGElementInstance} */ + get previousSibling() { + return wrap(this.impl.previousSibling); + }, + + /** @type {SVGElementInstance} */ + get nextSibling() { + return wrap(this.impl.nextSibling); + } + }); + + registerWrapper(OriginalSVGElementInstance, SVGElementInstance); + + scope.wrappers.SVGElementInstance = SVGElementInstance; +})(window.ShadowDOMPolyfill); diff --git a/src/wrappers/SVGUseElement.js b/src/wrappers/SVGUseElement.js new file mode 100644 index 0000000..7f91363 --- /dev/null +++ b/src/wrappers/SVGUseElement.js @@ -0,0 +1,46 @@ +// Copyright 2014 The Polymer Authors. All rights reserved. +// Use of this source code is goverened by a BSD-style +// license that can be found in the LICENSE file. + +(function(scope) { + 'use strict'; + + var mixin = scope.mixin; + var registerWrapper = scope.registerWrapper; + var unwrap = scope.unwrap; + var wrap = scope.wrap; + + var OriginalSVGUseElement = window.SVGUseElement; + + // IE uses SVGElement as parent interface, SVG2 (Blink & Gecko) uses + // SVGGraphicsElement. Use the element to get the right prototype. + + var SVG_NS = 'http://www.w3.org/2000/svg'; + var gWrapper = wrap(document.createElementNS(SVG_NS, 'g')); + var useElement = document.createElementNS(SVG_NS, 'use'); + var SVGGElement = gWrapper.constructor; + var parentInterfacePrototype = Object.getPrototypeOf(SVGGElement.prototype); + var parentInterface = parentInterfacePrototype.constructor; + + function SVGUseElement(impl) { + parentInterface.call(this, impl); + } + + SVGUseElement.prototype = Object.create(parentInterfacePrototype); + + // Firefox does not expose instanceRoot. + if ('instanceRoot' in useElement) { + mixin(SVGUseElement.prototype, { + get instanceRoot() { + return wrap(unwrap(this).instanceRoot); + }, + get animatedInstanceRoot() { + return wrap(unwrap(this).animatedInstanceRoot); + }, + }); + } + + registerWrapper(OriginalSVGUseElement, SVGUseElement, useElement); + + scope.wrappers.SVGUseElement = SVGUseElement; +})(window.ShadowDOMPolyfill); diff --git a/test/js/SVGElementInstance.js b/test/js/SVGElementInstance.js new file mode 100644 index 0000000..0dfdbb8 --- /dev/null +++ b/test/js/SVGElementInstance.js @@ -0,0 +1,99 @@ +/* + * Copyright 2014 The Polymer Authors. All rights reserved. + * Use of this source code is goverened by a BSD-style + * license that can be found in the LICENSE file. + */ + +suite('SVGElementInstance', function() { + + var div; + + teardown(function() { + if (div) { + if (div.parentNode) + div.parentNode.removeChild(div); + div = undefined; + } + }); + + var svgCode = '\ + \ + \ + \ + \ + \ + \ + \ + '; + + function getInstanceRoot() { + div = document.body.appendChild(document.createElement('div')); + div.innerHTML = svgCode; + var svg = div.firstElementChild; + var useElement = svg.firstElementChild.nextElementSibling; + return useElement.instanceRoot; + } + + test('instanceof SVGUseElement', function() { + div = document.body.appendChild(document.createElement('div')); + div.innerHTML = svgCode; + var svg = div.firstElementChild; + var useElement = svg.firstElementChild.nextElementSibling; + assert.instanceOf(useElement, SVGUseElement); + assert.instanceOf(useElement, SVGElement); + assert.instanceOf(useElement, Element); + assert.instanceOf(useElement, EventTarget); + }); + + test('instanceof SVGElementInstance', function() { + // Firefox does not implement SVGElementInstance. + if (/Firefox/.test(navigator.userAgent)) + return; + + var instanceRoot = getInstanceRoot(); + assert.instanceOf(instanceRoot, SVGElementInstance); + assert.instanceOf(instanceRoot, EventTarget); + }); + + test('correspondingUseElement', function() { + // Firefox does not implement SVGElementInstance. + if (/Firefox/.test(navigator.userAgent)) + return; + + div = document.body.appendChild(document.createElement('div')); + div.innerHTML = svgCode; + var svg = div.firstElementChild; + var useElement = svg.firstElementChild.nextElementSibling; + var instanceRoot = useElement.instanceRoot; + assert.equal(useElement, instanceRoot.correspondingUseElement); + }); + + test('correspondingElement', function() { + // Firefox does not implement SVGElementInstance. + if (/Firefox/.test(navigator.userAgent)) + return; + + var instanceRoot = getInstanceRoot(); + assert.equal('g', instanceRoot.correspondingElement.localName); + }); + + test('tree', function() { + // Firefox does not implement SVGElementInstance. + if (/Firefox/.test(navigator.userAgent)) + return; + + var instanceRoot = getInstanceRoot(); + + assert.equal('line', instanceRoot.firstChild.correspondingElement.localName); + assert.equal('line', instanceRoot.lastChild.correspondingElement.localName); + + // IE always returns new wrappers for all the accessors. + if (/Trident/.test(navigator.userAgent)) + return; + + assert.equal(instanceRoot.firstChild, instanceRoot.lastChild); + assert.equal(instanceRoot, instanceRoot.firstChild.parentNode); + assert.isNull(instanceRoot.parentNode); + }); + +}); diff --git a/test/test.main.js b/test/test.main.js index 64e52b7..1e81ee6 100644 --- a/test/test.main.js +++ b/test/test.main.js @@ -109,9 +109,10 @@ var modules = [ 'MutationObserver/transient.js', 'Node.js', 'ParentNodeInterface.js', + 'Range.js', + 'SVGElementInstance.js', 'ShadowRoot.js', 'Text.js', - 'Range.js', 'Window.js', 'custom-element.js', 'events.js',