mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
d9c1dbd617
* Enable Yarn workspaces for packages/* * Move src/isomorphic/* into packages/react/src/* * Create index.js stubs for all packages in packages/* This makes the test pass again, but breaks the build because npm/ folders aren't used yet. I'm not sure if we'll keep this structure--I'll just keep working and fix the build after it settles down. * Put FB entry point for react-dom into packages/* * Move src/renderers/testing/* into packages/react-test-renderer/src/* Note that this is currently broken because Jest ignores node_modules, and so Yarn linking makes Jest skip React source when transforming. * Remove src/node_modules It is now unnecessary. Some tests fail though. * Add a hacky workaround for Jest/Workspaces issue Jest sees node_modules and thinks it's third party code. This is a hacky way to teach Jest to still transform anything in node_modules/react* if it resolves outside of node_modules (such as to our packages/*) folder. I'm not very happy with this and we should revisit. * Add a fake react-native package * Move src/renderers/art/* into packages/react-art/src/* * Move src/renderers/noop/* into packages/react-noop-renderer/src/* * Move src/renderers/dom/* into packages/react-dom/src/* * Move src/renderers/shared/fiber/* into packages/react-reconciler/src/* * Move DOM/reconciler tests I previously forgot to move * Move src/renderers/native-*/* into packages/react-native-*/src/* * Move shared code into packages/shared It's not super clear how to organize this properly yet. * Add back files that somehow got lost * Fix the build * Prettier * Add missing license headers * Fix an issue that caused mocks to get included into build * Update other references to src/ * Re-run Prettier * Fix lint * Fix weird Flow violation I didn't change this file but Flow started complaining. Caleb said this annotation was unnecessarily using $Abstract though so I removed it. * Update sizes * Fix stats script * Fix packaging fixtures Use file: instead of NODE_PATH since NODE_PATH. NODE_PATH trick only worked because we had no react/react-dom in root node_modules, but now we do. file: dependency only works as I expect in Yarn, so I moved the packaging fixtures to use Yarn and committed lockfiles. Verified that the page shows up. * Fix art fixture * Fix reconciler fixture * Fix SSR fixture * Rename native packages
260 lines
7.7 KiB
JavaScript
260 lines
7.7 KiB
JavaScript
/**
|
|
* Copyright (c) 2013-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @providesModule DOMPropertyOperations
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var DOMProperty = require('DOMProperty');
|
|
|
|
if (__DEV__) {
|
|
var warning = require('fbjs/lib/warning');
|
|
}
|
|
|
|
// isAttributeNameSafe() is currently duplicated in DOMMarkupOperations.
|
|
// TODO: Find a better place for this.
|
|
var VALID_ATTRIBUTE_NAME_REGEX = new RegExp(
|
|
'^[' +
|
|
DOMProperty.ATTRIBUTE_NAME_START_CHAR +
|
|
'][' +
|
|
DOMProperty.ATTRIBUTE_NAME_CHAR +
|
|
']*$',
|
|
);
|
|
var illegalAttributeNameCache = {};
|
|
var validatedAttributeNameCache = {};
|
|
function isAttributeNameSafe(attributeName) {
|
|
if (validatedAttributeNameCache.hasOwnProperty(attributeName)) {
|
|
return true;
|
|
}
|
|
if (illegalAttributeNameCache.hasOwnProperty(attributeName)) {
|
|
return false;
|
|
}
|
|
if (VALID_ATTRIBUTE_NAME_REGEX.test(attributeName)) {
|
|
validatedAttributeNameCache[attributeName] = true;
|
|
return true;
|
|
}
|
|
illegalAttributeNameCache[attributeName] = true;
|
|
if (__DEV__) {
|
|
warning(false, 'Invalid attribute name: `%s`', attributeName);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// shouldIgnoreValue() is currently duplicated in DOMMarkupOperations.
|
|
// TODO: Find a better place for this.
|
|
function shouldIgnoreValue(propertyInfo, value) {
|
|
return (
|
|
value == null ||
|
|
(propertyInfo.hasBooleanValue && !value) ||
|
|
(propertyInfo.hasNumericValue && isNaN(value)) ||
|
|
(propertyInfo.hasPositiveNumericValue && value < 1) ||
|
|
(propertyInfo.hasOverloadedBooleanValue && value === false)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Operations for dealing with DOM properties.
|
|
*/
|
|
var DOMPropertyOperations = {
|
|
setAttributeForID: function(node, id) {
|
|
node.setAttribute(DOMProperty.ID_ATTRIBUTE_NAME, id);
|
|
},
|
|
|
|
setAttributeForRoot: function(node) {
|
|
node.setAttribute(DOMProperty.ROOT_ATTRIBUTE_NAME, '');
|
|
},
|
|
|
|
/**
|
|
* Get the value for a property on a node. Only used in DEV for SSR validation.
|
|
* The "expected" argument is used as a hint of what the expected value is.
|
|
* Some properties have multiple equivalent values.
|
|
*/
|
|
getValueForProperty: function(node, name, expected) {
|
|
if (__DEV__) {
|
|
var propertyInfo = DOMProperty.getPropertyInfo(name);
|
|
if (propertyInfo) {
|
|
var mutationMethod = propertyInfo.mutationMethod;
|
|
if (mutationMethod || propertyInfo.mustUseProperty) {
|
|
return node[propertyInfo.propertyName];
|
|
} else {
|
|
var attributeName = propertyInfo.attributeName;
|
|
|
|
var stringValue = null;
|
|
|
|
if (propertyInfo.hasOverloadedBooleanValue) {
|
|
if (node.hasAttribute(attributeName)) {
|
|
var value = node.getAttribute(attributeName);
|
|
if (value === '') {
|
|
return true;
|
|
}
|
|
if (shouldIgnoreValue(propertyInfo, expected)) {
|
|
return value;
|
|
}
|
|
if (value === '' + expected) {
|
|
return expected;
|
|
}
|
|
return value;
|
|
}
|
|
} else if (node.hasAttribute(attributeName)) {
|
|
if (shouldIgnoreValue(propertyInfo, expected)) {
|
|
// We had an attribute but shouldn't have had one, so read it
|
|
// for the error message.
|
|
return node.getAttribute(attributeName);
|
|
}
|
|
if (propertyInfo.hasBooleanValue) {
|
|
// If this was a boolean, it doesn't matter what the value is
|
|
// the fact that we have it is the same as the expected.
|
|
return expected;
|
|
}
|
|
// Even if this property uses a namespace we use getAttribute
|
|
// because we assume its namespaced name is the same as our config.
|
|
// To use getAttributeNS we need the local name which we don't have
|
|
// in our config atm.
|
|
stringValue = node.getAttribute(attributeName);
|
|
}
|
|
|
|
if (shouldIgnoreValue(propertyInfo, expected)) {
|
|
return stringValue === null ? expected : stringValue;
|
|
} else if (stringValue === '' + expected) {
|
|
return expected;
|
|
} else {
|
|
return stringValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Get the value for a attribute on a node. Only used in DEV for SSR validation.
|
|
* The third argument is used as a hint of what the expected value is. Some
|
|
* attributes have multiple equivalent values.
|
|
*/
|
|
getValueForAttribute: function(node, name, expected) {
|
|
if (__DEV__) {
|
|
if (!isAttributeNameSafe(name)) {
|
|
return;
|
|
}
|
|
if (!node.hasAttribute(name)) {
|
|
return expected === undefined ? undefined : null;
|
|
}
|
|
var value = node.getAttribute(name);
|
|
if (value === '' + expected) {
|
|
return expected;
|
|
}
|
|
return value;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Sets the value for a property on a node.
|
|
*
|
|
* @param {DOMElement} node
|
|
* @param {string} name
|
|
* @param {*} value
|
|
*/
|
|
setValueForProperty: function(node, name, value) {
|
|
var propertyInfo = DOMProperty.getPropertyInfo(name);
|
|
|
|
if (propertyInfo && DOMProperty.shouldSetAttribute(name, value)) {
|
|
var mutationMethod = propertyInfo.mutationMethod;
|
|
if (mutationMethod) {
|
|
mutationMethod(node, value);
|
|
} else if (shouldIgnoreValue(propertyInfo, value)) {
|
|
DOMPropertyOperations.deleteValueForProperty(node, name);
|
|
return;
|
|
} else if (propertyInfo.mustUseProperty) {
|
|
// Contrary to `setAttribute`, object properties are properly
|
|
// `toString`ed by IE8/9.
|
|
node[propertyInfo.propertyName] = value;
|
|
} else {
|
|
var attributeName = propertyInfo.attributeName;
|
|
var namespace = propertyInfo.attributeNamespace;
|
|
// `setAttribute` with objects becomes only `[object]` in IE8/9,
|
|
// ('' + value) makes it output the correct toString()-value.
|
|
if (namespace) {
|
|
node.setAttributeNS(namespace, attributeName, '' + value);
|
|
} else if (
|
|
propertyInfo.hasBooleanValue ||
|
|
(propertyInfo.hasOverloadedBooleanValue && value === true)
|
|
) {
|
|
node.setAttribute(attributeName, '');
|
|
} else {
|
|
node.setAttribute(attributeName, '' + value);
|
|
}
|
|
}
|
|
} else {
|
|
DOMPropertyOperations.setValueForAttribute(
|
|
node,
|
|
name,
|
|
DOMProperty.shouldSetAttribute(name, value) ? value : null,
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (__DEV__) {
|
|
var payload = {};
|
|
payload[name] = value;
|
|
}
|
|
},
|
|
|
|
setValueForAttribute: function(node, name, value) {
|
|
if (!isAttributeNameSafe(name)) {
|
|
return;
|
|
}
|
|
if (value == null) {
|
|
node.removeAttribute(name);
|
|
} else {
|
|
node.setAttribute(name, '' + value);
|
|
}
|
|
|
|
if (__DEV__) {
|
|
var payload = {};
|
|
payload[name] = value;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Deletes an attributes from a node.
|
|
*
|
|
* @param {DOMElement} node
|
|
* @param {string} name
|
|
*/
|
|
deleteValueForAttribute: function(node, name) {
|
|
node.removeAttribute(name);
|
|
},
|
|
|
|
/**
|
|
* Deletes the value for a property on a node.
|
|
*
|
|
* @param {DOMElement} node
|
|
* @param {string} name
|
|
*/
|
|
deleteValueForProperty: function(node, name) {
|
|
var propertyInfo = DOMProperty.getPropertyInfo(name);
|
|
if (propertyInfo) {
|
|
var mutationMethod = propertyInfo.mutationMethod;
|
|
if (mutationMethod) {
|
|
mutationMethod(node, undefined);
|
|
} else if (propertyInfo.mustUseProperty) {
|
|
var propName = propertyInfo.propertyName;
|
|
if (propertyInfo.hasBooleanValue) {
|
|
node[propName] = false;
|
|
} else {
|
|
node[propName] = '';
|
|
}
|
|
} else {
|
|
node.removeAttribute(propertyInfo.attributeName);
|
|
}
|
|
} else {
|
|
node.removeAttribute(name);
|
|
}
|
|
},
|
|
};
|
|
|
|
module.exports = DOMPropertyOperations;
|