Skip to content
This repository has been archived by the owner on Mar 13, 2018. It is now read-only.

Commit

Permalink
Fix issue with SVGElementInstance
Browse files Browse the repository at this point in the history
  • Loading branch information
arv committed Jan 10, 2014
1 parent de3c061 commit e8f5ab2
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 3 deletions.
3 changes: 3 additions & 0 deletions build.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 3 additions & 0 deletions shadowdom.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
9 changes: 7 additions & 2 deletions src/wrappers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 ||
Expand All @@ -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;
}

/**
Expand Down
16 changes: 16 additions & 0 deletions src/wrappers/SVGElement.js
Original file line number Diff line number Diff line change
@@ -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);
67 changes: 67 additions & 0 deletions src/wrappers/SVGElementInstance.js
Original file line number Diff line number Diff line change
@@ -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);
46 changes: 46 additions & 0 deletions src/wrappers/SVGUseElement.js
Original file line number Diff line number Diff line change
@@ -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 <g> 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);
99 changes: 99 additions & 0 deletions test/js/SVGElementInstance.js
Original file line number Diff line number Diff line change
@@ -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 = '\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">\
<defs>\
<g id="g">\
<line/>\
</g>\
</defs>\
<use xlink:href="#g" />\
</svg>';

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);
});

});
3 changes: 2 additions & 1 deletion test/test.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit e8f5ab2

Please sign in to comment.