import {
getPropertyInfo,
shouldIgnoreAttribute,
shouldRemoveAttribute,
isAttributeNameSafe,
BOOLEAN,
OVERLOADED_BOOLEAN,
} from '../shared/DOMProperty';
import sanitizeURL from '../shared/sanitizeURL';
import {
disableJavaScriptURLs,
enableTrustedTypesIntegration,
enableCustomElementPropertySupport,
} from 'shared/ReactFeatureFlags';
import {checkAttributeStringCoercion} from 'shared/CheckStringCoercion';
import {getFiberCurrentPropsFromNode} from './ReactDOMComponentTree';
import type {PropertyInfo} from '../shared/DOMProperty';
export function getValueForProperty(
node: Element,
name: string,
expected: mixed,
propertyInfo: PropertyInfo,
): mixed {
if (__DEV__) {
if (propertyInfo.mustUseProperty) {
const {propertyName} = propertyInfo;
return (node: any)[propertyName];
} else {
if (__DEV__) {
checkAttributeStringCoercion(expected, name);
}
if (!disableJavaScriptURLs && propertyInfo.sanitizeURL) {
sanitizeURL('' + (expected: any));
}
const attributeName = propertyInfo.attributeName;
let stringValue = null;
if (propertyInfo.type === OVERLOADED_BOOLEAN) {
if (node.hasAttribute(attributeName)) {
const value = node.getAttribute(attributeName);
if (value === '') {
return true;
}
if (shouldRemoveAttribute(name, expected, propertyInfo, false)) {
return value;
}
if (value === '' + (expected: any)) {
return expected;
}
return value;
}
} else if (node.hasAttribute(attributeName)) {
if (shouldRemoveAttribute(name, expected, propertyInfo, false)) {
return node.getAttribute(attributeName);
}
if (propertyInfo.type === BOOLEAN) {
return expected;
}
stringValue = node.getAttribute(attributeName);
}
if (shouldRemoveAttribute(name, expected, propertyInfo, false)) {
return stringValue === null ? expected : stringValue;
} else if (stringValue === '' + (expected: any)) {
return expected;
} else {
return stringValue;
}
}
}
}
export function getValueForAttribute(
node: Element,
name: string,
expected: mixed,
isCustomComponentTag: boolean,
): mixed {
if (__DEV__) {
if (!isAttributeNameSafe(name)) {
return;
}
if (!node.hasAttribute(name)) {
return expected === undefined ? undefined : null;
}
const value = node.getAttribute(name);
if (enableCustomElementPropertySupport) {
if (isCustomComponentTag && value === '') {
return true;
}
}
if (__DEV__) {
checkAttributeStringCoercion(expected, name);
}
if (value === '' + (expected: any)) {
return expected;
}
return value;
}
}
export function setValueForProperty(
node: Element,
name: string,
value: mixed,
isCustomComponentTag: boolean,
) {
const propertyInfo = getPropertyInfo(name);
if (shouldIgnoreAttribute(name, propertyInfo, isCustomComponentTag)) {
return;
}
if (
enableCustomElementPropertySupport &&
isCustomComponentTag &&
name[0] === 'o' &&
name[1] === 'n'
) {
let eventName = name.replace(/Capture$/, '');
const useCapture = name !== eventName;
eventName = eventName.slice(2);
const prevProps = getFiberCurrentPropsFromNode(node);
const prevValue = prevProps != null ? prevProps[name] : null;
if (typeof prevValue === 'function') {
node.removeEventListener(eventName, prevValue, useCapture);
}
if (typeof value === 'function') {
if (typeof prevValue !== 'function' && prevValue !== null) {
if (name in (node: any)) {
(node: any)[name] = null;
} else if (node.hasAttribute(name)) {
node.removeAttribute(name);
}
}
node.addEventListener(eventName, (value: EventListener), useCapture);
return;
}
}
if (
enableCustomElementPropertySupport &&
isCustomComponentTag &&
name in (node: any)
) {
(node: any)[name] = value;
return;
}
if (shouldRemoveAttribute(name, value, propertyInfo, isCustomComponentTag)) {
value = null;
}
if (enableCustomElementPropertySupport) {
if (isCustomComponentTag && value === true) {
value = '';
}
}
if (isCustomComponentTag || propertyInfo === null) {
if (isAttributeNameSafe(name)) {
const attributeName = name;
if (value === null) {
node.removeAttribute(attributeName);
} else {
if (__DEV__) {
checkAttributeStringCoercion(value, name);
}
node.setAttribute(
attributeName,
enableTrustedTypesIntegration ? (value: any) : '' + (value: any),
);
}
}
return;
}
const {mustUseProperty} = propertyInfo;
if (mustUseProperty) {
const {propertyName} = propertyInfo;
if (value === null) {
const {type} = propertyInfo;
(node: any)[propertyName] = type === BOOLEAN ? false : '';
} else {
(node: any)[propertyName] = value;
}
return;
}
const {attributeName, attributeNamespace} = propertyInfo;
if (value === null) {
node.removeAttribute(attributeName);
} else {
const {type} = propertyInfo;
let attributeValue;
if (type === BOOLEAN || (type === OVERLOADED_BOOLEAN && value === true)) {
attributeValue = '';
} else {
if (enableTrustedTypesIntegration) {
attributeValue = (value: any);
} else {
if (__DEV__) {
checkAttributeStringCoercion(value, attributeName);
}
attributeValue = '' + (value: any);
}
if (propertyInfo.sanitizeURL) {
sanitizeURL(attributeValue.toString());
}
}
if (attributeNamespace) {
node.setAttributeNS(attributeNamespace, attributeName, attributeValue);
} else {
node.setAttribute(attributeName, attributeValue);
}
}
}