Merge pull request #3718 from framp/master

Added support for namespace attributes
This commit is contained in:
Ben Alpert
2015-05-05 16:48:21 -07:00
6 changed files with 115 additions and 3 deletions
+41
View File
@@ -0,0 +1,41 @@
/**
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/
/*jslint evil: true */
'use strict';
var React;
var ReactTestUtils;
var SVGDOMNamespaces = {
xlink: 'http://www.w3.org/1999/xlink',
xml: 'http://www.w3.org/XML/1998/namespace',
xmlns: 'http://www.w3.org/2000/xmlns/'
};
describe('ReactDOMSVG', function() {
beforeEach(function() {
React = require('React');
ReactTestUtils = require('ReactTestUtils');
});
it('creates initial namespaced markup', function() {
var markup = React.renderToString(
<svg>
<image xlinkHref="http://i.imgur.com/w7GCRPb.png" />
</svg>
);
expect(markup).toContain('xlink:href="http://i.imgur.com/w7GCRPb.png"');
});
});
+17
View File
@@ -50,6 +50,9 @@ var DOMPropertyInjection = {
* attribute name. Attribute names not specified use the **lowercase**
* normalized name.
*
* DOMAttributeNamespaces: object mapping React attribute name to the DOM
* attribute namespace URL. (Attribute names not specified use no namespace.)
*
* DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
* Property names not specified use the normalized name.
*
@@ -60,6 +63,7 @@ var DOMPropertyInjection = {
*/
injectDOMPropertyConfig: function(domPropertyConfig) {
var Properties = domPropertyConfig.Properties || {};
var DOMAttributeNamespaces = domPropertyConfig.DOMAttributeNamespaces || {};
var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
@@ -93,6 +97,13 @@ var DOMPropertyInjection = {
DOMProperty.getAttributeName[propName] = lowerCased;
}
if (DOMAttributeNamespaces.hasOwnProperty(propName)) {
DOMProperty.getAttributeNamespace[propName] =
DOMAttributeNamespaces[propName];
} else {
DOMProperty.getAttributeNamespace[propName] = null;
}
DOMProperty.getPropertyName[propName] =
DOMPropertyNames.hasOwnProperty(propName) ?
DOMPropertyNames[propName] :
@@ -182,6 +193,12 @@ var DOMProperty = {
*/
getAttributeName: {},
/**
* Mapping from normalized names to namespaces.
* @type {Object}
*/
getAttributeNamespace: {},
/**
* Mapping from normalized names to properties on DOM node instances.
* (This includes properties that mutate due to external factors.)
+7 -1
View File
@@ -126,9 +126,15 @@ var DOMPropertyOperations = {
} else if (shouldIgnoreValue(name, value)) {
this.deleteValueForProperty(node, name);
} else if (DOMProperty.mustUseAttribute[name]) {
var attributeName = DOMProperty.getAttributeName[name];
var namespace = DOMProperty.getAttributeNamespace[name];
// `setAttribute` with objects becomes only `[object]` in IE8/9,
// ('' + value) makes it output the correct toString()-value.
node.setAttribute(DOMProperty.getAttributeName[name], '' + value);
if (namespace) {
node.setAttributeNS(namespace, attributeName, '' + value);
} else {
node.setAttribute(attributeName, '' + value);
}
} else {
var propName = DOMProperty.getPropertyName[name];
// Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
@@ -39,7 +39,6 @@ if (ExecutionEnvironment.canUseDOM) {
);
}
var HTMLDOMPropertyConfig = {
isCustomAttribute: RegExp.prototype.test.bind(
/^(data|aria)-[a-z_][a-z\d_.\-]*$/
+38 -1
View File
@@ -17,6 +17,11 @@ var DOMProperty = require('DOMProperty');
var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
var NS = {
xlink: 'http://www.w3.org/1999/xlink',
xml: 'http://www.w3.org/XML/1998/namespace'
};
var SVGDOMPropertyConfig = {
Properties: {
clipPath: MUST_USE_ATTRIBUTE,
@@ -60,10 +65,32 @@ var SVGDOMPropertyConfig = {
x1: MUST_USE_ATTRIBUTE,
x2: MUST_USE_ATTRIBUTE,
x: MUST_USE_ATTRIBUTE,
xlinkActuate: MUST_USE_ATTRIBUTE,
xlinkArcrole: MUST_USE_ATTRIBUTE,
xlinkHref: MUST_USE_ATTRIBUTE,
xlinkRole: MUST_USE_ATTRIBUTE,
xlinkShow: MUST_USE_ATTRIBUTE,
xlinkTitle: MUST_USE_ATTRIBUTE,
xlinkType: MUST_USE_ATTRIBUTE,
xmlBase: MUST_USE_ATTRIBUTE,
xmlLang: MUST_USE_ATTRIBUTE,
xmlSpace: MUST_USE_ATTRIBUTE,
y1: MUST_USE_ATTRIBUTE,
y2: MUST_USE_ATTRIBUTE,
y: MUST_USE_ATTRIBUTE
},
DOMAttributeNamespaces: {
xlinkActuate: NS.xlink,
xlinkArcrole: NS.xlink,
xlinkHref: NS.xlink,
xlinkRole: NS.xlink,
xlinkShow: NS.xlink,
xlinkTitle: NS.xlink,
xlinkType: NS.xlink,
xmlBase: NS.xml,
xmlLang: NS.xml,
xmlSpace: NS.xml
},
DOMAttributeNames: {
clipPath: 'clip-path',
fillOpacity: 'fill-opacity',
@@ -85,7 +112,17 @@ var SVGDOMPropertyConfig = {
strokeOpacity: 'stroke-opacity',
strokeWidth: 'stroke-width',
textAnchor: 'text-anchor',
viewBox: 'viewBox'
viewBox: 'viewBox',
xlinkActuate: 'xlink:actuate',
xlinkArcrole: 'xlink:arcrole',
xlinkHref: 'xlink:href',
xlinkRole: 'xlink:role',
xlinkShow: 'xlink:show',
xlinkTitle: 'xlink:title',
xlinkType: 'xlink:type',
xmlBase: 'xml:base',
xmlLang: 'xml:lang',
xmlSpace: 'xml:space'
}
};
@@ -197,6 +197,18 @@ describe('DOMPropertyOperations', function() {
expect(stubNode.role).toBeUndefined();
});
it('should set values as namespace attributes if necessary', function() {
spyOn(stubNode, 'setAttributeNS');
DOMPropertyOperations.setValueForProperty(
stubNode,
'xlinkHref',
'about:blank'
);
expect(stubNode.setAttributeNS.argsForCall.length).toBe(1);
expect(stubNode.setAttributeNS.argsForCall[0])
.toEqual(['http://www.w3.org/1999/xlink', 'xlink:href', 'about:blank']);
});
it('should convert attribute values to string first', function() {
// Browsers default to this behavior, but some test environments do not.
// This ensures that we have consistent behavior.