Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80529 views
1
/**
2
* Copyright 2013-2015, 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
* @providesModule DOMProperty
10
* @typechecks static-only
11
*/
12
13
/*jslint bitwise: true */
14
15
'use strict';
16
17
var invariant = require("./invariant");
18
19
function checkMask(value, bitmask) {
20
return (value & bitmask) === bitmask;
21
}
22
23
var DOMPropertyInjection = {
24
/**
25
* Mapping from normalized, camelcased property names to a configuration that
26
* specifies how the associated DOM property should be accessed or rendered.
27
*/
28
MUST_USE_ATTRIBUTE: 0x1,
29
MUST_USE_PROPERTY: 0x2,
30
HAS_SIDE_EFFECTS: 0x4,
31
HAS_BOOLEAN_VALUE: 0x8,
32
HAS_NUMERIC_VALUE: 0x10,
33
HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
34
HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,
35
36
/**
37
* Inject some specialized knowledge about the DOM. This takes a config object
38
* with the following properties:
39
*
40
* isCustomAttribute: function that given an attribute name will return true
41
* if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
42
* attributes where it's impossible to enumerate all of the possible
43
* attribute names,
44
*
45
* Properties: object mapping DOM property name to one of the
46
* DOMPropertyInjection constants or null. If your attribute isn't in here,
47
* it won't get written to the DOM.
48
*
49
* DOMAttributeNames: object mapping React attribute name to the DOM
50
* attribute name. Attribute names not specified use the **lowercase**
51
* normalized name.
52
*
53
* DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
54
* Property names not specified use the normalized name.
55
*
56
* DOMMutationMethods: Properties that require special mutation methods. If
57
* `value` is undefined, the mutation method should unset the property.
58
*
59
* @param {object} domPropertyConfig the config as described above.
60
*/
61
injectDOMPropertyConfig: function(domPropertyConfig) {
62
var Properties = domPropertyConfig.Properties || {};
63
var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
64
var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
65
var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
66
67
if (domPropertyConfig.isCustomAttribute) {
68
DOMProperty._isCustomAttributeFunctions.push(
69
domPropertyConfig.isCustomAttribute
70
);
71
}
72
73
for (var propName in Properties) {
74
("production" !== process.env.NODE_ENV ? invariant(
75
!DOMProperty.isStandardName.hasOwnProperty(propName),
76
'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
77
'\'%s\' which has already been injected. You may be accidentally ' +
78
'injecting the same DOM property config twice, or you may be ' +
79
'injecting two configs that have conflicting property names.',
80
propName
81
) : invariant(!DOMProperty.isStandardName.hasOwnProperty(propName)));
82
83
DOMProperty.isStandardName[propName] = true;
84
85
var lowerCased = propName.toLowerCase();
86
DOMProperty.getPossibleStandardName[lowerCased] = propName;
87
88
if (DOMAttributeNames.hasOwnProperty(propName)) {
89
var attributeName = DOMAttributeNames[propName];
90
DOMProperty.getPossibleStandardName[attributeName] = propName;
91
DOMProperty.getAttributeName[propName] = attributeName;
92
} else {
93
DOMProperty.getAttributeName[propName] = lowerCased;
94
}
95
96
DOMProperty.getPropertyName[propName] =
97
DOMPropertyNames.hasOwnProperty(propName) ?
98
DOMPropertyNames[propName] :
99
propName;
100
101
if (DOMMutationMethods.hasOwnProperty(propName)) {
102
DOMProperty.getMutationMethod[propName] = DOMMutationMethods[propName];
103
} else {
104
DOMProperty.getMutationMethod[propName] = null;
105
}
106
107
var propConfig = Properties[propName];
108
DOMProperty.mustUseAttribute[propName] =
109
checkMask(propConfig, DOMPropertyInjection.MUST_USE_ATTRIBUTE);
110
DOMProperty.mustUseProperty[propName] =
111
checkMask(propConfig, DOMPropertyInjection.MUST_USE_PROPERTY);
112
DOMProperty.hasSideEffects[propName] =
113
checkMask(propConfig, DOMPropertyInjection.HAS_SIDE_EFFECTS);
114
DOMProperty.hasBooleanValue[propName] =
115
checkMask(propConfig, DOMPropertyInjection.HAS_BOOLEAN_VALUE);
116
DOMProperty.hasNumericValue[propName] =
117
checkMask(propConfig, DOMPropertyInjection.HAS_NUMERIC_VALUE);
118
DOMProperty.hasPositiveNumericValue[propName] =
119
checkMask(propConfig, DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE);
120
DOMProperty.hasOverloadedBooleanValue[propName] =
121
checkMask(propConfig, DOMPropertyInjection.HAS_OVERLOADED_BOOLEAN_VALUE);
122
123
("production" !== process.env.NODE_ENV ? invariant(
124
!DOMProperty.mustUseAttribute[propName] ||
125
!DOMProperty.mustUseProperty[propName],
126
'DOMProperty: Cannot require using both attribute and property: %s',
127
propName
128
) : invariant(!DOMProperty.mustUseAttribute[propName] ||
129
!DOMProperty.mustUseProperty[propName]));
130
("production" !== process.env.NODE_ENV ? invariant(
131
DOMProperty.mustUseProperty[propName] ||
132
!DOMProperty.hasSideEffects[propName],
133
'DOMProperty: Properties that have side effects must use property: %s',
134
propName
135
) : invariant(DOMProperty.mustUseProperty[propName] ||
136
!DOMProperty.hasSideEffects[propName]));
137
("production" !== process.env.NODE_ENV ? invariant(
138
!!DOMProperty.hasBooleanValue[propName] +
139
!!DOMProperty.hasNumericValue[propName] +
140
!!DOMProperty.hasOverloadedBooleanValue[propName] <= 1,
141
'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
142
'numeric value, but not a combination: %s',
143
propName
144
) : invariant(!!DOMProperty.hasBooleanValue[propName] +
145
!!DOMProperty.hasNumericValue[propName] +
146
!!DOMProperty.hasOverloadedBooleanValue[propName] <= 1));
147
}
148
}
149
};
150
var defaultValueCache = {};
151
152
/**
153
* DOMProperty exports lookup objects that can be used like functions:
154
*
155
* > DOMProperty.isValid['id']
156
* true
157
* > DOMProperty.isValid['foobar']
158
* undefined
159
*
160
* Although this may be confusing, it performs better in general.
161
*
162
* @see http://jsperf.com/key-exists
163
* @see http://jsperf.com/key-missing
164
*/
165
var DOMProperty = {
166
167
ID_ATTRIBUTE_NAME: 'data-reactid',
168
169
/**
170
* Checks whether a property name is a standard property.
171
* @type {Object}
172
*/
173
isStandardName: {},
174
175
/**
176
* Mapping from lowercase property names to the properly cased version, used
177
* to warn in the case of missing properties.
178
* @type {Object}
179
*/
180
getPossibleStandardName: {},
181
182
/**
183
* Mapping from normalized names to attribute names that differ. Attribute
184
* names are used when rendering markup or with `*Attribute()`.
185
* @type {Object}
186
*/
187
getAttributeName: {},
188
189
/**
190
* Mapping from normalized names to properties on DOM node instances.
191
* (This includes properties that mutate due to external factors.)
192
* @type {Object}
193
*/
194
getPropertyName: {},
195
196
/**
197
* Mapping from normalized names to mutation methods. This will only exist if
198
* mutation cannot be set simply by the property or `setAttribute()`.
199
* @type {Object}
200
*/
201
getMutationMethod: {},
202
203
/**
204
* Whether the property must be accessed and mutated as an object property.
205
* @type {Object}
206
*/
207
mustUseAttribute: {},
208
209
/**
210
* Whether the property must be accessed and mutated using `*Attribute()`.
211
* (This includes anything that fails `<propName> in <element>`.)
212
* @type {Object}
213
*/
214
mustUseProperty: {},
215
216
/**
217
* Whether or not setting a value causes side effects such as triggering
218
* resources to be loaded or text selection changes. We must ensure that
219
* the value is only set if it has changed.
220
* @type {Object}
221
*/
222
hasSideEffects: {},
223
224
/**
225
* Whether the property should be removed when set to a falsey value.
226
* @type {Object}
227
*/
228
hasBooleanValue: {},
229
230
/**
231
* Whether the property must be numeric or parse as a
232
* numeric and should be removed when set to a falsey value.
233
* @type {Object}
234
*/
235
hasNumericValue: {},
236
237
/**
238
* Whether the property must be positive numeric or parse as a positive
239
* numeric and should be removed when set to a falsey value.
240
* @type {Object}
241
*/
242
hasPositiveNumericValue: {},
243
244
/**
245
* Whether the property can be used as a flag as well as with a value. Removed
246
* when strictly equal to false; present without a value when strictly equal
247
* to true; present with a value otherwise.
248
* @type {Object}
249
*/
250
hasOverloadedBooleanValue: {},
251
252
/**
253
* All of the isCustomAttribute() functions that have been injected.
254
*/
255
_isCustomAttributeFunctions: [],
256
257
/**
258
* Checks whether a property name is a custom attribute.
259
* @method
260
*/
261
isCustomAttribute: function(attributeName) {
262
for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
263
var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
264
if (isCustomAttributeFn(attributeName)) {
265
return true;
266
}
267
}
268
return false;
269
},
270
271
/**
272
* Returns the default property value for a DOM property (i.e., not an
273
* attribute). Most default values are '' or false, but not all. Worse yet,
274
* some (in particular, `type`) vary depending on the type of element.
275
*
276
* TODO: Is it better to grab all the possible properties when creating an
277
* element to avoid having to create the same element twice?
278
*/
279
getDefaultValueForProperty: function(nodeName, prop) {
280
var nodeDefaults = defaultValueCache[nodeName];
281
var testElement;
282
if (!nodeDefaults) {
283
defaultValueCache[nodeName] = nodeDefaults = {};
284
}
285
if (!(prop in nodeDefaults)) {
286
testElement = document.createElement(nodeName);
287
nodeDefaults[prop] = testElement[prop];
288
}
289
return nodeDefaults[prop];
290
},
291
292
injection: DOMPropertyInjection
293
};
294
295
module.exports = DOMProperty;
296
297