Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Y.Button can render as non-submit #968

Closed
wants to merge 2 commits into from

4 participants

@drjayvee

new Y.Buttons always render as submit buttons. That's bad. Especially for a ToggleButton inside of a form.
See this stackoverflow thread, where @juandopazo commented "Yeah, that's probably a bug."

From my change to HISTORY.md:
Added type ATTR to ButtonCore to enable Button nodes to be rendered with "type" attribute
The default type for <button> is submit, which is not always desired, especially for ToggleButton.

  • Button now supports submit (backwards-compatible default), button and reset
  • ToggleButton is always rendered with type="button"

This isn't done yet! IE 10 fails one test, and IE in compat mode fails even more.

Jeroen Versteeg added some commits
Jeroen Versteeg Fixed two docs tags in button/core d2076c6
Jeroen Versteeg button doesn't force type="submit"
See HISTORY.md for full explanation
9f7f3da
@drjayvee

return this.getNode().get('type') || 'submit';
makes IE 10 pass this test, but I don't understand why.

@drjayvee drjayvee referenced this pull request
Open

Various issues with Button #973

3 of 5 tasks complete
@derek derek was assigned
@drjayvee

As I mentioned in #973, type="button" is the most intuitive default (imo).

@onlywei

I think I have tried to work with this issue before. I remember encountering an issue where IE would not allow me to change the type of a button after it was already rendered, but I was not able to get that to happen anymore today in IE8, 9, and 10.

@drjayvee

Maybe we should make the type attr writeOnce: 'initOnly'

@derek

Hi Jeroen,

I spent some time tonight looking into this PR, and I agree with the overall approach here. Since browsers default type to submit, we should leave that as the default in core.js, but it certainly makes sense to default type to button for Toggle Buttons. The higher up we get in the button stack, the more liberty we can take with overriding default behavior to meet expectations and convinience.

I'll dig in a little deeper into this and your other reported Button issues on Monday & Tuesday. Good stuff! And thanks for your patience while I wrapped up some other work.

@derek

Maybe we should make the type attr writeOnce: 'initOnly'

:thumbsup:

@derek

Still working on this. While introducing a type ATTR could solve the problem, I'd like to start a little lower and resolve the lingering issue of not preserving the innerHTML of the button. That will give us a little clearer picture of what needs to be done here (if anything). If that were solved and the DOM node's type attribute were respected, then we might not need this workaround at all and defaulting a new Button to type=button would just be convenience sugar (possibly in Y.ButtonCore.prototype.TEMPLATE). This would also solve item 4 @ #973.

Oh, and I realized a type ATTR in Y.Button conflicts with Y.ToggleButton's type ATTR, so we'd have to address that collision. FWIW, Button is still in "beta", so breaking backwards compatibility is acceptable (though not ideal).

