UNPKG

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