Skip to content

Commit 67e1291

Browse files
committed
Merge pull request #1510 from syranide/propattr
Use removeAttribute to forcefully remove properties from the DOM
2 parents 9c3f595 + 77a137a commit 67e1291

File tree

6 files changed

+278
-191
lines changed

6 files changed

+278
-191
lines changed

src/renderers/dom/shared/DOMProperty.js

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@ var DOMPropertyInjection = {
2222
* Mapping from normalized, camelcased property names to a configuration that
2323
* specifies how the associated DOM property should be accessed or rendered.
2424
*/
25-
MUST_USE_ATTRIBUTE: 0x1,
26-
MUST_USE_PROPERTY: 0x2,
27-
HAS_SIDE_EFFECTS: 0x4,
28-
HAS_BOOLEAN_VALUE: 0x8,
29-
HAS_NUMERIC_VALUE: 0x10,
30-
HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
31-
HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,
25+
MUST_USE_PROPERTY: 0x1,
26+
HAS_SIDE_EFFECTS: 0x2,
27+
HAS_BOOLEAN_VALUE: 0x4,
28+
HAS_NUMERIC_VALUE: 0x8,
29+
HAS_POSITIVE_NUMERIC_VALUE: 0x10 | 0x8,
30+
HAS_OVERLOADED_BOOLEAN_VALUE: 0x20,
3231

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

94-
mustUseAttribute: checkMask(propConfig, Injection.MUST_USE_ATTRIBUTE),
9593
mustUseProperty: checkMask(propConfig, Injection.MUST_USE_PROPERTY),
9694
hasSideEffects: checkMask(propConfig, Injection.HAS_SIDE_EFFECTS),
9795
hasBooleanValue: checkMask(propConfig, Injection.HAS_BOOLEAN_VALUE),
@@ -102,11 +100,6 @@ var DOMPropertyInjection = {
102100
checkMask(propConfig, Injection.HAS_OVERLOADED_BOOLEAN_VALUE),
103101
};
104102

105-
invariant(
106-
!propertyInfo.mustUseAttribute || !propertyInfo.mustUseProperty,
107-
'DOMProperty: Cannot require using both attribute and property: %s',
108-
propName
109-
);
110103
invariant(
111104
propertyInfo.mustUseProperty || !propertyInfo.hasSideEffects,
112105
'DOMProperty: Properties that have side effects must use property: %s',
@@ -148,7 +141,6 @@ var DOMPropertyInjection = {
148141
}
149142
},
150143
};
151-
var defaultValueCache = {};
152144

153145
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';
154146

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

240-
/**
241-
* Returns the default property value for a DOM property (i.e., not an
242-
* attribute). Most default values are '' or false, but not all. Worse yet,
243-
* some (in particular, `type`) vary depending on the type of element.
244-
*
245-
* TODO: Is it better to grab all the possible properties when creating an
246-
* element to avoid having to create the same element twice?
247-
*/
248-
getDefaultValueForProperty: function(nodeName, prop) {
249-
var nodeDefaults = defaultValueCache[nodeName];
250-
var testElement;
251-
if (!nodeDefaults) {
252-
defaultValueCache[nodeName] = nodeDefaults = {};
253-
}
254-
if (!(prop in nodeDefaults)) {
255-
testElement = document.createElement(nodeName);
256-
nodeDefaults[prop] = testElement[prop];
257-
}
258-
return nodeDefaults[prop];
259-
},
260-
261229
injection: DOMPropertyInjection,
262230
};
263231

src/renderers/dom/shared/DOMPropertyOperations.js

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,17 @@ var DOMPropertyOperations = {
168168
mutationMethod(node, value);
169169
} else if (shouldIgnoreValue(propertyInfo, value)) {
170170
this.deleteValueForProperty(node, name);
171-
} else if (propertyInfo.mustUseAttribute) {
171+
} else if (propertyInfo.mustUseProperty) {
172+
var propName = propertyInfo.propertyName;
173+
// Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
174+
// property type before comparing; only `value` does and is string.
175+
if (!propertyInfo.hasSideEffects ||
176+
('' + node[propName]) !== ('' + value)) {
177+
// Contrary to `setAttribute`, object properties are properly
178+
// `toString`ed by IE8/9.
179+
node[propName] = value;
180+
}
181+
} else {
172182
var attributeName = propertyInfo.attributeName;
173183
var namespace = propertyInfo.attributeNamespace;
174184
// `setAttribute` with objects becomes only `[object]` in IE8/9,
@@ -181,16 +191,6 @@ var DOMPropertyOperations = {
181191
} else {
182192
node.setAttribute(attributeName, '' + value);
183193
}
184-
} else {
185-
var propName = propertyInfo.propertyName;
186-
// Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
187-
// property type before comparing; only `value` does and is string.
188-
if (!propertyInfo.hasSideEffects ||
189-
('' + node[propName]) !== ('' + value)) {
190-
// Contrary to `setAttribute`, object properties are properly
191-
// `toString`ed by IE8/9.
192-
node[propName] = value;
193-
}
194194
}
195195
} else if (DOMProperty.isCustomAttribute(name)) {
196196
DOMPropertyOperations.setValueForAttribute(node, name, value);
@@ -236,18 +236,19 @@ var DOMPropertyOperations = {
236236
var mutationMethod = propertyInfo.mutationMethod;
237237
if (mutationMethod) {
238238
mutationMethod(node, undefined);
239-
} else if (propertyInfo.mustUseAttribute) {
240-
node.removeAttribute(propertyInfo.attributeName);
241-
} else {
239+
} else if (propertyInfo.mustUseProperty) {
242240
var propName = propertyInfo.propertyName;
243-
var defaultValue = DOMProperty.getDefaultValueForProperty(
244-
node.nodeName,
245-
propName
246-
);
247-
if (!propertyInfo.hasSideEffects ||
248-
('' + node[propName]) !== defaultValue) {
249-
node[propName] = defaultValue;
241+
if (propertyInfo.hasBooleanValue) {
242+
// No HAS_SIDE_EFFECTS logic here, only `value` has it and is string.
243+
node[propName] = false;
244+
} else {
245+
if (!propertyInfo.hasSideEffects ||
246+
('' + node[propName]) !== '') {
247+
node[propName] = '';
248+
}
250249
}
250+
} else {
251+
node.removeAttribute(propertyInfo.attributeName);
251252
}
252253
} else if (DOMProperty.isCustomAttribute(name)) {
253254
node.removeAttribute(name);

0 commit comments

Comments
 (0)