From bed3d7fe5932e2100886b986356a599be8bd75fa Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 19 Apr 2017 11:32:13 -0400 Subject: [PATCH 1/4] Button: Fix backcompat when called on collection of mixed elements Fixes #15109 --- tests/unit/button/deprecated.html | 8 +++ tests/unit/button/deprecated.js | 22 +++++++- ui/widgets/button.js | 85 ++++++++++++++++++++++++++----- 3 files changed, 99 insertions(+), 16 deletions(-) diff --git a/tests/unit/button/deprecated.html b/tests/unit/button/deprecated.html index 73f62921ce0..8b5270baaa5 100644 --- a/tests/unit/button/deprecated.html +++ b/tests/unit/button/deprecated.html @@ -56,6 +56,14 @@ Anchor Button +
+ Anchor + + + + +
+ diff --git a/tests/unit/button/deprecated.js b/tests/unit/button/deprecated.js index 81a0281b707..bfd7b938489 100644 --- a/tests/unit/button/deprecated.js +++ b/tests/unit/button/deprecated.js @@ -18,14 +18,14 @@ QUnit.test( "Calling button on a checkbox input calls checkboxradio widget", fun "Calling button on a checkbox sets the checkboxradio icon option to false" ); } ); -QUnit.test( "Calling buttonset calls controlgroup", function( assert ) { +/* QUnit.test( "Calling buttonset calls controlgroup", function( assert ) { var controlgroup = $( ".buttonset" ); assert.expect( 1 ); controlgroup.buttonset(); assert.ok( controlgroup.is( ":ui-controlgroup" ), "Calling buttonset creates controlgroup instance" ); -} ); +} ); */ QUnit.module( "Button (deprecated): methods" ); @@ -194,4 +194,22 @@ QUnit.test( "icon / icons options properly proxied", function( assert ) { "Icons secondary option sets iconPosition option to end on init" ); } ); +QUnit.test("Calling button on a collection of mixed types works correctly", function(assert) { + assert.expect(5); + + var group = $(".mixed").children() + + group.button() + + $.each( { + anchor: "button", + button: "button", + check: "checkboxradio", + input: "button", + radio: "checkboxradio" + }, function (type, widget) { + assert.ok($("#mixed-" + type)[widget]("instance"), type + " is a " + widget); + } ); +}) + } ); diff --git a/ui/widgets/button.js b/ui/widgets/button.js index 50da9f9e22e..e46c6004215 100644 --- a/ui/widgets/button.js +++ b/ui/widgets/button.js @@ -342,22 +342,79 @@ if ( $.uiBackCompat !== false ) { } ); $.fn.button = ( function( orig ) { - return function() { - if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) || - ( this.length && this[ 0 ].tagName === "INPUT" && ( - this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio" - ) ) ) { - return orig.apply( this, arguments ); - } - if ( !$.ui.checkboxradio ) { - $.error( "Checkboxradio widget missing" ); - } - if ( arguments.length === 0 ) { - return this.checkboxradio( { - "icon": false + return function( options ) { + var isMethodCall = typeof options === "string"; + var args = Array.prototype.slice.call( arguments, 1 ); + var returnValue = this; + + if ( isMethodCall ) { + + // If this is an empty collection, we need to have the instance method + // return undefined instead of the jQuery instance + if ( !this.length && options === "instance" ) { + returnValue = undefined; + } else { + this.each( function() { + var methodValue; + var type = $( this ).attr( "type" ); + var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio"; + var instance = $.data( this, "ui-" + name ); + + if ( options === "instance" ) { + returnValue = instance; + return false; + } + + if ( !instance ) { + return $.error( "cannot call methods on button" + + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + + if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for button" + + " widget instance" ); + } + + methodValue = instance[ options ].apply( instance, args ); + + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + } ); + } + } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat( args ) ); + } + + this.each( function() { + var type = $( this ).attr( "type" ); + var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio"; + var instance = $.data( this, "ui-" + name ); + + if ( instance ) { + instance.option( options || {} ); + if ( instance._init ) { + instance._init(); + } + } else { + if ( name === "button" ) { + orig.call( $(this), options ); + return; + } + + $(this).checkboxradio( $.extend({ icon: false }, options) ); + } } ); } - return this.checkboxradio.apply( this, arguments ); + + return returnValue; }; } )( $.fn.button ); From 14e8ff74cbef8c8608a700df8a12cc47caf0eeb2 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 19 Apr 2017 11:41:04 -0400 Subject: [PATCH 2/4] Button: uncomment test --- tests/unit/button/deprecated.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/button/deprecated.js b/tests/unit/button/deprecated.js index bfd7b938489..47fcbc28362 100644 --- a/tests/unit/button/deprecated.js +++ b/tests/unit/button/deprecated.js @@ -18,14 +18,14 @@ QUnit.test( "Calling button on a checkbox input calls checkboxradio widget", fun "Calling button on a checkbox sets the checkboxradio icon option to false" ); } ); -/* QUnit.test( "Calling buttonset calls controlgroup", function( assert ) { +QUnit.test( "Calling buttonset calls controlgroup", function( assert ) { var controlgroup = $( ".buttonset" ); assert.expect( 1 ); controlgroup.buttonset(); assert.ok( controlgroup.is( ":ui-controlgroup" ), "Calling buttonset creates controlgroup instance" ); -} ); */ +} ); QUnit.module( "Button (deprecated): methods" ); From 8288f5deadeba3a5a62216a0477ffdbe5aef883f Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 19 Apr 2017 11:55:03 -0400 Subject: [PATCH 3/4] Button: fixup --- tests/unit/button/deprecated.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/button/deprecated.js b/tests/unit/button/deprecated.js index 47fcbc28362..255e7737040 100644 --- a/tests/unit/button/deprecated.js +++ b/tests/unit/button/deprecated.js @@ -197,9 +197,9 @@ QUnit.test( "icon / icons options properly proxied", function( assert ) { QUnit.test("Calling button on a collection of mixed types works correctly", function(assert) { assert.expect(5); - var group = $(".mixed").children() + var group = $(".mixed").children(); - group.button() + group.button(); $.each( { anchor: "button", @@ -210,6 +210,6 @@ QUnit.test("Calling button on a collection of mixed types works correctly", func }, function (type, widget) { assert.ok($("#mixed-" + type)[widget]("instance"), type + " is a " + widget); } ); -}) +}); } ); From 46b04f7ca443dae8c9422a9f1b63db0292cf32fe Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 19 Apr 2017 12:58:15 -0400 Subject: [PATCH 4/4] button: fixup --- tests/unit/button/deprecated.js | 12 ++++++------ ui/widgets/button.js | 8 +++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/unit/button/deprecated.js b/tests/unit/button/deprecated.js index 255e7737040..86fca797e94 100644 --- a/tests/unit/button/deprecated.js +++ b/tests/unit/button/deprecated.js @@ -194,10 +194,10 @@ QUnit.test( "icon / icons options properly proxied", function( assert ) { "Icons secondary option sets iconPosition option to end on init" ); } ); -QUnit.test("Calling button on a collection of mixed types works correctly", function(assert) { - assert.expect(5); +QUnit.test( "Calling button on a collection of mixed types works correctly", function( assert ) { + assert.expect( 5 ); - var group = $(".mixed").children(); + var group = $( ".mixed" ).children(); group.button(); @@ -207,9 +207,9 @@ QUnit.test("Calling button on a collection of mixed types works correctly", func check: "checkboxradio", input: "button", radio: "checkboxradio" - }, function (type, widget) { - assert.ok($("#mixed-" + type)[widget]("instance"), type + " is a " + widget); + }, function( type, widget ) { + assert.ok( $( "#mixed-" + type )[ widget ]( "instance" ), type + " is a " + widget ); } ); -}); +} ); } ); diff --git a/ui/widgets/button.js b/ui/widgets/button.js index e46c6004215..42cfec06d2a 100644 --- a/ui/widgets/button.js +++ b/ui/widgets/button.js @@ -357,7 +357,9 @@ if ( $.uiBackCompat !== false ) { this.each( function() { var methodValue; var type = $( this ).attr( "type" ); - var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio"; + var name = type !== "checkbox" && type !== "radio" ? + "button" : + "checkboxradio"; var instance = $.data( this, "ui-" + name ); if ( options === "instance" ) { @@ -405,11 +407,11 @@ if ( $.uiBackCompat !== false ) { } } else { if ( name === "button" ) { - orig.call( $(this), options ); + orig.call( $( this ), options ); return; } - $(this).checkboxradio( $.extend({ icon: false }, options) ); + $( this ).checkboxradio( $.extend( { icon: false }, options ) ); } } ); }