mirror of
https://github.com/facebook/react.git
synced 2026-02-25 05:03:03 +00:00
261 lines
6.6 KiB
JavaScript
261 lines
6.6 KiB
JavaScript
/**
|
|
* Copyright 2013 Facebook, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* @providesModule DOMProperty
|
|
* @typechecks
|
|
*/
|
|
|
|
/*jslint bitwise: true */
|
|
|
|
"use strict";
|
|
|
|
var invariant = require('invariant');
|
|
|
|
/**
|
|
* DOMProperty exports lookup objects that can be used like functions:
|
|
*
|
|
* > DOMProperty.isValid['id']
|
|
* true
|
|
* > DOMProperty.isValid['foobar']
|
|
* undefined
|
|
*
|
|
* Although this may be confusing, it performs better in general.
|
|
*
|
|
* @see http://jsperf.com/key-exists
|
|
* @see http://jsperf.com/key-missing
|
|
*/
|
|
var DOMProperty = {
|
|
|
|
/**
|
|
* Checks whether a property name is a standard property.
|
|
* @type {Object}
|
|
*/
|
|
isStandardName: {},
|
|
|
|
/**
|
|
* Mapping from normalized names to attribute names that differ. Attribute
|
|
* names are used when rendering markup or with `*Attribute()`.
|
|
* @type {Object}
|
|
*/
|
|
getAttributeName: {},
|
|
|
|
/**
|
|
* Mapping from normalized names to properties on DOM node instances.
|
|
* (This includes properties that mutate due to external factors.)
|
|
* @type {Object}
|
|
*/
|
|
getPropertyName: {},
|
|
|
|
/**
|
|
* Mapping from normalized names to mutation methods. This will only exist if
|
|
* mutation cannot be set simply by the property or `setAttribute()`.
|
|
* @type {Object}
|
|
*/
|
|
getMutationMethod: {},
|
|
|
|
/**
|
|
* Whether the property must be accessed and mutated as an object property.
|
|
* @type {Object}
|
|
*/
|
|
mustUseAttribute: {},
|
|
|
|
/**
|
|
* Whether the property must be accessed and mutated using `*Attribute()`.
|
|
* (This includes anything that fails `<propName> in <element>`.)
|
|
* @type {Object}
|
|
*/
|
|
mustUseProperty: {},
|
|
|
|
/**
|
|
* Whether the property should be removed when set to a falsey value.
|
|
* @type {Object}
|
|
*/
|
|
hasBooleanValue: {},
|
|
|
|
/**
|
|
* Whether or not setting a value causes side effects such as triggering
|
|
* resources to be loaded or text selection changes. We must ensure that
|
|
* the value is only set if it has changed.
|
|
* @type {Object}
|
|
*/
|
|
hasSideEffects: {},
|
|
|
|
/**
|
|
* Checks whether a property name is a custom attribute.
|
|
* @method
|
|
*/
|
|
isCustomAttribute: RegExp.prototype.test.bind(
|
|
/^(data|aria)-[a-z_][a-z\d_.\-]*$/
|
|
)
|
|
};
|
|
|
|
/**
|
|
* Mapping from normalized, camelcased property names to a configuration that
|
|
* specifies how the associated DOM property should be accessed or rendered.
|
|
*/
|
|
var MustUseAttribute = 0x1;
|
|
var MustUseProperty = 0x2;
|
|
var HasBooleanValue = 0x4;
|
|
var HasSideEffects = 0x8;
|
|
|
|
var Properties = {
|
|
/**
|
|
* Standard Properties
|
|
*/
|
|
accept: null,
|
|
action: null,
|
|
ajaxify: MustUseAttribute,
|
|
allowFullScreen: MustUseAttribute | HasBooleanValue,
|
|
alt: null,
|
|
autoComplete: null,
|
|
autoplay: HasBooleanValue,
|
|
cellPadding: null,
|
|
cellSpacing: null,
|
|
checked: MustUseProperty | HasBooleanValue,
|
|
className: MustUseProperty,
|
|
colSpan: null,
|
|
contentEditable: null,
|
|
controls: MustUseProperty | HasBooleanValue,
|
|
data: null, // For `<object />` acts as `src`.
|
|
dir: null,
|
|
disabled: MustUseProperty | HasBooleanValue,
|
|
enctype: null,
|
|
height: null,
|
|
href: null,
|
|
htmlFor: null,
|
|
method: null,
|
|
multiple: MustUseProperty | HasBooleanValue,
|
|
name: null,
|
|
poster: null,
|
|
preload: null,
|
|
placeholder: null,
|
|
rel: null,
|
|
required: HasBooleanValue,
|
|
role: MustUseAttribute,
|
|
scrollLeft: MustUseProperty,
|
|
scrollTop: MustUseProperty,
|
|
selected: MustUseProperty | HasBooleanValue,
|
|
spellCheck: null,
|
|
src: null,
|
|
style: null,
|
|
tabIndex: null,
|
|
target: null,
|
|
title: null,
|
|
type: null,
|
|
value: MustUseProperty | HasSideEffects,
|
|
width: null,
|
|
wmode: MustUseAttribute,
|
|
/**
|
|
* SVG Properties
|
|
*/
|
|
cx: MustUseProperty,
|
|
cy: MustUseProperty,
|
|
d: MustUseProperty,
|
|
fill: MustUseProperty,
|
|
fx: MustUseProperty,
|
|
fy: MustUseProperty,
|
|
points: MustUseProperty,
|
|
r: MustUseProperty,
|
|
stroke: MustUseProperty,
|
|
strokeLinecap: MustUseProperty,
|
|
strokeWidth: MustUseProperty,
|
|
transform: MustUseProperty,
|
|
x: MustUseProperty,
|
|
x1: MustUseProperty,
|
|
x2: MustUseProperty,
|
|
version: MustUseProperty,
|
|
viewBox: MustUseProperty,
|
|
y: MustUseProperty,
|
|
y1: MustUseProperty,
|
|
y2: MustUseProperty,
|
|
spreadMethod: MustUseProperty,
|
|
offset: MustUseProperty,
|
|
stopColor: MustUseProperty,
|
|
stopOpacity: MustUseProperty,
|
|
gradientUnits: MustUseProperty,
|
|
gradientTransform: MustUseProperty
|
|
};
|
|
|
|
/**
|
|
* Attribute names not specified use the **lowercase** normalized name.
|
|
*/
|
|
var DOMAttributeNames = {
|
|
className: 'class',
|
|
htmlFor: 'for',
|
|
strokeLinecap: 'stroke-linecap',
|
|
strokeWidth: 'stroke-width',
|
|
stopColor: 'stop-color',
|
|
stopOpacity: 'stop-opacity'
|
|
};
|
|
|
|
/**
|
|
* Property names not specified use the normalized name.
|
|
*/
|
|
var DOMPropertyNames = {
|
|
autoComplete: 'autocomplete',
|
|
spellCheck: 'spellcheck'
|
|
};
|
|
|
|
/**
|
|
* Properties that require special mutation methods.
|
|
*/
|
|
var DOMMutationMethods = {
|
|
/**
|
|
* Setting `className` to null may cause it to be set to the string "null".
|
|
*
|
|
* @param {DOMElement} node
|
|
* @param {*} value
|
|
*/
|
|
className: function(node, value) {
|
|
node.className = value || '';
|
|
}
|
|
};
|
|
|
|
for (var propName in Properties) {
|
|
DOMProperty.isStandardName[propName] = true;
|
|
|
|
DOMProperty.getAttributeName[propName] =
|
|
DOMAttributeNames[propName] || propName.toLowerCase();
|
|
|
|
DOMProperty.getPropertyName[propName] =
|
|
DOMPropertyNames[propName] || propName;
|
|
|
|
var mutationMethod = DOMMutationMethods[propName];
|
|
if (mutationMethod) {
|
|
DOMProperty.getMutationMethod[propName] = mutationMethod;
|
|
}
|
|
|
|
var propConfig = Properties[propName];
|
|
DOMProperty.mustUseAttribute[propName] = propConfig & MustUseAttribute;
|
|
DOMProperty.mustUseProperty[propName] = propConfig & MustUseProperty;
|
|
DOMProperty.hasBooleanValue[propName] = propConfig & HasBooleanValue;
|
|
DOMProperty.hasSideEffects[propName] = propConfig & HasSideEffects;
|
|
|
|
invariant(
|
|
!DOMProperty.mustUseAttribute[propName] ||
|
|
!DOMProperty.mustUseProperty[propName],
|
|
'DOMProperty: Cannot use require using both attribute and property: %s',
|
|
propName
|
|
);
|
|
invariant(
|
|
DOMProperty.mustUseProperty[propName] ||
|
|
!DOMProperty.hasSideEffects[propName],
|
|
'DOMProperty: Properties that have side effects must use property: %s',
|
|
propName
|
|
);
|
|
}
|
|
|
|
module.exports = DOMProperty;
|