UNPKG

8.24 kBJavaScriptView Raw
1/**
2 * Copyright 2013-present, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 */
10
11'use strict';
12
13var _prodInvariant = require('./reactProdInvariant');
14
15var invariant = require('fbjs/lib/invariant');
16
17function checkMask(value, bitmask) {
18 return (value & bitmask) === bitmask;
19}
20
21var DOMPropertyInjection = {
22 /**
23 * Mapping from normalized, camelcased property names to a configuration that
24 * specifies how the associated DOM property should be accessed or rendered.
25 */
26 MUST_USE_PROPERTY: 0x1,
27 HAS_BOOLEAN_VALUE: 0x4,
28 HAS_NUMERIC_VALUE: 0x8,
29 HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8,
30 HAS_OVERLOADED_BOOLEAN_VALUE: 0x20,
31
32 /**
33 * Inject some specialized knowledge about the DOM. This takes a config object
34 * with the following properties:
35 *
36 * isCustomAttribute: function that given an attribute name will return true
37 * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
38 * attributes where it's impossible to enumerate all of the possible
39 * attribute names,
40 *
41 * Properties: object mapping DOM property name to one of the
42 * DOMPropertyInjection constants or null. If your attribute isn't in here,
43 * it won't get written to the DOM.
44 *
45 * DOMAttributeNames: object mapping React attribute name to the DOM
46 * attribute name. Attribute names not specified use the **lowercase**
47 * normalized name.
48 *
49 * DOMAttributeNamespaces: object mapping React attribute name to the DOM
50 * attribute namespace URL. (Attribute names not specified use no namespace.)
51 *
52 * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
53 * Property names not specified use the normalized name.
54 *
55 * DOMMutationMethods: Properties that require special mutation methods. If
56 * `value` is undefined, the mutation method should unset the property.
57 *
58 * @param {object} domPropertyConfig the config as described above.
59 */
60 injectDOMPropertyConfig: function (domPropertyConfig) {
61 var Injection = DOMPropertyInjection;
62 var Properties = domPropertyConfig.Properties || {};
63 var DOMAttributeNamespaces = domPropertyConfig.DOMAttributeNamespaces || {};
64 var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
65 var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
66 var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
67
68 if (domPropertyConfig.isCustomAttribute) {
69 DOMProperty._isCustomAttributeFunctions.push(domPropertyConfig.isCustomAttribute);
70 }
71
72 for (var propName in Properties) {
73 !!DOMProperty.properties.hasOwnProperty(propName) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property \'%s\' which has already been injected. You may be accidentally injecting the same DOM property config twice, or you may be injecting two configs that have conflicting property names.', propName) : _prodInvariant('48', propName) : void 0;
74
75 var lowerCased = propName.toLowerCase();
76 var propConfig = Properties[propName];
77
78 var propertyInfo = {
79 attributeName: lowerCased,
80 attributeNamespace: null,
81 propertyName: propName,
82 mutationMethod: null,
83
84 mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),
85 hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE),
86 hasNumericValue: checkMask(propConfig, Injection.HAS_NUMERIC_VALUE),
87 hasPositiveNumericValue: checkMask(propConfig, Injection.HAS_POSITIVE_NUMERIC_VALUE),
88 hasOverloadedBooleanValue: checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE)
89 };
90 !(propertyInfo.hasBooleanValue + propertyInfo.hasNumericValue + propertyInfo.hasOverloadedBooleanValue <= 1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'DOMProperty: Value can be one of boolean, overloaded boolean, or numeric value, but not a combination: %s', propName) : _prodInvariant('50', propName) : void 0;
91
92 if (process.env.NODE_ENV !== 'production') {
93 DOMProperty.getPossibleStandardName[lowerCased] = propName;
94 }
95
96 if (DOMAttributeNames.hasOwnProperty(propName)) {
97 var attributeName = DOMAttributeNames[propName];
98 propertyInfo.attributeName = attributeName;
99 if (process.env.NODE_ENV !== 'production') {
100 DOMProperty.getPossibleStandardName[attributeName] = propName;
101 }
102 }
103
104 if (DOMAttributeNamespaces.hasOwnProperty(propName)) {
105 propertyInfo.attributeNamespace = DOMAttributeNamespaces[propName];
106 }
107
108 if (DOMPropertyNames.hasOwnProperty(propName)) {
109 propertyInfo.propertyName = DOMPropertyNames[propName];
110 }
111
112 if (DOMMutationMethods.hasOwnProperty(propName)) {
113 propertyInfo.mutationMethod = DOMMutationMethods[propName];
114 }
115
116 DOMProperty.properties[propName] = propertyInfo;
117 }
118 }
119};
120
121/* eslint-disable max-len */
122var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
123/* eslint-enable max-len */
124
125/**
126 * DOMProperty exports lookup objects that can be used like functions:
127 *
128 * > DOMProperty.isValid['id']
129 * true
130 * > DOMProperty.isValid['foobar']
131 * undefined
132 *
133 * Although this may be confusing, it performs better in general.
134 *
135 * @see http://jsperf.com/key-exists
136 * @see http://jsperf.com/key-missing
137 */
138var DOMProperty = {
139 ID_ATTRIBUTE_NAME: 'data-reactid',
140 ROOT_ATTRIBUTE_NAME: 'data-reactroot',
141
142 ATTRIBUTE_NAME_START_CHAR: ATTRIBUTE_NAME_START_CHAR,
143 ATTRIBUTE_NAME_CHAR: ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040',
144
145 /**
146 * Map from property "standard name" to an object with info about how to set
147 * the property in the DOM. Each object contains:
148 *
149 * attributeName:
150 * Used when rendering markup or with `*Attribute()`.
151 * attributeNamespace
152 * propertyName:
153 * Used on DOM node instances. (This includes properties that mutate due to
154 * external factors.)
155 * mutationMethod:
156 * If non-null, used instead of the property or `setAttribute()` after
157 * initial render.
158 * mustUseProperty:
159 * Whether the property must be accessed and mutated as an object property.
160 * hasBooleanValue:
161 * Whether the property should be removed when set to a falsey value.
162 * hasNumericValue:
163 * Whether the property must be numeric or parse as a numeric and should be
164 * removed when set to a falsey value.
165 * hasPositiveNumericValue:
166 * Whether the property must be positive numeric or parse as a positive
167 * numeric and should be removed when set to a falsey value.
168 * hasOverloadedBooleanValue:
169 * Whether the property can be used as a flag as well as with a value.
170 * Removed when strictly equal to false; present without a value when
171 * strictly equal to true; present with a value otherwise.
172 */
173 properties: {},
174
175 /**
176 * Mapping from lowercase property names to the properly cased version, used
177 * to warn in the case of missing properties. Available only in __DEV__.
178 *
179 * autofocus is predefined, because adding it to the property whitelist
180 * causes unintended side effects.
181 *
182 * @type {Object}
183 */
184 getPossibleStandardName: process.env.NODE_ENV !== 'production' ? { autofocus: 'autoFocus' } : null,
185
186 /**
187 * All of the isCustomAttribute() functions that have been injected.
188 */
189 _isCustomAttributeFunctions: [],
190
191 /**
192 * Checks whether a property name is a custom attribute.
193 * @method
194 */
195 isCustomAttribute: function (attributeName) {
196 for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
197 var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
198 if (isCustomAttributeFn(attributeName)) {
199 return true;
200 }
201 }
202 return false;
203 },
204
205 injection: DOMPropertyInjection
206};
207
208module.exports = DOMProperty;
\No newline at end of file