@derek derek referenced this pull request from a commit in derek/yui3
@derek derek Defaulting button template to type=button (#973, #968) 8a2c1b7
@derek

While the patch included in this PR will certainly address the issue of default button types, I think #1296 is a more ideal fix that addresses the root issue. Let me know if you disagree and we can revisit this pull request. Thanks again for this contribution and bringing all the button issues to my attention. As a result, the last few releases have really helped improve Button's stability and quality.

@triptych

Closing on behalf of @derek

@triptych triptych closed this
@drjayvee

Hey @derek! I just wanted to let you know I agree with the changes to Button. Good work!

@derek

@drjayvee Thanks!

@derek derek was unassigned by jlecomte
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 5, 2013
  1. Fixed two docs tags in button/core

    Jeroen Versteeg authored
  2. button doesn't force type="submit"

    Jeroen Versteeg authored
    See HISTORY.md for full explanation
This page is out of date. Refresh to see the latest.
View
5 src/button/HISTORY.md
@@ -4,7 +4,10 @@ Button Change History
@VERSION@
------
-* No changes.
+* Added type ATTR to ButtonCore to enable Button nodes to be rendered with "type" attribute
+ The default `type` for `<button>`s `submit`, which is not always desired, especially for ToggleButton.
+ * `Button` now supports `submit` (backwards-compatible default), `button` and `reset`
+ * `ToggleButton` is always rendered with `type="button"`
3.10.3
------
View
35 src/button/js/button.js
@@ -60,6 +60,10 @@ Y.extend(Button, Y.Widget, {
}
},
+ renderUI: function () {
+ this.getNode().set('type', this.get('type'));
+ },
+
/**
* bindUI implementation
*
@@ -136,6 +140,17 @@ Y.extend(Button, Y.Widget, {
*/
label: {
value: Y.ButtonCore.ATTRS.label.value
+ },
+
+ /**
+ * Type of button: 'submit', 'button' or 'reset'
+ */
+ type: {
+ value: 'submit',
+ validator: function (val) {
+ return val === 'submit' || val === 'button' || val === 'reset';
+ },
+ getter: null // don't get type from node
}
},
@@ -153,6 +168,10 @@ Y.extend(Button, Y.Widget, {
disabled: function(node) {
return node.getDOMNode().disabled;
+ },
+
+ type: function (node) {
+ return node.get('type');
}
},
@@ -208,8 +227,7 @@ Y.extend(ToggleButton, Button, {
*/
initializer: function (config) {
var button = this,
- type = button.get('type'),
- selectedAttrName = (type === "checkbox" ? 'checked' : 'pressed'),
+ selectedAttrName = (config.type === "checkbox" ? 'checked' : 'pressed'),
selectedState = config[selectedAttrName] || false;
// Create the checked/pressed attribute
@@ -228,6 +246,10 @@ Y.extend(ToggleButton, Button, {
delete this.selectedAttrName;
},
+ renderUI: function () {
+ this.getNode().set('type', 'button'); // toggles are buttons
+ },
+
/**
* @method bindUI
* @description Hooks up events for the widget
@@ -319,14 +341,13 @@ Y.extend(ToggleButton, Button, {
ATTRS: {
/**
- *
- *
- * @attribute type
- * @type String
+ * 'toggle' (default) or 'checkbox'
*/
type: {
value: 'toggle',
- writeOnce: 'initOnly'
+ validator: function (val) {
+ return val === 'toggle' || val === 'checkbox';
+ }
}
},
View
30 src/button/js/core.js
@@ -83,7 +83,7 @@ ButtonCore.prototype = {
* @param config {Object} Config object.
* @private
*/
- _renderUI: function() {
+ _renderUI: function(config) {
var node = this.getNode(),
tagName = node.get('tagName').toLowerCase();
@@ -92,6 +92,8 @@ ButtonCore.prototype = {
if (tagName !== 'button' && tagName !== 'input') {
node.set('role', 'button');
+ } else if (config.type) {
+ node.set('type', config.type);
}
},
@@ -142,6 +144,10 @@ ButtonCore.prototype = {
return label;
},
+ _getType: function () {
+ return this.getNode().get('type');
+ },
+
/**
* @method _uiSetLabel
* @description Setter for a button's 'label' ATTR
@@ -212,6 +218,22 @@ ButtonCore.ATTRS = {
value: false,
setter: '_uiSetDisabled',
lazyAdd: false
+ },
+
+ /**
+ * The host node's type
+ *
+ * If instantiated without a host, defaults 'submit', but can be set to 'button' or 'reset'
+ * Else, type is the host's type
+ *
+ * @attribute
+ * @type String
+ */
+ type: {
+ value: 'submit',
+ getter: '_getType',
+ writeOnce: 'initOnly',
+ lazyAdd: false
}
};
@@ -242,7 +264,7 @@ ButtonCore.CLASS_NAMES = {
/**
* Array of static constants used to for applying ARIA states
*
- * @property CLASS_NAMES
+ * @property ARIA_STATES
* @type {Object}
* @private
* @static
@@ -255,7 +277,7 @@ ButtonCore.ARIA_STATES = {
/**
* Array of static constants used to for applying ARIA roles
*
- * @property CLASS_NAMES
+ * @property ARIA_ROLES
* @type {Object}
* @private
* @static
@@ -267,4 +289,4 @@ ButtonCore.ARIA_ROLES = {
};
// Export Button
-Y.ButtonCore = ButtonCore;
+Y.ButtonCore = ButtonCore;
View
35 src/button/tests/unit/assets/button-core-test.js
@@ -116,6 +116,41 @@ YUI.add('button-core-test', function (Y) {
Assert.areEqual(button.get('label'), 'foo');
Assert.isInstanceOf(Y.ButtonCore, button);
},
+
+ 'New ButtonCores nodes should get proper type attribute': function () {
+ Assert.areEqual('submit', new Y.ButtonCore({}).get('type'));
+ Assert.areEqual('submit', new Y.ButtonCore({type: 'submit'}).get('type'));
+ Assert.areEqual('submit', new Y.ButtonCore({type: 'submit'}).get('type'));
+
+ Assert.areEqual('button', new Y.ButtonCore({type: 'button'}).get('type')); // sensible
+ Assert.areEqual('reset', new Y.ButtonCore({type: 'reset'}).get('type')); // sensible
+
+ Assert.areEqual('submit', new Y.ButtonCore({type: 'foo'}).get('type')); // ridiculous value, fall back to default
+ },
+
+ 'ButtonCore should respect host node\'s type': function () {
+ function getButtonType () {
+ return new Y.ButtonCore({
+ host: Y.one("#testButton")
+ }).get('type');
+ }
+
+ Y.one("#container").setContent('<button id="testButton">Hoi</button>');
+ Assert.areEqual('submit', getButtonType());
+ Y.one("#container").setContent('<button id="testButton" type="submit">Hoi</button>');
+ Assert.areEqual('submit', getButtonType());
+
+ Y.one("#container").setContent('<button id="testButton" type="button">Hoi</button>');
+ Assert.areEqual('button', getButtonType());
+
+ Y.one("#container").setContent('<button id="testButton" type="reset">Hoi</button>');
+ Assert.areEqual('reset', getButtonType());
+
+ Y.one("#container").setContent('<input id="testButton" type="submit">Hoi</button>');
+ Assert.areEqual('submit', getButtonType());
+ Y.one("#container").setContent('<input id="testButton" type="button">Hoi</button>');
+ Assert.areEqual('button', getButtonType());
+ },
'Modifying the label of a nested button structure should not modify the non-label elements': function () {
Y.one("#container").setContent('<button id="testButton">**<span class="yui3-button-label">Hello</span>**</button>');
View
48 src/button/tests/unit/assets/button-test.js
@@ -57,6 +57,11 @@ suite.add(new Y.Test.Case({
Assert.areEqual('toggle', role);
},
+ 'ToggleButton node should always be type="button"': function () {
+ Assert.areEqual('button', this.toggleButton.getNode().get('type'));
+ Assert.areEqual('button', this.checkButton.getNode().get('type'));
+ },
+
'Selecting a toggleButton should add class `yui3-button-selected`': function () {
var button = this.toggleButton,
cb = button.get('contentBox');
@@ -194,6 +199,22 @@ suite.add(new Y.Test.Case({
Y.one("#container").empty(true);
},
+ 'Passing a type should change the node\'s type': function () {
+ function getNewButtonType (type) {
+ return new Y.Button({
+ type: type,
+ render: '#container'
+ }).getNode().get('type');
+ }
+
+ Assert.areEqual('submit', getNewButtonType());
+ Assert.areEqual('submit', getNewButtonType('submit'));
+ Assert.areEqual('button', getNewButtonType('button'));
+ Assert.areEqual('reset', getNewButtonType('reset'));
+
+ Assert.areEqual('submit', getNewButtonType('feisty'));
+ },
+
'Passing `pressed=true` in with the config will default the button to a `pressed` state': function() {
var button;
@@ -293,6 +314,33 @@ suite.add(new Y.Test.Case({
Y.one("#container").empty(true);
},
+ 'The parser should read the button type': function () {
+ function getButtonType () {
+ var b;
+ b = new Y.Button({
+ srcNode: Y.one("#container button, #container input")
+ });
+ b.render();
+ return b.get('type');
+ }
+
+ Y.one("#container").setContent('<button>Hoi</button>');
+ Assert.areEqual('submit', getButtonType());
+ Y.one("#container").setContent('<button type="submit">Hoi</button>');
+ Assert.areEqual('submit', getButtonType());
+
+ Y.one("#container").setContent('<button type="button">Hoi</button>');
+ Assert.areEqual('button', getButtonType());
+
+ Y.one("#container").setContent('<button type="reset">Hoi</button>');
+ Assert.areEqual('reset', getButtonType());
+
+ Y.one("#container").setContent('<input type="submit">Hoi</button>');
+ Assert.areEqual('submit', getButtonType());
+ Y.one("#container").setContent('<input type="button">Hoi</button>');
+ Assert.areEqual('button', getButtonType());
+ },
+
'The HTML parser for the `label` attribute should reference the button text': function() {
var Test = this,
Something went wrong with that request. Please try again.