Skip to content

Commit

Permalink
Merge pull request #1510 from syranide/propattr
Browse files Browse the repository at this point in the history
Use removeAttribute to forcefully remove properties from the DOM
  • Loading branch information
jimfb committed Jan 29, 2016
2 parents 9c3f595 + 77a137a commit 67e1291
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 191 deletions.
44 changes: 6 additions & 38 deletions src/renderers/dom/shared/DOMProperty.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ var DOMPropertyInjection = {
* Mapping from normalized, camelcased property names to a configuration that
* specifies how the associated DOM property should be accessed or rendered.
*/
MUST_USE_ATTRIBUTE: 0x1,
MUST_USE_PROPERTY: 0x2,
HAS_SIDE_EFFECTS: 0x4,
HAS_BOOLEAN_VALUE: 0x8,
HAS_NUMERIC_VALUE: 0x10,
HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,
MUST_USE_PROPERTY: 0x1,
HAS_SIDE_EFFECTS: 0x2,
HAS_BOOLEAN_VALUE: 0x4,
HAS_NUMERIC_VALUE: 0x8,
HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8,
HAS_OVERLOADED_BOOLEAN_VALUE: 0x20,

/**
* Inject some specialized knowledge about the DOM. This takes a config object
Expand Down Expand Up @@ -91,7 +90,6 @@ var DOMPropertyInjection = {
propertyName: propName,
mutationMethod: null,

mustUseAttribute: checkMask(propConfig, Injection.MUST_USE_ATTRIBUTE),
mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),
hasSideEffects: checkMask(propConfig, Injection.HAS_SIDE_EFFECTS),
hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE),
Expand All @@ -102,11 +100,6 @@ var DOMPropertyInjection = {
checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE),
};

invariant(
!propertyInfo.mustUseAttribute || !propertyInfo.mustUseProperty,
'DOMProperty: Cannot require using both attribute and property: %s',
propName
);
invariant(
propertyInfo.mustUseProperty || !propertyInfo.hasSideEffects,
'DOMProperty: Properties that have side effects must use property: %s',
Expand Down Expand Up @@ -148,7 +141,6 @@ var DOMPropertyInjection = {
}
},
};
var defaultValueCache = {};

var 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';

Expand Down Expand Up @@ -186,9 +178,6 @@ var DOMProperty = {
* mutationMethod:
* If non-null, used instead of the property or `setAttribute()` after
* initial render.
* mustUseAttribute:
* Whether the property must be accessed and mutated using `*Attribute()`.
* (This includes anything that fails `<propName> in <element>`.)
* mustUseProperty:
* Whether the property must be accessed and mutated as an object property.
* hasSideEffects:
Expand Down Expand Up @@ -237,27 +226,6 @@ var DOMProperty = {
return false;
},

/**
* Returns the default property value for a DOM property (i.e., not an
* attribute). Most default values are '' or false, but not all. Worse yet,
* some (in particular, `type`) vary depending on the type of element.
*
* TODO: Is it better to grab all the possible properties when creating an
* element to avoid having to create the same element twice?
*/
getDefaultValueForProperty: function(nodeName, prop) {
var nodeDefaults = defaultValueCache[nodeName];
var testElement;
if (!nodeDefaults) {
defaultValueCache[nodeName] = nodeDefaults = {};
}
if (!(prop in nodeDefaults)) {
testElement = document.createElement(nodeName);
nodeDefaults[prop] = testElement[prop];
}
return nodeDefaults[prop];
},

injection: DOMPropertyInjection,
};

Expand Down
43 changes: 22 additions & 21 deletions src/renderers/dom/shared/DOMPropertyOperations.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,17 @@ var DOMPropertyOperations = {
mutationMethod(node, value);
} else if (shouldIgnoreValue(propertyInfo, value)) {
this.deleteValueForProperty(node, name);
} else if (propertyInfo.mustUseAttribute) {
} else if (propertyInfo.mustUseProperty) {
var propName = propertyInfo.propertyName;
// Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
// property type before comparing; only `value` does and is string.
if (!propertyInfo.hasSideEffects ||
('' + node[propName]) !== ('' + value)) {
// Contrary to `setAttribute`, object properties are properly
// `toString`ed by IE8/9.
node[propName] = value;
}
} else {
var attributeName = propertyInfo.attributeName;
var namespace = propertyInfo.attributeNamespace;
// `setAttribute` with objects becomes only `[object]` in IE8/9,
Expand All @@ -181,16 +191,6 @@ var DOMPropertyOperations = {
} else {
node.setAttribute(attributeName, '' + value);
}
} else {
var propName = propertyInfo.propertyName;
// Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
// property type before comparing; only `value` does and is string.
if (!propertyInfo.hasSideEffects ||
('' + node[propName]) !== ('' + value)) {
// Contrary to `setAttribute`, object properties are properly
// `toString`ed by IE8/9.
node[propName] = value;
}
}
} else if (DOMProperty.isCustomAttribute(name)) {
DOMPropertyOperations.setValueForAttribute(node, name, value);
Expand Down Expand Up @@ -236,18 +236,19 @@ var DOMPropertyOperations = {
var mutationMethod = propertyInfo.mutationMethod;
if (mutationMethod) {
mutationMethod(node, undefined);
} else if (propertyInfo.mustUseAttribute) {
node.removeAttribute(propertyInfo.attributeName);
} else {
} else if (propertyInfo.mustUseProperty) {
var propName = propertyInfo.propertyName;
var defaultValue = DOMProperty.getDefaultValueForProperty(
node.nodeName,
propName
);
if (!propertyInfo.hasSideEffects ||
('' + node[propName]) !== defaultValue) {
node[propName] = defaultValue;
if (propertyInfo.hasBooleanValue) {
// No HAS_SIDE_EFFECTS logic here, only `value` has it and is string.
node[propName] = false;
} else {
if (!propertyInfo.hasSideEffects ||
('' + node[propName]) !== '') {
node[propName] = '';
}
}
} else {
node.removeAttribute(propertyInfo.attributeName);
}
} else if (DOMProperty.isCustomAttribute(name)) {
node.removeAttribute(name);
Expand Down
Loading

0 comments on commit 67e1291

Please sign in to comment.