Skip to content

Commit

Permalink
Support arbitrary attributes on elements with dashes in the tag name.
Browse files Browse the repository at this point in the history
  • Loading branch information
jimfb committed Feb 5, 2015
1 parent c7e4f55 commit 076a97a
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/browser/ui/ReactDOMComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ ReactDOMComponent.Mixin = {
propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
}
var markup =
DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
DOMPropertyOperations.createMarkupForProperty(this._tag, propKey, propValue);
if (markup) {
ret += ' ' + markup;
}
Expand Down
17 changes: 15 additions & 2 deletions src/browser/ui/dom/DOMPropertyOperations.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,12 @@ var DOMPropertyOperations = {
/**
* Creates markup for a property.
*
* @param {string} tagName
* @param {string} name
* @param {*} value
* @return {?string} Markup string, or null if the property was invalid.
*/
createMarkupForProperty: function(name, value) {
createMarkupForProperty: function(tagName, name, value) {
if (DOMProperty.isStandardName.hasOwnProperty(name) &&
DOMProperty.isStandardName[name]) {
if (shouldIgnoreValue(name, value)) {
Expand All @@ -105,6 +106,11 @@ var DOMPropertyOperations = {
return '';
}
return name + '=' + quoteAttributeValueForBrowser(value);
} else if (tagName != null && tagName.indexOf('-') >= 0) {
if (value == null) {
return '';
}
return name + '=' + quoteAttributeValueForBrowser(value);
} else if (__DEV__) {
warnUnknownProperty(name);
}
Expand All @@ -119,7 +125,14 @@ var DOMPropertyOperations = {
* @param {*} value
*/
setValueForProperty: function(node, name, value) {
if (DOMProperty.isStandardName.hasOwnProperty(name) &&
if (node.tagName.indexOf('-') >= 0) {
if (value == null) {
node.removeAttribute(name);
} else {
node.setAttribute(name, '' + value);
}
}
else if (DOMProperty.isStandardName.hasOwnProperty(name) &&
DOMProperty.isStandardName[name]) {
var mutationMethod = DOMProperty.getMutationMethod[name];
if (mutationMethod) {
Expand Down
44 changes: 44 additions & 0 deletions src/browser/ui/dom/__tests__/DOMPropertyOperations-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,27 @@ describe('DOMPropertyOperations', function() {

it('should create markup for simple properties', function() {
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'name',
'simple'
)).toBe('name="simple"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'name',
false
)).toBe('name="false"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'name',
null
)).toBe('');
});

it('should work with the id attribute', function() {
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'id',
'simple'
)).toBe('id="simple"');
Expand All @@ -57,6 +61,7 @@ describe('DOMPropertyOperations', function() {
it('should warn about incorrect casing', function() {
spyOn(console, 'warn');
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'tabindex',
'1'
)).toBe(null);
Expand All @@ -67,6 +72,7 @@ describe('DOMPropertyOperations', function() {
it('should warn about class', function() {
spyOn(console, 'warn');
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'class',
'muffins'
)).toBe(null);
Expand All @@ -76,102 +82,134 @@ describe('DOMPropertyOperations', function() {

it('should create markup for boolean properties', function() {
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'checked',
'simple'
)).toBe('checked');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'checked',
true
)).toBe('checked');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'checked',
false
)).toBe('');
});

it('should create markup for booleanish properties', function() {
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'download',
'simple'
)).toBe('download="simple"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'download',
true
)).toBe('download');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'download',
'true'
)).toBe('download="true"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'download',
false
)).toBe('');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'download',
'false'
)).toBe('download="false"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'download',
undefined
)).toBe('');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'download',
null
)).toBe('');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'download',
0
)).toBe('download="0"');
});

it('should create markup for custom attributes', function() {
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'aria-label',
'simple'
)).toBe('aria-label="simple"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'aria-label',
false
)).toBe('aria-label="false"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'aria-label',
null
)).toBe('');
});

it('should create markup for numeric properties', function() {
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'start',
5
)).toBe('start="5"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'start',
0
)).toBe('start="0"');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'size',
0
)).toBe('');

expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'size',
1
)).toBe('size="1"');
});

it('should allow custom properties on web components', function() {
expect(DOMPropertyOperations.createMarkupForProperty(
'x-my-webcomponent',
'awesomeness',
5
)).toBe('awesomeness="5"');

expect(DOMPropertyOperations.createMarkupForProperty(
'x-my-webcomponent',
'dev',
'jim'
)).toBe('dev="jim"');
});

});

describe('setValueForProperty', function() {
Expand Down Expand Up @@ -296,12 +334,14 @@ describe('DOMPropertyOperations', function() {
it('should support custom attributes', function() {
// foobar does not exist yet
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'foobar',
'simple'
)).toBe(null);

// foo-* does not exist yet
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'foo-xyz',
'simple'
)).toBe(null);
Expand All @@ -316,22 +356,26 @@ describe('DOMPropertyOperations', function() {

// Ensure old attributes still work
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'name',
'simple'
)).toBe('name="simple"');
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'data-name',
'simple'
)).toBe('data-name="simple"');

// foobar should work
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'foobar',
'simple'
)).toBe('foobar="simple"');

// foo-* should work
expect(DOMPropertyOperations.createMarkupForProperty(
'div',
'foo-xyz',
'simple'
)).toBe('foo-xyz="simple"');
Expand Down

0 comments on commit 076a97a

Please sign in to comment.