mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #3718 from framp/master
Added support for namespace attributes
This commit is contained in:
@@ -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"');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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.)
|
||||
|
||||
@@ -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_.\-]*$/
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user