diff --git a/lib/get-property-info/svg/index.js b/lib/get-property-info/svg/index.js
new file mode 100644
index 0000000..73bebeb
--- /dev/null
+++ b/lib/get-property-info/svg/index.js
@@ -0,0 +1,21 @@
+var SVG_NAMESPACE = require('./svg-namespaces.js').SVG_NAMESPACE;
+var SVG_ELEMENTS = require('./svg-namespaces.js').SVG_ELEMENTS;
+var SVG_PROPERTIES = require('./svg-namespaces.js').SVG_PROPERTIES;
+
+function thisIsSVGTag(tag) {
+ return SVG_ELEMENTS.hasOwnProperty(tag);
+}
+
+function getSVGNamespace() {
+ return SVG_NAMESPACE;
+}
+
+function SVGAttributeNamespace(value) {
+ if (SVG_PROPERTIES.hasOwnProperty(value)) {
+ return SVG_PROPERTIES[value];
+ }
+}
+
+module.exports.thisIsSVGTag = thisIsSVGTag;
+module.exports.getSVGNamespace = getSVGNamespace;
+module.exports.SVGAttributeNamespace = SVGAttributeNamespace;
diff --git a/lib/get-property-info/svg/svg-attribute-hook.js b/lib/get-property-info/svg/svg-attribute-hook.js
new file mode 100644
index 0000000..28933cc
--- /dev/null
+++ b/lib/get-property-info/svg/svg-attribute-hook.js
@@ -0,0 +1,35 @@
+'use strict';
+
+function AttributeHook(namespace, value) {
+ if (!(this instanceof AttributeHook)) {
+ return new AttributeHook(namespace, value);
+ }
+
+ this.namespace = namespace;
+ this.value = value;
+}
+
+AttributeHook.prototype.hook = function (node, prop, prev) {
+ if (prev && prev.type === 'AttributeHook' &&
+ prev.value === this.value &&
+ prev.namespace === this.namespace) {
+ return;
+ }
+
+ node.setAttributeNS(this.namespace, prop, this.value);
+};
+
+AttributeHook.prototype.unhook = function (node, prop, next) {
+ if (next && next.type === 'AttributeHook' &&
+ next.namespace === this.namespace) {
+ return;
+ }
+
+ var colonPosition = prop.indexOf(':');
+ var localName = colonPosition > -1 ? prop.substr(colonPosition + 1) : prop;
+ node.removeAttributeNS(this.namespace, localName);
+};
+
+AttributeHook.prototype.type = 'AttributeHook';
+
+module.exports = AttributeHook;
diff --git a/lib/get-property-info/svg/svg-namespaces.js b/lib/get-property-info/svg/svg-namespaces.js
new file mode 100644
index 0000000..6ddc7b5
--- /dev/null
+++ b/lib/get-property-info/svg/svg-namespaces.js
@@ -0,0 +1,409 @@
+'use strict';
+
+/*
+ Adapted from https://github.com/Matt-Esch/virtual-dom/blob/master/virtual-hyperscript/svg-attribute-namespace.js
+ */
+
+var DEFAULT_NAMESPACE = null;
+var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
+var EV_NAMESPACE = 'http://www.w3.org/2001/xml-events';
+var XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink';
+var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace';
+
+// http://www.w3.org/TR/SVGTiny12/elementTable.html
+// http://www.w3.org/TR/SVG/eltindex.html
+var SVG_ELEMENTS = {
+ 'listener': SVG_NAMESPACE,
+// 'a': SVG_NAMESPACE,
+ 'animate': SVG_NAMESPACE,
+ 'altGlyph': SVG_NAMESPACE,
+ 'altGlyphDef': SVG_NAMESPACE,
+ 'altGlyphItem': SVG_NAMESPACE,
+ 'animateColor': SVG_NAMESPACE,
+ 'animateMotion': SVG_NAMESPACE,
+ 'animateTransform': SVG_NAMESPACE,
+ 'animation': SVG_NAMESPACE,
+// 'audio': SVG_NAMESPACE,
+ 'circle': SVG_NAMESPACE,
+ 'defs': SVG_NAMESPACE,
+ 'desc': SVG_NAMESPACE,
+ 'discard': SVG_NAMESPACE,
+ 'ellipse': SVG_NAMESPACE,
+ 'feBlend': SVG_NAMESPACE,
+ 'feColorMatrix': SVG_NAMESPACE,
+ 'feComponentTransfer': SVG_NAMESPACE,
+ 'feComposite': SVG_NAMESPACE,
+ 'feConvolveMatrix': SVG_NAMESPACE,
+ 'feDiffuseLighting': SVG_NAMESPACE,
+ 'feDisplacementMap': SVG_NAMESPACE,
+ 'feDistantLight': SVG_NAMESPACE,
+ 'feFlood': SVG_NAMESPACE,
+ 'feFuncA': SVG_NAMESPACE,
+ 'feFuncB': SVG_NAMESPACE,
+ 'feFuncG': SVG_NAMESPACE,
+ 'feFuncR': SVG_NAMESPACE,
+ 'feGaussianBlur': SVG_NAMESPACE,
+ 'feImage': SVG_NAMESPACE,
+ 'feMerge': SVG_NAMESPACE,
+ 'feMergeNode': SVG_NAMESPACE,
+ 'feMorphology': SVG_NAMESPACE,
+ 'feOffset': SVG_NAMESPACE,
+ 'fePointLight': SVG_NAMESPACE,
+ 'feSpecularLighting': SVG_NAMESPACE,
+ 'feSpotLight': SVG_NAMESPACE,
+ 'feTile': SVG_NAMESPACE,
+ 'feTurbulence': SVG_NAMESPACE,
+ 'filter': SVG_NAMESPACE,
+ 'font': SVG_NAMESPACE,
+ 'font-face': SVG_NAMESPACE,
+ 'font-face-format': SVG_NAMESPACE,
+ 'font-face-name': SVG_NAMESPACE,
+ 'font-face-src': SVG_NAMESPACE,
+ 'font-face-uri': SVG_NAMESPACE,
+ 'foreignObject': SVG_NAMESPACE,
+ 'g': SVG_NAMESPACE,
+ 'glyph': SVG_NAMESPACE,
+ 'glyphRef': SVG_NAMESPACE,
+ 'handler': SVG_NAMESPACE,
+ 'hkern': SVG_NAMESPACE,
+ 'image': SVG_NAMESPACE,
+ 'line': SVG_NAMESPACE,
+ 'linearGradient': SVG_NAMESPACE,
+ 'metadata': SVG_NAMESPACE,
+ 'missing-glyph': SVG_NAMESPACE,
+ 'mpath': SVG_NAMESPACE,
+ 'path': SVG_NAMESPACE,
+ 'polygon': SVG_NAMESPACE,
+ 'polyline': SVG_NAMESPACE,
+ 'prefetch': SVG_NAMESPACE,
+ 'radialGradient': SVG_NAMESPACE,
+ 'rect': SVG_NAMESPACE,
+// 'script': SVG_NAMESPACE,
+ 'set': SVG_NAMESPACE,
+ 'solidColor': SVG_NAMESPACE,
+ 'stop': SVG_NAMESPACE,
+ 'svg': SVG_NAMESPACE,
+ 'switch': SVG_NAMESPACE,
+ 'symbol': SVG_NAMESPACE,
+ 'tbreak': SVG_NAMESPACE,
+ 'text': SVG_NAMESPACE,
+ 'textArea': SVG_NAMESPACE,
+ 'title': SVG_NAMESPACE,
+ 'tspan': SVG_NAMESPACE,
+ 'tref': SVG_NAMESPACE,
+ 'use': SVG_NAMESPACE,
+ 'vkern': SVG_NAMESPACE,
+// 'video': SVG_NAMESPACE,
+};
+
+// http://www.w3.org/TR/SVGTiny12/attributeTable.html
+// http://www.w3.org/TR/SVG/attindex.html
+var SVG_PROPERTIES = {
+ 'about': DEFAULT_NAMESPACE,
+ 'accent-height': DEFAULT_NAMESPACE,
+ 'accumulate': DEFAULT_NAMESPACE,
+ 'additive': DEFAULT_NAMESPACE,
+ 'alignment-baseline': DEFAULT_NAMESPACE,
+ 'alphabetic': DEFAULT_NAMESPACE,
+ 'amplitude': DEFAULT_NAMESPACE,
+ 'arabic-form': DEFAULT_NAMESPACE,
+ 'ascent': DEFAULT_NAMESPACE,
+ 'attributeName': DEFAULT_NAMESPACE,
+ 'attributeType': DEFAULT_NAMESPACE,
+ 'azimuth': DEFAULT_NAMESPACE,
+ 'bandwidth': DEFAULT_NAMESPACE,
+ 'baseFrequency': DEFAULT_NAMESPACE,
+ 'baseProfile': DEFAULT_NAMESPACE,
+ 'baseline-shift': DEFAULT_NAMESPACE,
+ 'bbox': DEFAULT_NAMESPACE,
+ 'begin': DEFAULT_NAMESPACE,
+ 'bias': DEFAULT_NAMESPACE,
+ 'by': DEFAULT_NAMESPACE,
+ 'calcMode': DEFAULT_NAMESPACE,
+ 'cap-height': DEFAULT_NAMESPACE,
+ 'class': DEFAULT_NAMESPACE,
+ 'clip': DEFAULT_NAMESPACE,
+ 'clip-path': DEFAULT_NAMESPACE,
+ 'clip-rule': DEFAULT_NAMESPACE,
+ 'clipPathUnits': DEFAULT_NAMESPACE,
+ 'color': DEFAULT_NAMESPACE,
+ 'color-interpolation': DEFAULT_NAMESPACE,
+ 'color-interpolation-filters': DEFAULT_NAMESPACE,
+ 'color-profile': DEFAULT_NAMESPACE,
+ 'color-rendering': DEFAULT_NAMESPACE,
+ 'content': DEFAULT_NAMESPACE,
+ 'contentScriptType': DEFAULT_NAMESPACE,
+ 'contentStyleType': DEFAULT_NAMESPACE,
+ 'cursor': DEFAULT_NAMESPACE,
+ 'cx': DEFAULT_NAMESPACE,
+ 'cy': DEFAULT_NAMESPACE,
+ 'd': DEFAULT_NAMESPACE,
+ 'datatype': DEFAULT_NAMESPACE,
+ 'defaultAction': DEFAULT_NAMESPACE,
+ 'descent': DEFAULT_NAMESPACE,
+ 'diffuseConstant': DEFAULT_NAMESPACE,
+ 'direction': DEFAULT_NAMESPACE,
+ 'display': DEFAULT_NAMESPACE,
+ 'divisor': DEFAULT_NAMESPACE,
+ 'dominant-baseline': DEFAULT_NAMESPACE,
+ 'dur': DEFAULT_NAMESPACE,
+ 'dx': DEFAULT_NAMESPACE,
+ 'dy': DEFAULT_NAMESPACE,
+ 'edgeMode': DEFAULT_NAMESPACE,
+ 'editable': DEFAULT_NAMESPACE,
+ 'elevation': DEFAULT_NAMESPACE,
+ 'enable-background': DEFAULT_NAMESPACE,
+ 'end': DEFAULT_NAMESPACE,
+ 'ev:event': EV_NAMESPACE,
+ 'event': DEFAULT_NAMESPACE,
+ 'exponent': DEFAULT_NAMESPACE,
+ 'externalResourcesRequired': DEFAULT_NAMESPACE,
+ 'fill': DEFAULT_NAMESPACE,
+ 'fill-opacity': DEFAULT_NAMESPACE,
+ 'fill-rule': DEFAULT_NAMESPACE,
+ 'filter': DEFAULT_NAMESPACE,
+ 'filterRes': DEFAULT_NAMESPACE,
+ 'filterUnits': DEFAULT_NAMESPACE,
+ 'flood-color': DEFAULT_NAMESPACE,
+ 'flood-opacity': DEFAULT_NAMESPACE,
+ 'focusHighlight': DEFAULT_NAMESPACE,
+ 'focusable': DEFAULT_NAMESPACE,
+ 'font-family': DEFAULT_NAMESPACE,
+ 'font-size': DEFAULT_NAMESPACE,
+ 'font-size-adjust': DEFAULT_NAMESPACE,
+ 'font-stretch': DEFAULT_NAMESPACE,
+ 'font-style': DEFAULT_NAMESPACE,
+ 'font-variant': DEFAULT_NAMESPACE,
+ 'font-weight': DEFAULT_NAMESPACE,
+ 'format': DEFAULT_NAMESPACE,
+ 'from': DEFAULT_NAMESPACE,
+ 'fx': DEFAULT_NAMESPACE,
+ 'fy': DEFAULT_NAMESPACE,
+ 'g1': DEFAULT_NAMESPACE,
+ 'g2': DEFAULT_NAMESPACE,
+ 'glyph-name': DEFAULT_NAMESPACE,
+ 'glyph-orientation-horizontal': DEFAULT_NAMESPACE,
+ 'glyph-orientation-vertical': DEFAULT_NAMESPACE,
+ 'glyphRef': DEFAULT_NAMESPACE,
+ 'gradientTransform': DEFAULT_NAMESPACE,
+ 'gradientUnits': DEFAULT_NAMESPACE,
+ 'handler': DEFAULT_NAMESPACE,
+ 'hanging': DEFAULT_NAMESPACE,
+ 'height': DEFAULT_NAMESPACE,
+ 'horiz-adv-x': DEFAULT_NAMESPACE,
+ 'horiz-origin-x': DEFAULT_NAMESPACE,
+ 'horiz-origin-y': DEFAULT_NAMESPACE,
+ 'id': DEFAULT_NAMESPACE,
+ 'ideographic': DEFAULT_NAMESPACE,
+ 'image-rendering': DEFAULT_NAMESPACE,
+ 'in': DEFAULT_NAMESPACE,
+ 'in2': DEFAULT_NAMESPACE,
+ 'initialVisibility': DEFAULT_NAMESPACE,
+ 'intercept': DEFAULT_NAMESPACE,
+ 'k': DEFAULT_NAMESPACE,
+ 'k1': DEFAULT_NAMESPACE,
+ 'k2': DEFAULT_NAMESPACE,
+ 'k3': DEFAULT_NAMESPACE,
+ 'k4': DEFAULT_NAMESPACE,
+ 'kernelMatrix': DEFAULT_NAMESPACE,
+ 'kernelUnitLength': DEFAULT_NAMESPACE,
+ 'kerning': DEFAULT_NAMESPACE,
+ 'keyPoints': DEFAULT_NAMESPACE,
+ 'keySplines': DEFAULT_NAMESPACE,
+ 'keyTimes': DEFAULT_NAMESPACE,
+ 'lang': DEFAULT_NAMESPACE,
+ 'lengthAdjust': DEFAULT_NAMESPACE,
+ 'letter-spacing': DEFAULT_NAMESPACE,
+ 'lighting-color': DEFAULT_NAMESPACE,
+ 'limitingConeAngle': DEFAULT_NAMESPACE,
+ 'local': DEFAULT_NAMESPACE,
+ 'marker-end': DEFAULT_NAMESPACE,
+ 'marker-mid': DEFAULT_NAMESPACE,
+ 'marker-start': DEFAULT_NAMESPACE,
+ 'markerHeight': DEFAULT_NAMESPACE,
+ 'markerUnits': DEFAULT_NAMESPACE,
+ 'markerWidth': DEFAULT_NAMESPACE,
+ 'mask': DEFAULT_NAMESPACE,
+ 'maskContentUnits': DEFAULT_NAMESPACE,
+ 'maskUnits': DEFAULT_NAMESPACE,
+ 'mathematical': DEFAULT_NAMESPACE,
+ 'max': DEFAULT_NAMESPACE,
+ 'media': DEFAULT_NAMESPACE,
+ 'mediaCharacterEncoding': DEFAULT_NAMESPACE,
+ 'mediaContentEncodings': DEFAULT_NAMESPACE,
+ 'mediaSize': DEFAULT_NAMESPACE,
+ 'mediaTime': DEFAULT_NAMESPACE,
+ 'method': DEFAULT_NAMESPACE,
+ 'min': DEFAULT_NAMESPACE,
+ 'mode': DEFAULT_NAMESPACE,
+ 'name': DEFAULT_NAMESPACE,
+ 'nav-down': DEFAULT_NAMESPACE,
+ 'nav-down-left': DEFAULT_NAMESPACE,
+ 'nav-down-right': DEFAULT_NAMESPACE,
+ 'nav-left': DEFAULT_NAMESPACE,
+ 'nav-next': DEFAULT_NAMESPACE,
+ 'nav-prev': DEFAULT_NAMESPACE,
+ 'nav-right': DEFAULT_NAMESPACE,
+ 'nav-up': DEFAULT_NAMESPACE,
+ 'nav-up-left': DEFAULT_NAMESPACE,
+ 'nav-up-right': DEFAULT_NAMESPACE,
+ 'numOctaves': DEFAULT_NAMESPACE,
+ 'observer': DEFAULT_NAMESPACE,
+ 'offset': DEFAULT_NAMESPACE,
+ 'opacity': DEFAULT_NAMESPACE,
+ 'operator': DEFAULT_NAMESPACE,
+ 'order': DEFAULT_NAMESPACE,
+ 'orient': DEFAULT_NAMESPACE,
+ 'orientation': DEFAULT_NAMESPACE,
+ 'origin': DEFAULT_NAMESPACE,
+ 'overflow': DEFAULT_NAMESPACE,
+ 'overlay': DEFAULT_NAMESPACE,
+ 'overline-position': DEFAULT_NAMESPACE,
+ 'overline-thickness': DEFAULT_NAMESPACE,
+ 'panose-1': DEFAULT_NAMESPACE,
+ 'path': DEFAULT_NAMESPACE,
+ 'pathLength': DEFAULT_NAMESPACE,
+ 'patternContentUnits': DEFAULT_NAMESPACE,
+ 'patternTransform': DEFAULT_NAMESPACE,
+ 'patternUnits': DEFAULT_NAMESPACE,
+ 'phase': DEFAULT_NAMESPACE,
+ 'playbackOrder': DEFAULT_NAMESPACE,
+ 'pointer-events': DEFAULT_NAMESPACE,
+ 'points': DEFAULT_NAMESPACE,
+ 'pointsAtX': DEFAULT_NAMESPACE,
+ 'pointsAtY': DEFAULT_NAMESPACE,
+ 'pointsAtZ': DEFAULT_NAMESPACE,
+ 'preserveAlpha': DEFAULT_NAMESPACE,
+ 'preserveAspectRatio': DEFAULT_NAMESPACE,
+ 'primitiveUnits': DEFAULT_NAMESPACE,
+ 'propagate': DEFAULT_NAMESPACE,
+ 'property': DEFAULT_NAMESPACE,
+ 'r': DEFAULT_NAMESPACE,
+ 'radius': DEFAULT_NAMESPACE,
+ 'refX': DEFAULT_NAMESPACE,
+ 'refY': DEFAULT_NAMESPACE,
+ 'rel': DEFAULT_NAMESPACE,
+ 'rendering-intent': DEFAULT_NAMESPACE,
+ 'repeatCount': DEFAULT_NAMESPACE,
+ 'repeatDur': DEFAULT_NAMESPACE,
+ 'requiredExtensions': DEFAULT_NAMESPACE,
+ 'requiredFeatures': DEFAULT_NAMESPACE,
+ 'requiredFonts': DEFAULT_NAMESPACE,
+ 'requiredFormats': DEFAULT_NAMESPACE,
+ 'resource': DEFAULT_NAMESPACE,
+ 'restart': DEFAULT_NAMESPACE,
+ 'result': DEFAULT_NAMESPACE,
+ 'rev': DEFAULT_NAMESPACE,
+ 'role': DEFAULT_NAMESPACE,
+ 'rotate': DEFAULT_NAMESPACE,
+ 'rx': DEFAULT_NAMESPACE,
+ 'ry': DEFAULT_NAMESPACE,
+ 'scale': DEFAULT_NAMESPACE,
+ 'seed': DEFAULT_NAMESPACE,
+ 'shape-rendering': DEFAULT_NAMESPACE,
+ 'slope': DEFAULT_NAMESPACE,
+ 'snapshotTime': DEFAULT_NAMESPACE,
+ 'spacing': DEFAULT_NAMESPACE,
+ 'specularConstant': DEFAULT_NAMESPACE,
+ 'specularExponent': DEFAULT_NAMESPACE,
+ 'spreadMethod': DEFAULT_NAMESPACE,
+ 'startOffset': DEFAULT_NAMESPACE,
+ 'stdDeviation': DEFAULT_NAMESPACE,
+ 'stemh': DEFAULT_NAMESPACE,
+ 'stemv': DEFAULT_NAMESPACE,
+ 'stitchTiles': DEFAULT_NAMESPACE,
+ 'stop-color': DEFAULT_NAMESPACE,
+ 'stop-opacity': DEFAULT_NAMESPACE,
+ 'strikethrough-position': DEFAULT_NAMESPACE,
+ 'strikethrough-thickness': DEFAULT_NAMESPACE,
+ 'string': DEFAULT_NAMESPACE,
+ 'stroke': DEFAULT_NAMESPACE,
+ 'stroke-dasharray': DEFAULT_NAMESPACE,
+ 'stroke-dashoffset': DEFAULT_NAMESPACE,
+ 'stroke-linecap': DEFAULT_NAMESPACE,
+ 'stroke-linejoin': DEFAULT_NAMESPACE,
+ 'stroke-miterlimit': DEFAULT_NAMESPACE,
+ 'stroke-opacity': DEFAULT_NAMESPACE,
+ 'stroke-width': DEFAULT_NAMESPACE,
+ 'surfaceScale': DEFAULT_NAMESPACE,
+ 'syncBehavior': DEFAULT_NAMESPACE,
+ 'syncBehaviorDefault': DEFAULT_NAMESPACE,
+ 'syncMaster': DEFAULT_NAMESPACE,
+ 'syncTolerance': DEFAULT_NAMESPACE,
+ 'syncToleranceDefault': DEFAULT_NAMESPACE,
+ 'systemLanguage': DEFAULT_NAMESPACE,
+ 'tableValues': DEFAULT_NAMESPACE,
+ 'target': DEFAULT_NAMESPACE,
+ 'targetX': DEFAULT_NAMESPACE,
+ 'targetY': DEFAULT_NAMESPACE,
+ 'text-anchor': DEFAULT_NAMESPACE,
+ 'text-decoration': DEFAULT_NAMESPACE,
+ 'text-rendering': DEFAULT_NAMESPACE,
+ 'textLength': DEFAULT_NAMESPACE,
+ 'timelineBegin': DEFAULT_NAMESPACE,
+ 'title': DEFAULT_NAMESPACE,
+ 'to': DEFAULT_NAMESPACE,
+ 'transform': DEFAULT_NAMESPACE,
+ 'transformBehavior': DEFAULT_NAMESPACE,
+ 'type': DEFAULT_NAMESPACE,
+ 'typeof': DEFAULT_NAMESPACE,
+ 'u1': DEFAULT_NAMESPACE,
+ 'u2': DEFAULT_NAMESPACE,
+ 'underline-position': DEFAULT_NAMESPACE,
+ 'underline-thickness': DEFAULT_NAMESPACE,
+ 'unicode': DEFAULT_NAMESPACE,
+ 'unicode-bidi': DEFAULT_NAMESPACE,
+ 'unicode-range': DEFAULT_NAMESPACE,
+ 'units-per-em': DEFAULT_NAMESPACE,
+ 'v-alphabetic': DEFAULT_NAMESPACE,
+ 'v-hanging': DEFAULT_NAMESPACE,
+ 'v-ideographic': DEFAULT_NAMESPACE,
+ 'v-mathematical': DEFAULT_NAMESPACE,
+ 'values': DEFAULT_NAMESPACE,
+ 'version': DEFAULT_NAMESPACE,
+ 'vert-adv-y': DEFAULT_NAMESPACE,
+ 'vert-origin-x': DEFAULT_NAMESPACE,
+ 'vert-origin-y': DEFAULT_NAMESPACE,
+ 'viewBox': DEFAULT_NAMESPACE,
+ 'viewTarget': DEFAULT_NAMESPACE,
+ 'visibility': DEFAULT_NAMESPACE,
+ 'width': DEFAULT_NAMESPACE,
+ 'widths': DEFAULT_NAMESPACE,
+ 'word-spacing': DEFAULT_NAMESPACE,
+ 'writing-mode': DEFAULT_NAMESPACE,
+ 'x': DEFAULT_NAMESPACE,
+ 'x-height': DEFAULT_NAMESPACE,
+ 'x1': DEFAULT_NAMESPACE,
+ 'x2': DEFAULT_NAMESPACE,
+ 'xChannelSelector': DEFAULT_NAMESPACE,
+ 'xlink:actuate': XLINK_NAMESPACE,
+ 'xlink:arcrole': XLINK_NAMESPACE,
+ 'xlink:href': XLINK_NAMESPACE,
+ 'xlink:role': XLINK_NAMESPACE,
+ 'xlink:show': XLINK_NAMESPACE,
+ 'xlink:title': XLINK_NAMESPACE,
+ 'xlink:type': XLINK_NAMESPACE,
+ 'xml:base': XML_NAMESPACE,
+ 'xml:id': XML_NAMESPACE,
+ 'xml:lang': XML_NAMESPACE,
+ 'xml:space': XML_NAMESPACE,
+ 'y': DEFAULT_NAMESPACE,
+ 'y1': DEFAULT_NAMESPACE,
+ 'y2': DEFAULT_NAMESPACE,
+ 'yChannelSelector': DEFAULT_NAMESPACE,
+ 'z': DEFAULT_NAMESPACE,
+ 'zoomAndPan': DEFAULT_NAMESPACE
+};
+
+module.exports.SVG_NAMESPACE = SVG_NAMESPACE;
+module.exports.SVG_ELEMENTS = SVG_ELEMENTS;
+module.exports.SVG_PROPERTIES = SVG_PROPERTIES;
+
+
+
+
+
+
+
+
+
diff --git a/lib/html-to-vdom.js b/lib/html-to-vdom.js
index 5135d39..f37ee87 100644
--- a/lib/html-to-vdom.js
+++ b/lib/html-to-vdom.js
@@ -22,7 +22,7 @@ module.exports = function initializeHtmlToVdom (VTree, VText) {
else {
convertedHTML = htmlparserToVdom.convert(tags[0], getVNodeKey);
}
-
+
return convertedHTML;
};
};
diff --git a/lib/htmlparser-to-vdom.js b/lib/htmlparser-to-vdom.js
index 9993453..9761687 100644
--- a/lib/htmlparser-to-vdom.js
+++ b/lib/htmlparser-to-vdom.js
@@ -1,7 +1,31 @@
var decode = require('ent').decode;
var convertTagAttributes = require('./convert-tag-attributes');
+var svg = require('./get-property-info/svg');
+var SVGAttributeHook = require('./get-property-info/svg/svg-attribute-hook');
module.exports = function createConverter (VNode, VText) {
+ function convertSvg(tag, attributes, children, key) {
+ var _attributes = attributes.attributes;
+
+ for(var _key in _attributes) {
+ var namespace = svg.SVGAttributeNamespace(_key);
+
+ if (namespace === void 0) { // not a svg attribute
+ continue;
+ }
+
+ var value = _attributes[_key];
+
+ if (namespace !== null) { // namespaced attribute
+ attributes[_key] = new SVGAttributeHook(namespace, value);
+ _attributes[_key] = void 0;
+ continue;
+ }
+ }
+
+ return new VNode(tag.name, attributes, children, key, svg.getSVGNamespace());
+ }
+
var converter = {
convert: function (node, getVNodeKey) {
if (node.type === 'tag' || node.type === 'script' || node.type === 'style') {
@@ -25,8 +49,13 @@ module.exports = function createConverter (VNode, VText) {
return converter.convert(node, getVNodeKey);
});
+ if(svg.thisIsSVGTag(tag.name)) {
+ return convertSvg(tag, attributes, children, key);
+ }
+
return new VNode(tag.name, attributes, children, key);
}
};
+
return converter;
};
diff --git a/package.json b/package.json
index 73bdbf9..56da1f0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "html-to-vdom",
- "version": "0.7.0",
+ "version": "0.7.2",
"description": "Converts html into a vtree",
"main": "index.js",
"scripts": {
diff --git a/test/get-property-info/svg/svg-attribute-hook.js b/test/get-property-info/svg/svg-attribute-hook.js
new file mode 100644
index 0000000..9f0e44b
--- /dev/null
+++ b/test/get-property-info/svg/svg-attribute-hook.js
@@ -0,0 +1,102 @@
+var SVGAttributeHook = require('../../../lib/get-property-info/svg/svg-attribute-hook');
+
+
+describe('SVGAttributeHook', function () {
+ var testNamespace = "http://www.testnamespace.com";
+ var testValue = "test-value";
+ var attributeHook = SVGAttributeHook(testNamespace, testValue);
+
+ it('creates new AttributeBook with namespace and value', function () {
+ attributeHook.namespace.should.equal(testNamespace)
+ attributeHook.value.should.equal(testValue)
+ });
+
+ describe('hook', function() {
+ context('prev is the same AttributeHook', function() {
+ it('does nothing', function() {
+ var prev = attributeHook;
+ var node = {};
+ var prop = {};
+
+ var hooked = attributeHook.hook(node, prop, prev)
+
+ should.equal(hooked, undefined)
+ });
+ });
+
+ context('prev is different AttributeHook', function() {
+ it('sets the attribute to the input node', function() {
+ var otherNamespace = "othernamespace";
+ var otherValue = "otherValue";
+ var testProp = "testProp";
+ var prev = SVGAttributeHook(otherNamespace, otherValue);
+ var node = {
+ setAttributeNS: function(namespace, prop, value) {
+ this.namespace = namespace;
+ this.value = value;
+ this.prop = prop;
+ },
+ namespace: null,
+ value: null,
+ prop: null,
+ };
+
+ attributeHook.hook(node, testProp, prev)
+
+ node.namespace.should.equal(testNamespace)
+ node.value.should.equal(testValue)
+ node.prop.should.equal(testProp)
+ });
+ });
+ });
+
+ describe('unhook', function() {
+ context('node is has same namespace as next', function() {
+ it('does nothing', function() {
+ var next = attributeHook;
+ var node = {};
+ var prop = {};
+
+ var hooked = attributeHook.unhook(node, prop, next)
+
+ should.equal(hooked, undefined)
+ });
+ });
+
+ context('node has different namespace as next', function() {
+ it('removes attribute namespace from the node', function() {
+ var otherNamespace = "othernamespace";
+ var otherValue = "otherValue";
+ var testProp = "color:red";
+ var next = SVGAttributeHook(otherNamespace, otherValue);
+ var node = {
+ removeAttributeNS: function(namespace, name) {
+ this.namespace = name;
+ },
+ namespace: testNamespace
+ };
+
+ attributeHook.unhook(node, testProp, next)
+
+ node.namespace.should.equal('red')
+ });
+
+ it('removes attribute namespace without colon in prop from the node', function() {
+ var otherNamespace = "othernamespace";
+ var otherValue = "otherValue";
+ var testProp = "color";
+ var next = SVGAttributeHook(otherNamespace, otherValue);
+ var node = {
+ removeAttributeNS: function(namespace, name) {
+ this.namespace = name;
+ },
+ namespace: testNamespace
+ };
+
+ attributeHook.unhook(node, testProp, next)
+
+ node.namespace.should.equal('color')
+ });
+ });
+ });
+});
diff --git a/test/html-to-vdom/lib/convert-tag-attributes/attributes.js b/test/html-to-vdom/lib/convert-tag-attributes/attributes.js
index fd7c62e..ea58f90 100644
--- a/test/html-to-vdom/lib/convert-tag-attributes/attributes.js
+++ b/test/html-to-vdom/lib/convert-tag-attributes/attributes.js
@@ -45,6 +45,30 @@ describe('convertTagAttributes', function () {
});
});
});
+
+ describe('when converting an svg', function() {
+
+ it('sets them', function() {
+ var tag = parseHTML('')[0];
+
+ var converted = convertTagAttributes(tag);
+ converted.should.eql({
+ attributes: {
+ 'xmlns:rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+ 'xmlns': 'http://www.w3.org/2000/svg',
+ 'xml:space': 'preserve',
+ 'height': '180.903',
+ 'width': '220.34801',
+ 'version': '1.1',
+ 'xmlns:cc': 'http://creativecommons.org/ns#',
+ 'xmlns:dc': 'http://purl.org/dc/elements/1.1/'
+ }
+ });
+
+ });
+
+ });
+
});
});
diff --git a/test/html-to-vdom/lib/html-to-vdom/index.js b/test/html-to-vdom/lib/html-to-vdom/index.js
index 2a09fba..b4c2172 100644
--- a/test/html-to-vdom/lib/html-to-vdom/index.js
+++ b/test/html-to-vdom/lib/html-to-vdom/index.js
@@ -173,4 +173,64 @@ describe('html-to-vdom', function () {
comment.text.should.eql('');
});
});
+
+ describe('when converting an svg tag', function () {
+ var svg1 = convertHTML(
+ '');
+
+ var svg2 = convertHTML(
+ '');
+
+ it('converts to the fill tag correctly', function () {
+ svg1.tagName.should.eql('svg');
+ should.exist(svg1.children);
+
+ svg1.children.length.should.eql(2);
+ svg1.children[0].tagName.should.eql('metadata');
+ svg1.children[1].tagName.should.eql('path');
+ });
+
+ it('processes attributes correctly', function() {
+ svg2.tagName.should.eql('svg');
+
+ var attrs = svg2.properties.attributes;
+
+ attrs.height.should.eql('32px');
+ attrs.width.should.eql('32px');
+ attrs['aria-labelledby'].should.eql('navigation-svg-title');
+ attrs.viewBox.should.eql('0 0 32 32');
+
+ svg2.properties.style['enable-background'].should.eql('new 0 0 32 32');
+ });
+
+ it('processes title and path correctly', function() {
+ should.exist(svg2.children);
+ svg2.children.length.should.eql(2);
+ var title = svg2.children[0];
+ var path = svg2.children[1];
+
+ title.tagName.should.eql('title');
+ title.properties.id.should.eql('navigation-svg-title');
+
+ path.tagName.should.eql('path');
+ path.properties.attributes['class'].should.eql('c-small-navigation__icon');
+ path.properties.attributes.d.should.eql('M4,10h24c1.104,0,2-0.896,2-2s-0.896-2-2-2H4C2.896,6,2,6.896,2,8S2.896,10,4,10z M28,14H4c-1.104,0-2,0.896-2,2 s0.896,2,2,2h24c1.104,0,2-0.896,2-2S29.104,14,28,14z M28,22H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h24c1.104,0,2-0.896,2-2 S29.104,22,28,22z');
+ });
+
+ });
});