From a8641722e6b515607e549d892b2b198ed6cd1de9 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Mon, 2 Feb 2015 19:21:44 -0500 Subject: [PATCH 001/107] Build: Add qunit-assert-classes plug-in for classes tests --- Gruntfile.js | 3 ++ bower.json | 1 + external/qunit-assert-classes/LICENSE.txt | 22 +++++++++ .../qunit-assert-classes.js | 47 +++++++++++++++++++ 4 files changed, 73 insertions(+) create mode 100644 external/qunit-assert-classes/LICENSE.txt create mode 100644 external/qunit-assert-classes/qunit-assert-classes.js diff --git a/Gruntfile.js b/Gruntfile.js index 277169a7217..b08547b256c 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -229,6 +229,9 @@ grunt.initConfig({ "qunit/qunit.css": "qunit/qunit/qunit.css", "qunit/MIT-LICENSE.txt": "qunit/MIT-LICENSE.txt", + "qunit-assert-classes/qunit-assert-classes.js": "qunit-assert-classes/qunit-assert-classes.js", + "qunit-assert-classes/LICENSE.txt": "qunit-assert-classes/LICENSE", + "jquery-mousewheel/jquery.mousewheel.js": "jquery-mousewheel/jquery.mousewheel.js", "jquery-mousewheel/LICENSE.txt": "jquery-mousewheel/LICENSE.txt", diff --git a/bower.json b/bower.json index cab4b258e5b..29f884f64d7 100644 --- a/bower.json +++ b/bower.json @@ -15,6 +15,7 @@ "jquery-simulate": "1.0.0", "jshint": "2.4.4", "qunit": "1.17.1", + "qunit-assert-classes": "0.1.5", "jquery-1.7.0": "jquery#1.7.0", "jquery-1.7.1": "jquery#1.7.1", diff --git a/external/qunit-assert-classes/LICENSE.txt b/external/qunit-assert-classes/LICENSE.txt new file mode 100644 index 00000000000..938db036815 --- /dev/null +++ b/external/qunit-assert-classes/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Alexander Schmitz + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/external/qunit-assert-classes/qunit-assert-classes.js b/external/qunit-assert-classes/qunit-assert-classes.js new file mode 100644 index 00000000000..f61046bc85b --- /dev/null +++ b/external/qunit-assert-classes/qunit-assert-classes.js @@ -0,0 +1,47 @@ +( function( QUnit ) { + function inArray( haystack, needle ) { + for ( var i = 0; i < haystack.length; i++ ) { + if ( haystack[ i ] === needle ) { + return true; + } + } + return false; + } + function check( element, classes, stateVal, message ) { + var i, result, classAttribute, elementClassArray, + classArray = classes.split( " " ), + missing = [], + found = []; + + if ( element.jquery && element.length !== 1 ) { + throw( "Class checks can only be performed on a single element on a collection" ); + } + element = element.jquery ? element[ 0 ] : element; + classAttribute = element.getAttribute( "class" ); + message = message || "Element must " + ( stateVal? "" : "not " ) + "have classes"; + if ( classAttribute ) { + elementClassArray = classAttribute.split( " " ); + for( i = 0; i < classArray.length; i++ ) { + if ( !inArray( elementClassArray, classArray[ i ] ) ) { + missing.push( classArray[ i ] ); + } else { + found.push( classArray[ i ] ); + } + } + } else { + missing = classArray; + } + + result = stateVal ? !missing.length : !found.length; + QUnit.push( result, classes, result ? classes : found.join( " " ), message ); + } + + QUnit.extend( QUnit.assert, { + hasClasses: function( element, classes, message ) { + check( element, classes, true, message ); + }, + lacksClasses: function( element, classes, message ) { + check( element, classes, false, message ); + } + }); +})( QUnit ); \ No newline at end of file From 2f20d0ec42bd4b53f1ff82d1b46ed7b0696d60cd Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 3 Dec 2014 11:20:20 -0500 Subject: [PATCH 002/107] Widget: Add classes option and _add/_remove/_toggleClass methods --- tests/unit/widget/widget.html | 1 + tests/unit/widget/widget_classes.js | 129 ++++++++++++++++++++++++++++ tests/unit/widget/widget_core.js | 3 + ui/widget.js | 115 ++++++++++++++++++++++--- 4 files changed, 234 insertions(+), 14 deletions(-) create mode 100644 tests/unit/widget/widget_classes.js diff --git a/tests/unit/widget/widget.html b/tests/unit/widget/widget.html index 2b764abab9e..1738b12aa07 100644 --- a/tests/unit/widget/widget.html +++ b/tests/unit/widget/widget.html @@ -21,6 +21,7 @@ + diff --git a/tests/unit/widget/widget_classes.js b/tests/unit/widget/widget_classes.js new file mode 100644 index 00000000000..9a801c91bae --- /dev/null +++ b/tests/unit/widget/widget_classes.js @@ -0,0 +1,129 @@ +(function( $ ) { + +module( "widget factory classes", { + teardown: function() { + if ( $.ui ) { + delete $.ui.classWidget; + delete $.fn.classWidget; + } + } +}); + +$.widget( "ui.classesWidget", { + options: { + classes: { + "test-wrapper": "self-wrapper", + "test-self": "self-class self-class-2" + } + }, + _create: function() { + this.span = $( "" ) + .appendTo( this.element ); + + this.element.wrap( "
" ); + + this.wrapper = this.element.parent(); + + this._addClass( "test-self", "test-self-extra" ) + ._addClass( "test-self-2" ) + ._addClass( null, "test-self-extra-null" ) + ._addClass( this.span, null, "test-span-extra-null" ) + ._addClass( this.span, "test-span", "test-span-extra" ) + ._addClass( this.wrapper, "test-wrapper" ); + + }, + toggleClasses: function( bool ) { + this._toggleClass( "test-self", "test-self-extra", bool ) + ._toggleClass( "test-self-2", null, bool ) + ._toggleClass( null, "test-self-extra-null", bool ) + ._toggleClass( this.span, null, "test-span-extra-null", bool ) + ._toggleClass( this.span, "test-span", "test-span-extra", bool ) + ._toggleClass( this.wrapper, "test-wrapper", null, bool ); + }, + removeClasses: function() { + this._removeClass( "test-self", "test-self-extra" ) + ._removeClass( "test-self-2" ) + ._removeClass( null, "test-self-extra-null" ) + ._removeClass( this.span, null, "test-span-extra-null" ) + ._removeClass( this.span, "test-span", "test-span-extra" ) + ._removeClass( this.wrapper, "test-wrapper" ); + }, + _destroy: function() { + this.span.remove(); + this.element.unwrap(); + }, + widget: function() { + return this.wrapper; + } +}); + +test( ".option() - classes setter", function(){ + expect( 12 ); + + var testWidget = $.ui.classesWidget(), + currentWrapperClass = testWidget.option( "classes.test-wrapper" ); + + testElementClasses( testWidget.element, true, "add" ); + + testWidget.option({ + classes: { + "test-span": "self-span-new", + "test-wrapper": currentWrapperClass + " self-wrapper-new", + "test-self": "self-class-2" + } + }); + + equal( testWidget.element.is( ".test-self.self-class-2" ), true, + "Removing a class leaves the structure and other classes in value" ); + equal( !testWidget.element.is( ".self-class" ), true, + "Removing a class from the value removes the class" ); + testWidget.option( "classes.test-self", "" ); + equal( testWidget.element.is( ".test-self" ), true, + "Setting to empty value leaves structure class" ); + equal( !testWidget.element.is( ".self-class-2" ), true, + "Setting empty value removes previous value classes" ); + equal( testWidget.span.is( ".test-span.self-span-new" ), true, + "Adding a class to an empty value works as expected" ); + equal( testWidget.wrapper.is( ".test-wrapper.self-wrapper-new" ), true, + "Appending a class to the current value works as expected" ); +}); + +test( ".destroy() - class removal", function(){ + expect( 1 ); + + domEqual( "#widget", function(){ + $( "#widget" ).classesWidget().classesWidget( "destroy" ); + }); +}); + +function testElementClasses( widget, bool, method, toggle ) { + toggle = toggle || ""; + equal( widget.is( ".test-self.self-class.self-class-2" ), bool, + "_" + method + "Class works with ( keys, extra " + toggle + ")" ); + equal( widget.is( ".test-self-2" ), bool, + "_" + method + "Class works with ( keys, null " + toggle + ")" ); + equal( widget.is( ".test-self-extra-null" ), bool, + "_" + method + "Class works with ( null, extra " + toggle + ")" ); + equal( widget.parent().is( ".test-wrapper.self-wrapper" ), bool, + "_" + method + "Class works with ( element, null, extra " + toggle + ")" ); + equal( widget.find( "span" ).is( ".test-span.test-span-extra" ), bool, + "_" + method + "Class works with ( element, keys, extra " + toggle + ")" ); + equal( widget.find( "span" ).is( ".test-span-extra-null" ), bool, + "_" + method + "Class works with ( element, keys, null " + toggle + ")" ); +} + +test( "._add/_remove/_toggleClass()", function(){ + expect( 24 ); + + var widget = $( "#widget" ).classesWidget(); + + testElementClasses( widget, true, "add" ); + widget.classesWidget( "toggleClasses", false ); + testElementClasses( widget, false, "toggle", ", false "); + widget.classesWidget( "toggleClasses", true ); + testElementClasses( widget, true, "toggle", ", true "); + widget.classesWidget( "removeClasses" ); + testElementClasses( widget, false, "remove" ); +}); + +}( jQuery ) ); diff --git a/tests/unit/widget/widget_core.js b/tests/unit/widget/widget_core.js index 2b88e39ef22..4059447da3d 100644 --- a/tests/unit/widget/widget_core.js +++ b/tests/unit/widget/widget_core.js @@ -228,6 +228,7 @@ test( "merge multiple option arguments", function() { _create: function() { deepEqual( this.options, { create: null, + classes: {}, disabled: false, option1: "value1", option2: "value2", @@ -282,6 +283,7 @@ test( "._getCreateOptions()", function() { _create: function() { deepEqual( this.options, { create: null, + classes: {}, disabled: false, option1: "override1", option2: "value2", @@ -486,6 +488,7 @@ test( ".option() - getter", function() { options = div.testWidget( "option" ); deepEqual( options, { create: null, + classes: {}, disabled: false, foo: "bar", baz: 5, diff --git a/ui/widget.js b/ui/widget.js index 33e0d156e4d..348a7795d65 100644 --- a/ui/widget.js +++ b/ui/widget.js @@ -251,6 +251,7 @@ $.Widget.prototype = { defaultElement: "
", options: { disabled: false, + classes: {}, // callbacks create: null @@ -264,6 +265,7 @@ $.Widget.prototype = { this.bindings = $(); this.hoverable = $(); this.focusable = $(); + this.classesElementLookup = {}; if ( element !== this ) { $.data( element, this.widgetFullName, this ); @@ -297,7 +299,12 @@ $.Widget.prototype = { _init: $.noop, destroy: function() { + var that = this; this._destroy(); + $.each( this.classesElementLookup, function( key, value ) { + that._removeClass( value, key ); + }); + // we can probably remove the unbind calls in 2.0 // all event bindings should go through this._on() this.element @@ -305,15 +312,10 @@ $.Widget.prototype = { .removeData( this.widgetFullName ); this.widget() .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); + .removeAttr( "aria-disabled" ); // clean up events and states this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); }, _destroy: $.noop, @@ -369,17 +371,44 @@ $.Widget.prototype = { return this; }, + _updateClassesOption: function( value ) { + var classKey, elements, currentElements; + for ( classKey in value ) { + currentElements = this.classesElementLookup[ classKey ]; + if ( value[ classKey ] === this.options.classes[ classKey ] || + !currentElements || + !currentElements.length ) { + continue; + } + elements = $( currentElements.get() ); + this._removeClass( currentElements, classKey ); + + // We don't use _addClass here because that uses this.options.classes + // for generating the string of classes we want to use value is the new + // value for classes which was passed to _setOption so we call _classes + // directly to pass in this value. + elements.addClass( this._classes({ + element: elements, + keys: classKey, + classes: value, + add: true + })); + } + }, _setOption: function( key, value ) { + if ( key === "classes" ) { + this._updateClassesOption( value ); + } + this.options[ key ] = value; if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled", !!value ); + this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); // If the widget is becoming disabled, then nothing is interactive if ( value ) { - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); + this._removeClass( this.hoverable, null, "ui-state-hover" ); + this._removeClass( this.focusable, null, "ui-state-focus" ); } } @@ -393,6 +422,62 @@ $.Widget.prototype = { return this._setOptions({ disabled: true }); }, + _classes: function( options ) { + var full = [], + that = this, + settings = $.extend({ + element: this.element, + classes: this.options.classes || {} + }, options ); + + function processClassString( classes, checkOption ) { + var current, i; + for ( i = 0; i < classes.length; i++ ) { + current = that.classesElementLookup[ classes[ i ] ] || $(); + if ( settings.add ) { + current = $( $.unique( current.get().concat( settings.element.get() ) ) ); + } else { + current = $( current.not( settings.element ).get() ); + } + that.classesElementLookup[ classes[ i ] ] = current; + full.push( classes[ i ] ); + if ( checkOption && settings.classes[ classes[ i ] ] ) { + full.push( settings.classes[ classes[ i ] ] ); + } + } + } + + if ( settings.keys ) { + processClassString( settings.keys.split( " " ), true ); + } + if ( settings.extra ) { + processClassString( settings.extra.split( " " ) ); + } + + return full.join( " " ); + }, + + _removeClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, false ); + }, + + _addClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, true ); + }, + + _toggleClass: function( element, keys, extra, add ) { + add = ( typeof add === "boolean" ) ? add : extra; + var shift = ( typeof element === "string" || element === null ), + options = { + extra: shift ? keys : extra, + keys: shift ? element : keys, + element: shift ? this.element : element, + add: add + }; + options.element.toggleClass( this._classes( options ), add ); + return this; + }, + _on: function( suppressDisabledCheck, element, handlers ) { var delegateElement, instance = this; @@ -466,25 +551,27 @@ $.Widget.prototype = { }, _hoverable: function( element ) { + var that = this; this.hoverable = this.hoverable.add( element ); this._on( element, { mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); + that._addClass( $( event.currentTarget ), null, "ui-state-hover" ); }, mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); + that._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); } }); }, _focusable: function( element ) { + var that = this; this.focusable = this.focusable.add( element ); this._on( element, { focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); + that._addClass( $( event.currentTarget ), null, "ui-state-focus" ); }, focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); + that._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); } }); }, From 11d25df102b9456c6e3c7dc7c14cd35303be52f1 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Mon, 2 Feb 2015 20:27:31 -0500 Subject: [PATCH 003/107] Button: Add classes option to please the tests --- ui/button.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/button.js b/ui/button.js index a3a40b46d58..f4a8430cc65 100644 --- a/ui/button.js +++ b/ui/button.js @@ -58,6 +58,7 @@ var lastActive, $.widget( "ui.button", { version: "@VERSION", + classes: {}, defaultElement: " - + - + An anchor +
+

CSS Buttons

+ + + -An anchor +An anchor

Examples of the markup that can be used for buttons: A button element, an input of type submit and an anchor.

diff --git a/demos/button/icons.html b/demos/button/icons.html index 76cb1147876..ac7611b98b5 100644 --- a/demos/button/icons.html +++ b/demos/button/icons.html @@ -11,39 +11,58 @@ - - - - - -

Some buttons with various combinations of text and icons.

+
+
+

Widget

+ Button with icon only + + + +
+
+

CSS

+ + + + + +
diff --git a/tests/unit/button/button.html b/tests/unit/button/button.html index 679c316bfb7..b334575e892 100644 --- a/tests/unit/button/button.html +++ b/tests/unit/button/button.html @@ -34,7 +34,7 @@
-
+
diff --git a/tests/unit/button/button_common.js b/tests/unit/button/button_common.js index 1564a1beeee..6141fda4e0f 100644 --- a/tests/unit/button/button_common.js +++ b/tests/unit/button/button_common.js @@ -2,14 +2,12 @@ TestHelpers.commonWidgetTests( "button", { defaults: { classes: {}, disabled: null, - icons: { - primary: null, - secondary: null - }, + showLabel: true, label: null, - text: true, + icon: null, + iconPosition: "beginning", - // callbacks + // Callbacks create: null } }); diff --git a/tests/unit/button/button_core.js b/tests/unit/button/button_core.js index 2d7e0a7477d..ce8ee3c894a 100644 --- a/tests/unit/button/button_core.js +++ b/tests/unit/button/button_core.js @@ -4,73 +4,9 @@ (function($) { -module("button: core"); +module( "Button: core" ); -test("checkbox", function( assert ) { - expect( 4 ); - var input = $("#check"), - label = $("label[for=check]"); - ok( input.is(":visible") ); - ok( label.is(":not(.ui-button)") ); - input.button(); - assert.hasClasses( input, "ui-helper-hidden-accessible" ); - assert.hasClasses( label, "ui-button" ); -}); - -test("radios", function( assert ) { - expect( 8 ); - var inputs = $("#radio0 input"), - labels = $("#radio0 label"); - ok( inputs.is(":visible") ); - ok( labels.is(":not(.ui-button)") ); - inputs.button(); - inputs.each(function() { - assert.hasClasses( this, "ui-helper-hidden-accessible" ); - }); - labels.each(function() { - assert.hasClasses( this, "ui-button" ); - }); -}); - -function assertClasses(noForm, form1, form2) { - QUnit.assert.hasClasses( $("#radio0 .ui-button" + noForm ), "ui-state-active" ); - QUnit.assert.hasClasses( $("#radio1 .ui-button" + form1 ), "ui-state-active" ); - QUnit.assert.hasClasses( $("#radio2 .ui-button" + form2 ), "ui-state-active" ); -} - -test("radio groups", function() { - expect( 12 ); - $("input[type=radio]").button(); - assertClasses(":eq(0)", ":eq(1)", ":eq(2)"); - - // click outside of forms - $("#radio0 .ui-button:eq(1)").click(); - assertClasses(":eq(1)", ":eq(1)", ":eq(2)"); - - // click in first form - $("#radio1 .ui-button:eq(0)").click(); - assertClasses(":eq(1)", ":eq(0)", ":eq(2)"); - - // click in second form - $("#radio2 .ui-button:eq(0)").click(); - assertClasses(":eq(1)", ":eq(0)", ":eq(0)"); -}); - -test( "radio groups - ignore elements with same name", function() { - expect( 1 ); - var form = $( "form:first" ), - radios = form.find( "[type=radio]" ).button(), - checkbox = $( "", { - type: "checkbox", - name: radios.attr( "name" ) - }); - - form.append( checkbox ); - radios.button( "refresh" ); - ok( true, "no exception from accessing button instance of checkbox" ); -}); - -test("input type submit, don't create child elements", function() { +test( "Input type submit, don't create child elements", function() { expect( 2 ); var input = $("#submit"); deepEqual( input.children().length, 0 ); @@ -78,153 +14,19 @@ test("input type submit, don't create child elements", function() { deepEqual( input.children().length, 0 ); }); -test("buttonset", function( assert ) { - expect( 6 ); - var set = $("#radio1").buttonset(); - assert.hasClasses( set, "ui-buttonset" ); - deepEqual( set.children(".ui-button").length, 3 ); - deepEqual( set.children("input[type=radio].ui-helper-hidden-accessible").length, 3 ); - ok( set.children("label:eq(0)").is(".ui-button.ui-corner-left:not(.ui-corner-all)") ); - ok( set.children("label:eq(1)").is(".ui-button:not(.ui-corner-all)") ); - ok( set.children("label:eq(2)").is(".ui-button.ui-corner-right:not(.ui-corner-all)") ); -}); - -test("buttonset (rtl)", function( assert ) { - expect( 6 ); - var set, - parent = $("#radio1").parent(); - // Set to rtl - parent.attr("dir", "rtl"); - - set = $("#radio1").buttonset(); - assert.hasClasses( set, "ui-buttonset" ); - deepEqual( set.children(".ui-button").length, 3 ); - deepEqual( set.children("input[type=radio].ui-helper-hidden-accessible").length, 3 ); - ok( set.children("label:eq(0)").is(".ui-button.ui-corner-right:not(.ui-corner-all)") ); - ok( set.children("label:eq(1)").is(".ui-button:not(.ui-corner-all)") ); - ok( set.children("label:eq(2)").is(".ui-button.ui-corner-left:not(.ui-corner-all)") ); -}); - -// TODO: simulated click events don't behave like real click events in IE -// remove this when simulate properly simulates this -// see http://yuilibrary.com/projects/yui2/ticket/2528826 fore more info -if ( !$.ui.ie || ( document.documentMode && document.documentMode > 8 ) ) { - asyncTest( "ensure checked and aria after single click on checkbox label button, see #5518", function( assert ) { - expect( 3 ); - - $("#check2").button().change( function() { - var lbl = $( this ).button("widget"); - ok( this.checked, "checked ok" ); - ok( lbl.attr("aria-pressed") === "true", "aria ok" ); - assert.hasClasses( lbl, "ui-state-active" ); - }); - - // support: Opera - // Opera doesn't trigger a change event when this is done synchronously. - // This seems to be a side effect of another test, but until that can be - // tracked down, this delay will have to do. - setTimeout(function() { - $("#check2").button("widget").simulate("click"); - start(); - }, 1 ); - }); -} - -test( "#7092 - button creation that requires a matching label does not find label in all cases", function( assert ) { - expect( 5 ); - var group = $( "" ); - group.find( "input[type=checkbox]" ).button(); - assert.hasClasses( group.find( "label" ), "ui-button" ); - - group = $( "" ); - group.filter( "input[type=checkbox]" ).button(); - assert.hasClasses( group.filter( "label" ), "ui-button" ); - - group = $( "" ); - group.find( "input[type=checkbox]" ).button(); - assert.hasClasses( group.filter( "label" ), "ui-button" ); - - group = $( "" ); - group.find( "input[type=checkbox]" ).button(); - assert.hasClasses( group.find( "label" ), "ui-button" ); - - group = $( "" ); - group.filter( "input[type=checkbox]" ).button(); - assert.hasClasses( group.find( "label" ), "ui-button" ); -}); - -test( "#5946 - buttonset should ignore buttons that are not :visible", function( assert ) { - expect( 2 ); - $( "#radio01" ).next().addBack().hide(); - var set = $( "#radio0" ).buttonset({ items: "input[type=radio]:visible" }); - ok( set.find( "label:eq(0)" ).is( ":not(.ui-button):not(.ui-corner-left)" ) ); - assert.hasClasses( set.find( "label:eq(1)" ), "ui-button ui-corner-left" ); -}); - -test( "#6262 - buttonset not applying ui-corner to invisible elements", function( assert ) { - expect( 3 ); - $( "#radio0" ).hide(); - var set = $( "#radio0" ).buttonset(); - assert.hasClasses( set.find( "label:eq(0)" ), "ui-button ui-corner-left" ); - assert.hasClasses( set.find( "label:eq(1)" ), "ui-button" ); - assert.hasClasses( set.find( "label:eq(2)" ), "ui-button ui-corner-right" ); - -}); - -asyncTest( "Resetting a button's form should refresh the visual state of the button widget to match.", function( assert ) { - expect( 2 ); - var form = $( "
" + - "" + - "" + - "
" ), - button = form.find( "button" ).button(), - checkbox = form.find( "input[type=checkbox]" ).button(); - - checkbox.prop( "checked", false ).button( "refresh" ); - assert.lacksClasses( checkbox.button( "widget" ), "ui-state-active" ); - - form.get( 0 ).reset(); - - // #9213: If a button has been removed, refresh should not be called on it when - // its corresponding form is reset. - button.remove(); - - setTimeout(function() { - assert.hasClasses( checkbox.button( "widget" ), "ui-state-active" ); - start(); - }, 1 ); -}); - -asyncTest( "#6711 Checkbox/Radiobutton do not Show Focused State when using Keyboard Navigation", function( assert ) { - expect( 2 ); - var check = $( "#check" ).button(), - label = $( "label[for='check']" ); - assert.lacksClasses( label, "ui-state-focus" ); - check.focus(); - setTimeout(function() { - assert.hasClasses( label, "ui-state-focus" ); - start(); - }); -}); - -test( "#7534 - Button label selector works for ids with \":\"", function( assert ) { +asyncTest( "Disabled button maintains ui-state-focus", function() { expect( 1 ); - var group = $( "" ); - group.find( "input" ).button(); - assert.hasClasses( group.find( "label" ), "ui-button" , "Found an id with a :" ); -}); - -asyncTest( "#9169 - Disabled button maintains ui-state-focus", function( assert ) { - expect( 2 ); var element = $( "#button1" ).button(); - element[ 0 ].focus(); + element.simulate( "focus" ); setTimeout(function() { - assert.hasClasses( element, "ui-state-focus" ); + + // Todo: figure out why this fails in phantom put passes in browser + // ok( element.is( ":focus" ), "Button is focused" ); element.button( "disable" ); - assert.lacksClasses( element, "ui-state-focus", - "button does not have ui-state-focus when disabled" ); + ok( !element.is( ":focus" ), + "Button has had focus removed" ); start(); }); }); -})(jQuery); +})(jQuery); \ No newline at end of file diff --git a/tests/unit/button/button_events.js b/tests/unit/button/button_events.js index 2a8bb772727..6f4c6aae45d 100644 --- a/tests/unit/button/button_events.js +++ b/tests/unit/button/button_events.js @@ -3,24 +3,16 @@ */ (function($) { -module("button: events"); +module( "Button: events" ); -test("buttonset works with single-quote named elements (#7505)", function() { - expect( 1 ); - $("#radio3").buttonset(); - $("#radio33").click( function(){ - ok( true, "button clicks work with single-quote named elements" ); - }).click(); -}); - -asyncTest( "when button loses focus, ensure active state is removed (#8559)", function( assert ) { +asyncTest( "When button loses focus, ensure active state is removed", function() { expect( 1 ); var element = $( "#button" ).button(); element.one( "keypress", function() { element.one( "blur", function() { - assert.lacksClasses( element, "ui-state-active", "button loses active state appropriately" ); + ok( !element.is( ".ui-state-active" ), "button loses active state appropriately" ); start(); }).blur(); }); @@ -33,4 +25,4 @@ asyncTest( "when button loses focus, ensure active state is removed (#8559)", fu }); }); -})(jQuery); +})(jQuery); \ No newline at end of file diff --git a/tests/unit/button/button_methods.js b/tests/unit/button/button_methods.js index d4d92cead09..8e2a8b8a05d 100644 --- a/tests/unit/button/button_methods.js +++ b/tests/unit/button/button_methods.js @@ -3,9 +3,10 @@ */ (function($) { -module("button: methods"); -test("destroy", function() { +module( "Button: methods" ); + +test( "destroy", function() { expect( 1 ); domEqual( "#button", function() { $( "#button" ).button().button( "destroy" ); @@ -13,7 +14,7 @@ test("destroy", function() { }); test( "refresh: Ensure disabled state is preserved correctly.", function() { - expect( 8 ); + expect( 4 ); var element = $( "" ); element.button({ disabled: true }).button( "refresh" ); @@ -27,47 +28,11 @@ test( "refresh: Ensure disabled state is preserved correctly.", function() { element.button( { disabled: true} ).button( "refresh" ); ok( element.button( "option", "disabled" ), "" ); element.button( { disabled: true} ).prop( "disabled", false ).button( "refresh" ); ok( !element.button( "option", "disabled" ), "Changing a
-
- - - - - - -
- -
- - - - - - -
-
anchor anchor diff --git a/themes/base/button.css b/themes/base/button.css index 70caf10ed42..039a8cf0803 100644 --- a/themes/base/button.css +++ b/themes/base/button.css @@ -9,9 +9,9 @@ * http://api.jqueryui.com/button/#theming */ .ui-button { + padding: .4em 1em; display: inline-block; position: relative; - padding: 0; line-height: normal; margin-right: .1em; cursor: pointer; @@ -19,6 +19,7 @@ text-align: center; overflow: visible; /* removes extra width in IE */ } + .ui-button, .ui-button:link, .ui-button:visited, @@ -28,83 +29,110 @@ } /* to make room for the icon, a width needs to be set here */ .ui-button-icon-only { - width: 2.2em; + padding: 0; + height: 2.1em; + text-indent: -9999px; + white-space: nowrap; +} +.ui-icon { + position: absolute; + display: block; } /* button elements seem to need a little more width */ button.ui-button-icon-only { width: 2.4em; } -.ui-button-icons-only { - width: 3.4em; -} -button.ui-button-icons-only { - width: 3.7em; -} -/* button text element */ -.ui-button .ui-button-text { - display: block; - line-height: normal; -} -.ui-button-text-only .ui-button-text { +/* no icon support for input elements, provide padding by default */ +input.ui-button.ui-icon-end, +input.ui-button.ui-icon-beginning, +input.ui-button.ui-icon-top, +input.ui-button.ui-icon-bottom{ padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, -.ui-button-icons-only .ui-button-text { - padding: .4em; - text-indent: -9999999px; +input.ui-button.ui-button-icon-only { + text-indent: 0; } -.ui-button-text-icon-primary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 1em .4em 2.1em; + +/* button icon element(s) */ +.ui-button.ui-icon-end .ui-icon { + left: auto; + right: .5em; } -.ui-button-text-icon-secondary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 2.1em .4em 1em; + +.ui-button.ui-icon-top .ui-icon, +.ui-button.ui-icon-bottom .ui-icon { + left: 50%; + margin-left: -11px; } -.ui-button-text-icons .ui-button-text { - padding-left: 2.1em; - padding-right: 2.1em; + +.ui-button.ui-icon-top .ui-icon { + top: .6em; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { - padding: .4em 1em; + +.ui-button.ui-icon-bottom .ui-icon { + top: auto; + bottom: .05em; } -/* button icon element(s) */ -.ui-button-icon-only .ui-icon, -.ui-button-text-icon-primary .ui-icon, -.ui-button-text-icon-secondary .ui-icon, -.ui-button-text-icons .ui-icon, -.ui-button-icons-only .ui-icon { +.ui-button-icon-only .ui-icon { + left: 50%; + margin-left: -8px; +} + +.ui-button .ui-icon { position: absolute; + display: block; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { - left: 50%; - margin-left: -8px; + +.ui-button.ui-icon-beginning { + padding-left: 2.4em; } -.ui-button-text-icon-primary .ui-button-icon-primary, -.ui-button-text-icons .ui-button-icon-primary, -.ui-button-icons-only .ui-button-icon-primary { - left: .5em; + +.ui-button.ui-icon-end { + padding: .4em 2.1em .4em 1em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, -.ui-button-text-icons .ui-button-icon-secondary, -.ui-button-icons-only .ui-button-icon-secondary { - right: .5em; + +.ui-button.ui-icon-top { + padding: 1.1em 1em .4em 1em; +} + +.ui-button.ui-icon-bottom { + padding: .4em 1em 1.1em 1em; +} + +.ui-button.ui-icon-notext .ui-icon { + padding: 0; + width: 2.1em; + height: 2.1em; + text-indent: -9999px; + white-space: nowrap; + } +input.ui-button.ui-icon-notext .ui-icon { + width: auto; + height: auto; + text-indent: 0; + white-space: normal; + padding: .4em 1em; +} /* button sets */ .ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { - margin-left: 0; - margin-right: -.3em; + +.ui-button.ui-icon-top { + padding: 1.1em 1em .4em 1em; +} + +.ui-button.ui-icon-bottom { + padding: .4em 1em 1.1em 1em; } +>>>>>>> 06cac52... Button: fix css errors /* workarounds */ /* reset extra padding in Firefox, see h5bp.com/l */ input.ui-button::-moz-focus-inner, diff --git a/themes/base/core.css b/themes/base/core.css index 4a39cd39560..096967567f4 100644 --- a/themes/base/core.css +++ b/themes/base/core.css @@ -69,7 +69,6 @@ /* Icons ----------------------------------*/ -/* states and images */ .ui-icon { display: block; text-indent: -99999px; @@ -77,6 +76,35 @@ background-repeat: no-repeat; } +.ui-icon { + left: .5em; + top: .2em; +} + +.ui-icon-end .ui-icon { + left: auto; + right: .5em; +} + +.ui-icon-top .ui-icon, +.ui-icon-bottom .ui-icon { + left: 50%; + margin-left: -11px; +} + +.ui-icon-top .ui-icon { + top: .6em; +} + +.ui-icon-bottom .ui-icon { + top: auto; + bottom: .05em; +} + +.ui-icon-notext .ui-icon { + left: 50%; + margin-left: -8px; +} /* Misc visuals ----------------------------------*/ diff --git a/themes/base/theme.css b/themes/base/theme.css index 1b7a7bf1b08..2cf6c2d11db 100644 --- a/themes/base/theme.css +++ b/themes/base/theme.css @@ -50,7 +50,10 @@ ----------------------------------*/ .ui-state-default, .ui-widget-content .ui-state-default, -.ui-widget-header .ui-state-default { +.ui-widget-header .ui-state-default, +.ui-button, +html .ui-button.ui-state-disabled:hover, +html .ui-button.ui-state-disabled:active { border: 1px solid #c5c5c5/*{borderColorDefault}*/; background: #f6f6f6/*{bgColorDefault}*/ /*{bgImgUrlDefault}*/ /*{bgDefaultXPos}*/ /*{bgDefaultYPos}*/ /*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; @@ -58,7 +61,11 @@ } .ui-state-default a, .ui-state-default a:link, -.ui-state-default a:visited { +.ui-state-default a:visited, +a.ui-button, +a:link.ui-button, +a:visited.ui-button, +.ui-button { color: #454545/*{fcDefault}*/; text-decoration: none; } @@ -67,7 +74,9 @@ .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, -.ui-widget-header .ui-state-focus { +.ui-widget-header .ui-state-focus, +.ui-button:hover, +.ui-button:focus { border: 1px solid #cccccc/*{borderColorHover}*/; background: #ededed/*{bgColorHover}*/ /*{bgImgUrlHover}*/ /*{bgHoverXPos}*/ /*{bgHoverYPos}*/ /*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; @@ -80,13 +89,17 @@ .ui-state-focus a, .ui-state-focus a:hover, .ui-state-focus a:link, -.ui-state-focus a:visited { +.ui-state-focus a:visited, +a.ui-button:hover, +a.ui-button:focus { color: #2b2b2b/*{fcHover}*/; text-decoration: none; } .ui-state-active, .ui-widget-content .ui-state-active, -.ui-widget-header .ui-state-active { +.ui-widget-header .ui-state-active, +a.ui-button:active, +.ui-button:active { border: 1px solid #003eff/*{borderColorActive}*/; background: #007fff/*{bgColorActive}*/ /*{bgImgUrlActive}*/ /*{bgActiveXPos}*/ /*{bgActiveYPos}*/ /*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; @@ -168,14 +181,18 @@ .ui-widget-header .ui-icon { background-image: url("images/ui-icons_444444_256x240.png")/*{iconsHeader}*/; } -.ui-state-default .ui-icon { +.ui-state-default .ui-icon, +.ui-button .ui-icon { background-image: url("images/ui-icons_777777_256x240.png")/*{iconsDefault}*/; } .ui-state-hover .ui-icon, -.ui-state-focus .ui-icon { +.ui-state-focus .ui-icon, +.ui-button:hover .ui-icon, +.ui-button:focus .ui-icon { background-image: url("images/ui-icons_555555_256x240.png")/*{iconsHover}*/; } -.ui-state-active .ui-icon { +.ui-state-active .ui-icon, +.ui-button:active .ui-icon { background-image: url("images/ui-icons_ffffff_256x240.png")/*{iconsActive}*/; } .ui-state-highlight .ui-icon { diff --git a/ui/button.js b/ui/button.js index f4a8430cc65..ef1391256f1 100644 --- a/ui/button.js +++ b/ui/button.js @@ -29,31 +29,14 @@ } }(function( $ ) { -var lastActive, - baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", - typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", +var baseClasses = "ui-button ui-widget ui-corner-all", + typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons" + + " ui-button-text-only ui-icon-beginning ui-icon-end ui-icon-top ui-icon-bottom", formResetHandler = function() { var form = $( this ); setTimeout(function() { - form.find( ":ui-button" ).button( "refresh" ); - }, 1 ); - }, - radioGroup = function( radio ) { - var name = radio.name, - form = radio.form, - radios = $( [] ); - if ( name ) { - name = name.replace( /'/g, "\\'" ); - if ( form ) { - radios = $( form ).find( "[name='" + name + "'][type=radio]" ); - } else { - radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument ) - .filter(function() { - return !this.form; - }); - } - } - return radios; + form.find( ".ui-button" ).filter( ":ui-button" ).button( "refresh" ); + }); }; $.widget( "ui.button", { @@ -62,354 +45,161 @@ $.widget( "ui.button", { defaultElement: " - -
-
    -
  • Open...
  • -
  • Save
  • -
  • Delete
  • -
-
- -
-

An example of a split button built with two buttons: A plain button with just text, one with only a primary icon -and no text. Both are grouped together in a set.

-
- - diff --git a/demos/button/toolbar.html b/demos/button/toolbar.html deleted file mode 100644 index e2eac055c82..00000000000 --- a/demos/button/toolbar.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - jQuery UI Button - Toolbar - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
-

- A mediaplayer toolbar. Take a look at the underlying markup: A few button elements, - an input of type checkbox for the Shuffle button, and three inputs of type radio for the Repeat options. -

-
- - From 5c0c3992010380af6656f4c204e37d4895985a07 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Tue, 2 Sep 2014 20:57:22 -0400 Subject: [PATCH 045/107] Button: Adding classes option --- tests/unit/button/button_common.js | 5 +++++ tests/unit/button/button_options.js | 7 ++++--- themes/base/button.css | 30 ----------------------------- ui/button.js | 17 ++++++++++------ 4 files changed, 20 insertions(+), 39 deletions(-) diff --git a/tests/unit/button/button_common.js b/tests/unit/button/button_common.js index 6141fda4e0f..d13f1e1c3a9 100644 --- a/tests/unit/button/button_common.js +++ b/tests/unit/button/button_common.js @@ -6,6 +6,11 @@ TestHelpers.commonWidgetTests( "button", { label: null, icon: null, iconPosition: "beginning", + classes: { + "ui-button": "ui-corner-all", + "ui-button-icon-only": "", + "ui-button-icon": "" + }, // Callbacks create: null diff --git a/tests/unit/button/button_options.js b/tests/unit/button/button_options.js index bca656225bb..37a93eae3bc 100644 --- a/tests/unit/button/button_options.js +++ b/tests/unit/button/button_options.js @@ -80,7 +80,8 @@ test( "showLabel false without icon", function() { $( "#button" ).button({ showLabel: false }); - strictEqual( $( "#button" ).attr( "class" ), "ui-button ui-widget ui-corner-all" ); + strictEqual( $( "#button" ).is( ":ui-button.ui-corner-all.ui-widget" ), true, + "Button has correct classes" ); $( "#button" ).button( "destroy" ); }); @@ -91,8 +92,8 @@ test("showLabel false with icon", function() { showLabel: false, icon: "iconclass" }); - strictEqual( $( "#button" ).attr( "class" ), "ui-button ui-widget ui-corner-all ui-icon-beginning ui-button-icon-only" ); - + strictEqual( $( "#button" ).is( ".ui-button.ui-corner-all.ui-widget.ui-button-icon-only" ), + true, "Button has correct classes" ); $( "#button" ).button( "destroy" ); }); diff --git a/themes/base/button.css b/themes/base/button.css index 039a8cf0803..74dbe971ea9 100644 --- a/themes/base/button.css +++ b/themes/base/button.css @@ -103,36 +103,6 @@ input.ui-button.ui-button-icon-only { padding: .4em 1em 1.1em 1em; } -.ui-button.ui-icon-notext .ui-icon { - padding: 0; - width: 2.1em; - height: 2.1em; - text-indent: -9999px; - white-space: nowrap; - -} - -input.ui-button.ui-icon-notext .ui-icon { - width: auto; - height: auto; - text-indent: 0; - white-space: normal; - padding: .4em 1em; -} -/* button sets */ -.ui-buttonset { - margin-right: 7px; -} - -.ui-button.ui-icon-top { - padding: 1.1em 1em .4em 1em; -} - -.ui-button.ui-icon-bottom { - padding: .4em 1em 1.1em 1em; -} - ->>>>>>> 06cac52... Button: fix css errors /* workarounds */ /* reset extra padding in Firefox, see h5bp.com/l */ input.ui-button::-moz-focus-inner, diff --git a/ui/button.js b/ui/button.js index 9a96c8db569..d0a312090ea 100644 --- a/ui/button.js +++ b/ui/button.js @@ -48,7 +48,12 @@ $.widget( "ui.button", { showLabel: true, label: null, icon: null, - iconPosition: "beginning" + iconPosition: "beginning", + classes: { + "ui-button": "ui-corner-all", + "ui-button-icon-only": "", + "ui-button-icon": "" + } }, _getCreateOptions: function() { @@ -124,11 +129,11 @@ $.widget( "ui.button", { _updateIcon: function( icon ) { if ( !this.icon ) { - this.icon = $( "" ).addClass( "ui-icon" ); + this.icon = $( "" ).addClass( this._classes( "ui-button-icon" ) + " ui-icon" ); this.element.addClass( "ui-icon-" + this.options.iconPosition ); if ( !this.options.showLabel ){ - this.element.addClass( "ui-button-icon-only" ); + this.element.addClass( this._classes( "ui-button-icon-only" ) ); } } else { this.icon.removeClass( this.options.icon ); @@ -140,7 +145,7 @@ $.widget( "ui.button", { _destroy: function() { this.element - .removeClass( baseClasses + " ui-state-active " + typeClasses ) + .removeClass( this._classes( "ui-button ui-button-icon-only" ) + " " + baseClasses + " ui-state-active " + typeClasses ) .removeAttr( "role" ); if ( this.icon ) { @@ -157,14 +162,14 @@ $.widget( "ui.button", { this._updateIcon( value ); } else { this.icon.remove(); - this.element.removeClass( "ui-icon-" + this.options.iconPosition ); + this.element.removeClass( this._classes( "ui-button-icon" ) + " ui-icon-" + this.options.iconPosition ); } } // Make sure we cant end up with a button that has no text nor icon if ( key === "showLabel" ) { if ( ( !value && !this.options.icon ) || value ) { - this.element.toggleClass( "ui-button-icon-only", !value ) + this.element.toggleClass( this._classes( "ui-button-icon-only" ), !value ) .toggleClass( this.options.iconPosition, !!value ); this._updateTooltip(); } else { From 8704c7074ce1d057545b77b18255b30743f8a62a Mon Sep 17 00:00:00 2001 From: Jasper de Groot Date: Thu, 4 Sep 2014 13:14:16 +0200 Subject: [PATCH 046/107] Button: Fixed the height of icon-only buttons in controlgroups --- themes/base/button.css | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/themes/base/button.css b/themes/base/button.css index 74dbe971ea9..682d4882fb0 100644 --- a/themes/base/button.css +++ b/themes/base/button.css @@ -27,21 +27,19 @@ .ui-button:active { text-decoration: none; } + /* to make room for the icon, a width needs to be set here */ .ui-button-icon-only { - padding: 0; - height: 2.1em; + width: 2.2em; + box-sizing: border-box; text-indent: -9999px; white-space: nowrap; } + .ui-icon { position: absolute; display: block; } -/* button elements seem to need a little more width */ -button.ui-button-icon-only { - width: 2.4em; -} /* no icon support for input elements, provide padding by default */ input.ui-button.ui-icon-end, From 3860f48f2e4e297e95a3c3d4bba4cfe6d23887b8 Mon Sep 17 00:00:00 2001 From: Jasper de Groot Date: Mon, 8 Sep 2014 10:20:11 +0200 Subject: [PATCH 047/107] Button: Added user-select none --- themes/base/button.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/themes/base/button.css b/themes/base/button.css index 682d4882fb0..8a27a2d438c 100644 --- a/themes/base/button.css +++ b/themes/base/button.css @@ -18,6 +18,10 @@ vertical-align: middle; text-align: center; overflow: visible; /* removes extra width in IE */ + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .ui-button, From 8a43b7273e3ffc1d77c14d73f9043f6817b924d7 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Mon, 22 Sep 2014 23:32:20 -0400 Subject: [PATCH 048/107] Button: Fixup from PR Review --- demos/button/default.html | 11 +++++----- demos/button/icons.html | 8 ++++---- ui/button.js | 42 +++++++++++++++++++++++++++++---------- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/demos/button/default.html b/demos/button/default.html index 928a3b4a7b1..f4fdd672284 100644 --- a/demos/button/default.html +++ b/demos/button/default.html @@ -11,11 +11,10 @@ @@ -37,6 +36,8 @@

CSS Buttons

Examples of the markup that can be used for buttons: A button element, an input of type submit and an anchor.

+

Buttons can be styled via the button widget for by adding the classes yourself to avoid the javascript overhead if you dont need any of the methods provided by the button widget

p> +

Here you can see examples of both buttons styled with css only and done using the button widget

diff --git a/demos/button/icons.html b/demos/button/icons.html index ac7611b98b5..3982ab7fc48 100644 --- a/demos/button/icons.html +++ b/demos/button/icons.html @@ -30,12 +30,9 @@ -
-

Some buttons with various combinations of text and icons.

-

Widget

- Button with icon only + Button with icon only @@ -63,6 +60,9 @@

CSS

Button with icon on top +
+
+

Some buttons with various combinations of text and icons.

diff --git a/ui/button.js b/ui/button.js index d0a312090ea..61e0bc085dd 100644 --- a/ui/button.js +++ b/ui/button.js @@ -29,8 +29,7 @@ } }(function( $ ) { -var baseClasses = "ui-button ui-widget ui-corner-all", - typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons" + +var typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons" + " ui-button-text-only ui-icon-beginning ui-icon-end ui-icon-top ui-icon-bottom", formResetHandler = function() { var form = $( this ); @@ -87,6 +86,7 @@ $.widget( "ui.button", { this.options.disabled = this.element.prop( "disabled" ) || false; } + this.hasTitle = this.element.attr( "title" ); this._enhance(); if ( this.element.is( "a" ) ) { @@ -103,7 +103,9 @@ $.widget( "ui.button", { _enhance: function() { this._setOption( "disabled", this.options.disabled ); - this.element.addClass( baseClasses ).attr( "role", "button" ); + this.element + .addClass( this._classes( "ui-button" ) + " ui-widget" ) + .attr( "role", "button" ); // Check to see if the label needs to be set or if its already correct if ( this.options.label && this.options.label !== this.originalLabel ) { @@ -120,9 +122,8 @@ $.widget( "ui.button", { _updateTooltip: function() { this.title = this.element.attr( "title" ); - this.noTitle = !this.title; - if ( !this.options.showLabel && !this.noTitle ){ + if ( !this.options.showLabel && !this.title ) { this.element.attr( "title", this.options.label ); } }, @@ -130,10 +131,11 @@ $.widget( "ui.button", { _updateIcon: function( icon ) { if ( !this.icon ) { this.icon = $( "" ).addClass( this._classes( "ui-button-icon" ) + " ui-icon" ); - this.element.addClass( "ui-icon-" + this.options.iconPosition ); - if ( !this.options.showLabel ){ + if ( !this.options.showLabel ) { this.element.addClass( this._classes( "ui-button-icon-only" ) ); + } else { + this.element.addClass( "ui-icon-" + this.options.iconPosition ); } } else { this.icon.removeClass( this.options.icon ); @@ -145,7 +147,8 @@ $.widget( "ui.button", { _destroy: function() { this.element - .removeClass( this._classes( "ui-button ui-button-icon-only" ) + " " + baseClasses + " ui-state-active " + typeClasses ) + .removeClass( this._classes( "ui-button ui-button-icon-only" ) + " ui-widget" + + " ui-state-active " + typeClasses ) .removeAttr( "role" ); if ( this.icon ) { @@ -156,17 +159,35 @@ $.widget( "ui.button", { } }, + _elementsFromClassKey: function( classKey ) { + switch ( classKey ) { + case "ui-button-icon-only": + if ( this.options.showLabel ) { + return $(); + } + break; + case "ui-button-icon": + if ( this.icon ) { + return this.icon; + } + return $(); + default: + return this._superApply( arguments ); + } + }, + _setOption: function( key, value ) { if ( key === "icon" ) { if ( value !== null ) { this._updateIcon( value ); } else { this.icon.remove(); - this.element.removeClass( this._classes( "ui-button-icon" ) + " ui-icon-" + this.options.iconPosition ); + this.element.removeClass( this._classes( "ui-button-icon" ) + " ui-icon-" + + this.options.iconPosition ); } } - // Make sure we cant end up with a button that has no text nor icon + // Make sure we can't end up with a button that has no text nor icon if ( key === "showLabel" ) { if ( ( !value && !this.options.icon ) || value ) { this.element.toggleClass( this._classes( "ui-button-icon-only" ), !value ) @@ -183,6 +204,7 @@ $.widget( "ui.button", { if ( this.isInput ) { this.element.val( value ); } else { + // If there us an icon append it else nothing then append the value // this avoids removal of the icon when setting label text this.element.html( !!this.icon ? "" : this.icon ).append( value ); From 0e12103bae16830bd928822f76c282132d7ea290 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 22 Oct 2014 11:50:17 -0400 Subject: [PATCH 049/107] Button: backcompat for old button widget --- ui/button.js | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/ui/button.js b/ui/button.js index 61e0bc085dd..1faaf749987 100644 --- a/ui/button.js +++ b/ui/button.js @@ -229,9 +229,84 @@ $.widget( "ui.button", { this._updateTooltip(); } - }); +// DEPRECATED +if ( $.uiBackCompat ) { + + // Text and Icons options + $.widget( "ui.button", $.ui.button, { + options: { + text: true, + icons: { + primary: null, + secondary: null + } + }, + + _create: function() { + if ( this.options.showLabel && !this.options.text ) { + this.options.showLabel = this.options.text; + } + if ( !this.options.icon && ( this.options.icons.primary || + this.options.icons.secondary ) ) { + if ( this.options.icons.primary ) { + this.options.icon = this.options.icons.primary; + } else { + this.options.icon = this.options.icons.secondary; + this.options.iconPosition = "end"; + } + } + this._super(); + }, + + _setOption: function( key, value ) { + if ( key === "text" ) { + this._setOption( "showLabel", value ); + } + if ( key === "icons" ) { + this._setOption( "icon", value ); + if ( value.primary ) { + this._setOption( "icon", value ); + this._setOption( "iconPosition", "beginning" ); + } else if ( value.secondary ) { + this._setOption( "icon", value ); + this._setOption( "iconPosition", "end" ); + } + } + this._superApply( arguments ); + } + }); + $.fn.button = (function( orig ) { + return function() { + if ( this[ 0 ].tagName === "input" && ( this.attr( "type") === "checkbox" || + this.attr( "type" ) === "radio" ) ) { + if ( $.ui.checkboxradio ) { + if ( arguments.length === 0 ) { + return this.checkboxradio({ + "icon": false + }); + } else { + return this.checkboxradio.apply( arguments ); + } + } else { + $.error( "Checkboxradio widget missing" ); + } + } else { + return orig.apply( this, arguments ); + } + }; + })( $.fn.button ); + $.fn.buttonset = function( method, key, value ) { + if ( method === "option" && key === "items" ) { + value = { + "button": value + }; + } + this.controlgroup.call( method, key, value ); + }; +} + return $.ui.button; })); From 50fba69c2d462f71e91df346d691050e9c4520e9 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Fri, 28 Mar 2014 10:48:18 -0400 Subject: [PATCH 050/107] Dialog: Updating dialog and tests for new button API --- tests/unit/dialog/dialog_options.js | 16 +++++++--------- ui/dialog.js | 16 ++++++++-------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/tests/unit/dialog/dialog_options.js b/tests/unit/dialog/dialog_options.js index 3b18df5601d..36a1cd417aa 100644 --- a/tests/unit/dialog/dialog_options.js +++ b/tests/unit/dialog/dialog_options.js @@ -153,10 +153,8 @@ test("buttons - advanced", function( assert ) { click: function() { equal(this, element[0], "correct context"); }, - icons: { - primary: "ui-icon-cancel" - }, - showText: false + icon: "ui-icon-cancel", + showLabel: false } ] }); @@ -166,8 +164,8 @@ test("buttons - advanced", function( assert ) { equal(buttons.attr("id"), "my-button-id", "correct id"); equal(buttons.text(), "a button", "correct label"); assert.hasClasses( buttons, "additional-class" ); - deepEqual( buttons.button("option", "icons"), { primary: "ui-icon-cancel", secondary: null } ); - equal( buttons.button( "option", "text" ), false ); + deepEqual( buttons.button("option", "icon"), "ui-icon-cancel" ); + equal( buttons.button( "option", "showLabel" ), false ); buttons.click(); element.remove(); @@ -208,17 +206,17 @@ test("closeText", function() { expect(3); var element = $("
").dialog(); - equal(element.dialog("widget").find(".ui-dialog-titlebar-close span").text(), "Close", + equal(element.dialog("widget").find(".ui-dialog-titlebar-close").text(), "Close", "default close text"); element.remove(); element = $("
").dialog({ closeText: "foo" }); - equal(element.dialog("widget").find(".ui-dialog-titlebar-close span").text(), "foo", + equal(element.dialog("widget").find(".ui-dialog-titlebar-close").text(), "foo", "closeText on init"); element.remove(); element = $("
").dialog().dialog("option", "closeText", "bar"); - equal(element.dialog("widget").find(".ui-dialog-titlebar-close span").text(), "bar", + equal(element.dialog("widget").find(".ui-dialog-titlebar-close").text(), "bar", "closeText via option method"); element.remove(); }); diff --git a/ui/dialog.js b/ui/dialog.js index 01a279df7c7..d6cccf811e8 100644 --- a/ui/dialog.js +++ b/ui/dialog.js @@ -413,10 +413,8 @@ $.widget( "ui.dialog", { this.uiDialogTitlebarClose = $( "" ) .button({ label: this.options.closeText, - icons: { - primary: "ui-icon-closethick" - }, - text: false + icon: "ui-icon-closethick", + showLabel: false }) .appendTo( this.uiDialogTitlebar ); @@ -484,11 +482,13 @@ $.widget( "ui.dialog", { click.apply( that.element[ 0 ], arguments ); }; buttonOptions = { - icons: props.icons, - text: props.showText + icon: props.icon, + showLabel: props.showLabel, + iconPosition: props.iconPosition }; - delete props.icons; - delete props.showText; + delete props.icon; + delete props.showLabel; + delete props.iconPosition; $( "", props ) .button( buttonOptions ) .appendTo( that.uiButtonSet ); From 144695279b1ed3818570005600f87d40c49a7e23 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Fri, 22 Aug 2014 16:40:09 -0400 Subject: [PATCH 051/107] Selectmenu: update to use button css This ensures consistency between different form elements --- tests/unit/selectmenu/selectmenu.html | 2 +- tests/unit/selectmenu/selectmenu_methods.js | 2 +- themes/base/selectmenu.css | 19 +------------------ ui/selectmenu.js | 2 -- 4 files changed, 3 insertions(+), 22 deletions(-) diff --git a/tests/unit/selectmenu/selectmenu.html b/tests/unit/selectmenu/selectmenu.html index c9a399ad548..bd92bd14bf6 100644 --- a/tests/unit/selectmenu/selectmenu.html +++ b/tests/unit/selectmenu/selectmenu.html @@ -12,7 +12,7 @@ + + + + + + + +
+

Checkbox and radio button widgets

+

Checkbox

+ + + + +

Radio Group

+ + + + + + +
+ +
+

Examples of the markup that can be used with checkboxs and radio buttons.

+
+ + diff --git a/demos/checkboxradio/icon.html b/demos/checkboxradio/icon.html new file mode 100644 index 00000000000..28e266a1668 --- /dev/null +++ b/demos/checkboxradio/icon.html @@ -0,0 +1,45 @@ + + + + + jQuery UI Button - Icon functionality + + + + + + + + + +
+

Checkbox and radio button widgets

+

Checkbox

+ + + + +

Radio Group

+ + + + + + +
+ +
+

Examples of the markup that can be used with checkboxs and radio buttons.

+
+ + diff --git a/tests/unit/checkboxradio/checkboxradio.html b/tests/unit/checkboxradio/checkboxradio.html new file mode 100644 index 00000000000..e729e71fdc8 --- /dev/null +++ b/tests/unit/checkboxradio/checkboxradio.html @@ -0,0 +1,85 @@ + + + + + jQuery UI Checkboxradio Test Suite + + + + + + + + + + + + + + + + +
+
+ +
+ + + +
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/tests/unit/checkboxradio/checkboxradio_common.js b/tests/unit/checkboxradio/checkboxradio_common.js new file mode 100644 index 00000000000..93c74613767 --- /dev/null +++ b/tests/unit/checkboxradio/checkboxradio_common.js @@ -0,0 +1,10 @@ +TestHelpers.commonWidgetTests( "checkboxradio", { + defaults: { + disabled: null, + label: null, + icon: false, + + // Callbacks + create: null + } +}); diff --git a/tests/unit/checkboxradio/checkboxradio_core.js b/tests/unit/checkboxradio/checkboxradio_core.js new file mode 100644 index 00000000000..ffbf5312459 --- /dev/null +++ b/tests/unit/checkboxradio/checkboxradio_core.js @@ -0,0 +1,140 @@ +/* + * checkboxradio_core.js + */ + + +(function($) { + +module("Checkboxradio: core"); +test("Checkbox", function() { + expect( 4 ); + var input = $("#check"), + label = $("label[for=check]"); + ok( input.is( ":visible" ) ); + ok( !label.hasClass(".ui-button)") ); + input.checkboxradio(); + strictEqual( input.attr( "class" ), "ui-helper-hidden-accessible ui-checkboxradio" ); + strictEqual( label.attr( "class" ), "ui-button ui-widget ui-corner-all ui-checkbox-label" ); +}); + +test("Radios", function() { + expect( 4 ); + var inputs = $("#radio0 input"), + labels = $("#radio0 label"); + ok( inputs.is(":visible") ); + ok( labels.is(":not(.ui-button)") ); + inputs.checkboxradio(); + ok( inputs.is(".ui-helper-hidden-accessible") ); + ok( labels.is(".ui-button") ); +}); + +function assert(noForm, form1, form2) { + ok( $("#radio0 .ui-button" + noForm).is(".ui-state-active") ); + ok( $("#radio1 .ui-button" + form1).is(".ui-state-active") ); + ok( $("#radio2 .ui-button" + form2).is(".ui-state-active") ); +} + +test("radio groups", function() { + expect( 12 ); + $("input[type=radio]").checkboxradio(); + assert(":eq(0)", ":eq(1)", ":eq(2)"); + + // click outside of forms + $("#radio0 .ui-button:eq(1)").simulate("click"); + assert(":eq(1)", ":eq(1)", ":eq(2)"); + + // click in first form + $("#radio1 .ui-button:eq(0)").simulate("click"); + assert(":eq(1)", ":eq(0)", ":eq(2)"); + + // click in second form + $("#radio2 .ui-button:eq(0)").simulate("click"); + assert(":eq(1)", ":eq(0)", ":eq(0)"); +}); + +asyncTest( "Checkbox/Radiobutton do not Show Focused State when using Keyboard Navigation", function() { + expect( 2 ); + var check = $( "#check" ).checkboxradio(), + label = $( "label[for='check']" ); + ok( !label.is( ".ui-state-focus" ) ); + check.focus(); + setTimeout(function() { + ok( label.is( ".ui-state-focus" ) ); + start(); + }); +}); + +// TODO: simulated click events don't behave like real click events in IE +// remove this when simulate properly simulates this +// see http://yuilibrary.com/projects/yui2/ticket/2528826 fore more info +if ( !$.ui.ie || ( document.documentMode && document.documentMode > 8 ) ) { + asyncTest( "Ensure checked after single click on checkbox label button", function() { + expect( 2 ); + + $( "#check2" ).checkboxradio().change( function() { + var label = $( this ).checkboxradio( "widget" ); + ok( this.checked, "checked ok" ); + + // The following test is commented out for now because with new markup we are trying to avoid aria + //ok( lbl.attr("aria-pressed") === "true", "aria ok" ); + ok( label.hasClass( "ui-state-active" ), "ui-state-active ok" ); + }); + + // Support: Opera + // Opera doesn't trigger a change event when this is done synchronously. + // This seems to be a side effect of another test, but until that can be + // tracked down, this delay will have to do. + setTimeout(function() { + $( "#check2" ).checkboxradio( "widget" ).simulate( "click" ); + start(); + }, 1 ); + }); +} +test( "Checkbox creation that requires a matching label does not find label in all cases", function() { + expect( 5 ); + var group = $( "" ); + group.find( "input[type=checkbox]" ).checkboxradio(); + ok( group.find( "label" ).is( ".ui-button" ) ); + + group = $( "" ); + group.filter( "input[type=checkbox]" ).checkboxradio(); + ok( group.filter( "label" ).is( ".ui-button" ) ); + + group = $( "" ); + group.find( "input[type=checkbox]" ).checkboxradio(); + ok( group.filter( "label" ).is( ".ui-button" ) ); + + group = $( "" ); + group.find( "input[type=checkbox]" ).checkboxradio(); + ok( group.find( "label" ).is( ".ui-button" ) ); + + group = $( "" ); + group.filter( "input[type=checkbox]" ).checkboxradio(); + ok( group.find( "label" ).is( ".ui-button" ) ); +}); + +asyncTest( "Resetting a button's form should refresh the visual state of the button widget to match.", function() { + expect( 2 ); + var form = $( "
" + + "" + + "
" ), + checkbox = form.find( "input[type=checkbox]" ).checkboxradio(); + + checkbox.prop( "checked", false ).checkboxradio( "refresh" ); + ok( !checkbox.checkboxradio( "widget" ).hasClass( "ui-state-active" ) ); + + form.get( 0 ).reset(); + + setTimeout(function() { + ok( checkbox.checkboxradio( "widget" ).hasClass( "ui-state-active" )); + start(); + }, 1 ); +}); +test( "Checkbox label selector works for ids with \":\"", function() { + expect( 1 ); + var group = $( "" ); + group.find( "input" ).checkboxradio(); + ok( group.find( "label" ).is( ".ui-button" ), "Found an id with a :" ); +}); + +})(jQuery); diff --git a/tests/unit/checkboxradio/checkboxradio_methods.js b/tests/unit/checkboxradio/checkboxradio_methods.js new file mode 100644 index 00000000000..bcec6d9f059 --- /dev/null +++ b/tests/unit/checkboxradio/checkboxradio_methods.js @@ -0,0 +1,131 @@ +/* + * checkboxradio_methods.js + */ + + +(function($) { + +module( "Checkboxradio: methods" ); + test( "Checkbox: refresh", function() { + var checkbox = $( "#checkbox-method-refresh" ), + widget; + expect( 2 ); + checkbox.checkboxradio({ + icon: true + }); + + widget = checkbox.checkboxradio( "widget" ); + delete $(".ui-icon" )[0]; + + checkbox.checkboxradio( "refresh" ); + strictEqual( widget.find( ".ui-icon" ).length, 1, "Icon is recreated on refresh" ); + checkbox.prop( "checked", true ); + checkbox.checkboxradio( "refresh" ); + strictEqual( widget.hasClass( "ui-checkbox-checked" ), true, + "State updated based on checked property" ); + }); + + test( "Checkbox: destroy", function(){ + var checkbox = $( "#checkbox-method-destroy" ), + checkboxClasses = checkbox.attr( "class" ), + label = $( "#checkbox-method-destroy-label" ), + labelClasses = label.attr( "class" ); + + expect( 2 ); + checkbox.checkboxradio(); + checkbox.checkboxradio( "destroy" ); + strictEqual( checkbox.attr( "class"), checkboxClasses, + "checkbox classes match original after destroy" ); + strictEqual( label.attr( "class"), labelClasses, + "label classes match original after destroy" ); + }); + + test( "Checkbox: disable / enable", function(){ + var checkbox = $( "#checkbox-method-disable" ); + + expect( 4 ); + checkbox.checkboxradio(); + checkbox.checkboxradio( "disable" ); + strictEqual( checkbox.checkboxradio( "widget" ).hasClass( "ui-state-disabled" ), true, + "label gets ui-state-disabled when disable is called" ); + strictEqual( checkbox.is( ":disabled" ), true, + "checkbox is disabled when disable is called" ); + checkbox.checkboxradio( "enable" ); + strictEqual( checkbox.checkboxradio( "widget" ).hasClass( "ui-state-disabled" ), false, + "label has ui-state-disabled removed when enable is called" ); + strictEqual( checkbox.is( ":disabled" ), false, + "checkbox has disabled prop removed when enable is called" ); + }); + test( "Checkbox: widget returns the label", function(){ + var checkbox = $( "#checkbox-method-refresh" ), + label = $( "#checkbox-method-refresh-label" ); + + expect( 1 ); + + checkbox.checkboxradio(); + strictEqual( checkbox.checkboxradio( "widget" ).attr( "id" ), label.attr( "id" ), + "widget method returns label" ); + }); + + test( "Radio: refresh", function() { + var radio = $( "#radio-method-refresh" ), + widget; + expect( 2 ); + radio.checkboxradio({ + icon: true + }); + + widget = radio.checkboxradio( "widget" ); + delete $(".ui-icon" )[0]; + + radio.checkboxradio( "refresh" ); + strictEqual( widget.find( ".ui-icon" ).length, 1, "Icon is recreated on refresh" ); + radio.prop( "checked", true ); + radio.checkboxradio( "refresh" ); + strictEqual( widget.hasClass( "ui-radio-checked" ), true, + "State updated based on checked property" ); + }); + + test( "Radio: destroy", function(){ + var radio = $( "#radio-method-destroy" ), + radioClasses = radio.attr( "class" ), + label = $( "#radio-method-destroy-label" ), + labelClasses = label.attr( "class" ); + + expect( 2 ); + radio.checkboxradio(); + radio.checkboxradio( "destroy" ); + strictEqual( radio.attr( "class"), radioClasses, + "radio classes match original after destroy" ); + strictEqual( label.attr( "class"), labelClasses, + "label classes match original after destroy" ); + }); + + test( "Radio: disable / enable", function(){ + var radio = $( "#checkbox-method-disable" ); + + expect( 4 ); + radio.checkboxradio(); + radio.checkboxradio( "disable" ); + strictEqual( radio.checkboxradio( "widget" ).hasClass( "ui-state-disabled" ), true, + "label gets ui-state-disabled when disable is called" ); + strictEqual( radio.is( ":disabled" ), true, + "radio is disabled when disable is called" ); + radio.checkboxradio( "enable" ); + strictEqual( radio.checkboxradio( "widget" ).hasClass( "ui-state-disabled" ), false, + "label has ui-state-disabled removed when enable is called" ); + strictEqual( radio.is( ":disabled" ), false, + "radio has disabled prop removed when enable is called" ); + }); + test( "Radio: widget returns the label", function(){ + var radio = $( "#radio-method-refresh" ), + label = $( "#radio-method-refresh-label" ); + + expect( 1 ); + + radio.checkboxradio(); + strictEqual( radio.checkboxradio( "widget" ).attr( "id" ), label.attr( "id" ), + "widget method returns label" ); + }); + +})(jQuery); diff --git a/tests/unit/checkboxradio/checkboxradio_options.js b/tests/unit/checkboxradio/checkboxradio_options.js new file mode 100644 index 00000000000..b372e267064 --- /dev/null +++ b/tests/unit/checkboxradio/checkboxradio_options.js @@ -0,0 +1,173 @@ +/* + * checkboxradio_methods.js + */ + + +(function($) { + +module( "Checkboxradio: checkbox: options" ); + test( "options: disabled", function() { + var checkbox = $( "#checkbox-option-disabled" ), + widget; + expect( 10 ); + checkbox.checkboxradio({ + disabled: true + }); + + widget = checkbox.checkboxradio( "widget" ); + + strictEqual( widget.hasClass( "ui-state-disabled" ), true, + "label gets ui-state-disabled when initial option set to true" ); + strictEqual( checkbox.is( ":disabled" ), true, + "checkbox is disabled when inital option is set to true" ); + + checkbox.checkboxradio( "option", "disabled", false ); + + strictEqual( widget.hasClass( "ui-state-disabled" ), false, + "label has ui-state-disabled removed when disabled set to false" ); + strictEqual( checkbox.is( ":disabled" ), false, + "checkbox has disabled prop removed when disabled set to false" ); + + checkbox.checkboxradio( "option", "disabled", true ); + + strictEqual( widget.hasClass( "ui-state-disabled" ), true, + "label gets ui-state-disabled when option set to true" ); + strictEqual( checkbox.is( ":disabled" ), true, + "checkbox is disabled when option is set to true" ); + + checkbox.checkboxradio( "destroy" ); + checkbox.prop( "disabled", true ); + checkbox.checkboxradio(); + + strictEqual( widget.hasClass( "ui-state-disabled" ), true, + "label gets ui-state-disabled when checkbox is disabled in dom on startup" ); + strictEqual( checkbox.is( ":disabled" ), true, + "checkbox is disabled when checkbox is disabled in dom on startup" ); + + checkbox.checkboxradio( "destroy" ); + checkbox.checkboxradio({ + disabled: null + }); + + strictEqual( widget.hasClass( "ui-state-disabled" ), true, + "passing null to disabled on startup checks the dom" ); + strictEqual( checkbox.is( ":disabled" ), true, + "passing null to disabled on startup checks the dom" ); + }); + test( "options: icon", function() { + var checkbox = $( "#checkbox-option-icon" ), + widget; + + expect( 9 ); + + checkbox.checkboxradio(); + + widget = checkbox.checkboxradio( "widget" ); + + strictEqual( widget.find( "span" ).length, 0, + "Label does not contain a span when created with icon:false" ); + + checkbox.checkboxradio( "destroy" ); + + checkbox.checkboxradio({ + icon: true + }); + + strictEqual( widget.find( "span" ).length, 1, + "Label contains a span when created with icon:true" ); + strictEqual( widget.find( "span" ).attr( "class" ), + "ui-icon ui-icon-background ui-corner-all ui-icon-blank", + "Icon span has proper classes when created not checked" ); + + checkbox.checkboxradio( "destroy" ).prop( "checked", true ); + + checkbox.checkboxradio({ + icon: true + }); + + strictEqual( widget.find( "span" ).attr( "class" ), + "ui-icon ui-icon-background ui-corner-all ui-icon-check", + "Icon span has proper classes when created checked" ); + + checkbox.checkboxradio( "option", "icon", false ); + + strictEqual( widget.find( "span" ).length, 0, + "Label does not contain a span when option set to icon:false and checked" ); + + checkbox.checkboxradio( "option", "icon", true ); + + strictEqual( widget.find( "span" ).attr( "class" ), + "ui-icon ui-icon-background ui-corner-all ui-icon-check", + "Icon span has proper classes when option set to true and :is( checked )" ); + + checkbox.prop( "checked", false ).checkboxradio( "refresh" ); + checkbox.checkboxradio( "option", "icon", false ); + + strictEqual( widget.find( "span" ).length, 0, + "Label does not contain a span when option set to icon:false and not checked" ); + + checkbox.checkboxradio( "option", "icon", true ); + + strictEqual( widget.find( "span" ).attr( "class" ), + "ui-icon ui-icon-background ui-corner-all ui-icon-blank", + "Icon span has proper classes when option set to true and not checked" ); + + checkbox.checkboxradio( "destroy" ); + + strictEqual( widget.find( "span" ).length, 0, + "Label does not contain a span after destroy when icon true" ); + + }); + test( "options: label", function() { + var checkbox = $( "#checkbox-option-label" ), + widget; + + expect( 10 ); + + checkbox.checkboxradio(); + + widget = checkbox.checkboxradio( "widget" ); + + strictEqual( checkbox.checkboxradio( "option", "label" ), + "checkbox label", "When no value passed on create text from dom is used for option" ); + strictEqual( widget.text(), + "checkbox label", "When no value passed on create text from dom is used in dom" ); + + checkbox.checkboxradio( "destroy" ); + + checkbox.checkboxradio({ + label: "foo" + }); + + strictEqual( checkbox.checkboxradio( "option", "label" ), + "foo", "When value is passed on create value is used for option" ); + strictEqual( widget.text(), + "foo", "When value is passed on create value is used in dom" ); + + checkbox.checkboxradio( "destroy" ); + checkbox.checkboxradio({ + label: null + }); + + strictEqual( checkbox.checkboxradio( "option", "label" ), + "foo", "When null is passed on create text from dom is used for option" ); + strictEqual( widget.text(), + "foo", "When null is passed on create text from dom is used in dom" ); + + checkbox.checkboxradio( "option", "label", "bar" ); + + strictEqual( checkbox.checkboxradio( "option", "label" ), + "bar", "When value is passed value is used for option" ); + strictEqual( widget.text(), + "bar", "When value is passed value is used in dom" ); + + checkbox.checkboxradio( "option", "label", null ); + + strictEqual( checkbox.checkboxradio( "option", "label" ), + "bar", "When null is passed text from dom is used for option" ); + strictEqual( widget.text(), + "bar", "When null is passed text from dom is used in dom" ); + + }); + +})(jQuery); diff --git a/tests/unit/controlgroup/controlgroup_core.js b/tests/unit/controlgroup/controlgroup_core.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/index.html b/tests/unit/index.html index 418cfd34cc6..fe358cb6c81 100644 --- a/tests/unit/index.html +++ b/tests/unit/index.html @@ -40,6 +40,7 @@

Widgets

  • Accordion
  • Autocomplete
  • Button
  • +
  • Checkboxradio
  • Datepicker
  • Dialog
  • Menu
  • diff --git a/tests/visual/checkboxradio/checkbox.html b/tests/visual/checkboxradio/checkbox.html new file mode 100644 index 00000000000..f3db979dda0 --- /dev/null +++ b/tests/visual/checkboxradio/checkbox.html @@ -0,0 +1,70 @@ + + + + + jQuery UI Button - Checkboxes + + + + + + + + + + + +
    + css for new checkbox widget +
    +
    + + + + + + + + +
    +
    + + + + + + + + +
    + + diff --git a/themes/base/base.css b/themes/base/base.css index 3ed02661f5e..7194eba2756 100644 --- a/themes/base/base.css +++ b/themes/base/base.css @@ -13,6 +13,7 @@ @import url("accordion.css"); @import url("autocomplete.css"); @import url("button.css"); +@import url("checkboxradio.css"); @import url("datepicker.css"); @import url("dialog.css"); @import url("draggable.css"); diff --git a/themes/base/checkboxradio.css b/themes/base/checkboxradio.css new file mode 100644 index 00000000000..7e90394df5d --- /dev/null +++ b/themes/base/checkboxradio.css @@ -0,0 +1,40 @@ +/*! + * jQuery UI Checkboxradio @VERSION + * http://jqueryui.com + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/checkboxradio/#theming + */ + +.ui-checkbox { + display: none; +} +.ui-checkbox-label .ui-icon-background { + border-radius: .12em; + border: none; +} +.ui-radio-label .ui-icon.ui-icon-background { + width: 16px; + height: 16px; + border-radius: 1em; + overflow: visible; + border: none; + background-color: rgb( 0, 0, 0 ); + background-color: rgba( 0, 0, 0, .3 ); + opacity: .3; +} +.ui-radio-label.ui-radio-checked .ui-icon, +.ui-radio-label.ui-radio-checked:hover .ui-icon { + background-image: none; + background-color: #fff; + width: 8px; + height: 8px; + border-width: 4px; + border-style: solid; +} +.ui-checkboxradio-disabled { + pointer-events: none; +} diff --git a/themes/base/core.css b/themes/base/core.css index 096967567f4..3d03511cef6 100644 --- a/themes/base/core.css +++ b/themes/base/core.css @@ -78,7 +78,7 @@ .ui-icon { left: .5em; - top: .2em; + top: .3em; } .ui-icon-end .ui-icon { diff --git a/themes/base/theme.css b/themes/base/theme.css index 2cf6c2d11db..6151ee509c0 100644 --- a/themes/base/theme.css +++ b/themes/base/theme.css @@ -59,6 +59,9 @@ html .ui-button.ui-state-disabled:active { font-weight: normal/*{fwDefault}*/; color: #454545/*{fcDefault}*/; } +.ui-state-active .ui-icon-background { + background-color: #e6e6e6/*{bgColorDefault}*/; +} .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited, @@ -99,12 +102,16 @@ a.ui-button:focus { .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, -.ui-button:active { +.ui-button:active, +.ui-button.ui-state-active:hover { border: 1px solid #003eff/*{borderColorActive}*/; background: #007fff/*{bgColorActive}*/ /*{bgImgUrlActive}*/ /*{bgActiveXPos}*/ /*{bgActiveYPos}*/ /*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #ffffff/*{fcActive}*/; } +.ui-icon-background { + background-color: #ffffff/*{bgColorActive}*/; +} .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js new file mode 100644 index 00000000000..684f8fbcca2 --- /dev/null +++ b/ui/checkboxradio.js @@ -0,0 +1,271 @@ +/*! + * jQuery UI Checkboxradio @VERSION + * http://jqueryui.com + * + * Copyright 2014 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/checkboxradio/ + */ +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define([ + "jquery", + "./core", + "./widget" + ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +}(function( $ ) { + +var baseClasses = "ui-button ui-widget ui-corner-all", + typeClasses = " ui-icon ui-icon-background ui-state-focus ui-icon-check ui-icon-blank" + + " ui-radio-label ui-checkbox-label ui-state-active ui-icon-beginning ui-icon-end" + + " ui-icon-top ui-icon-bottom ui-radio-checked ui-checkbox-checked", + formResetHandler = function() { + var form = $( this ); + setTimeout(function() { + form.find( ".ui-checkboxradio" ).checkboxradio( "refresh" ); + }); + }, + radioGroup = function( radio ) { + var name = radio.name, + form = radio.form, + radios = $( [] ); + if ( name ) { + name = name.replace( /'/g, "\\'" ); + if ( form ) { + radios = $( form ).find( "[name='" + name + "']" ); + } else { + radios = $( "[name='" + name + "']", radio.ownerDocument ) + .filter(function() { + return !this.form; + }); + } + } + return radios; + }; + +$.widget( "ui.checkboxradio", { + version: "@VERSION", + defaultElement: "", + options: { + disabled: null, + label: null, + icon: false + }, + + _getCreateOptions: function() { + var options = {}; + + this._readLabel(); + + this.originalLabel = this.label.html(); + + this._readDisabled( options ); + + if ( this.originalLabel ) { + options.label = this.originalLabel; + } + + return options; + }, + + _readDisabled: function( options ) { + var isDisabled = this.element.prop( "disabled" ); + + if ( isDisabled !== undefined ) { + options.disabled = isDisabled; + } else { + options.disabled = false; + } + }, + + _create: function() { + var formElement = $( this.element[ 0 ].form ); + + // We don't use _on and _off here because we want all the checkboxes in the same form to use + // single handler which handles all the checkboxradio widgets in the form + formElement.off( "reset" + this.eventNamespace, formResetHandler ); + formElement.on( "reset" + this.eventNamespace, formResetHandler ); + + // If the option is a boolean its been set by either user or by + // _getCreateOptions so we need to make sure the prop matches + // If it is not a boolean the user set it explicitly to null so we need to check the dom + if ( typeof this.options.disabled === "boolean" ) { + this.element.prop( "disabled", this.options.disabled ); + } else { + this._readDisabled( this.options ); + } + + // If the option is true we call set options to add the disabled + // classes and ensure the element is not focused + if ( this.options.disabled === true ){ + this._setOption( "disabled", true ); + } + + this._readType(); + + this._enhance(); + + this._on({ + "change": "_toggleClasses", + "focus": function() { + this.label.addClass( "ui-state-focus" ); + }, + "blur": function() { + this.label.removeClass( "ui-state-focus" ); + } + }); + }, + + _readType: function() { + this.type = this.element[ 0 ].type; + if ( !/radio|checkbox/.test( this.type ) ) { + throw new Error( "Can't create checkboxradio widget for type " + this.type ); + } + }, + + _readLabel: function() { + var ancestor, labelSelector, + labels = this.element[ 0 ].labels; + + // Check control.labels first + if ( labels !== undefined && labels.length > 0 ) { + this.label = $( labels[ 0 ] ); + } else { + + // We don't search against the document in case the element + // is disconnected from the DOM + ancestor = this.element.parents().last(); + + // Look for the label based on the id + labelSelector = "label[for='" + this.element.attr( "id" ) + "']"; + this.label = ancestor.find( labelSelector ); + if ( !this.label.length ) { + + // The label was not found make sure ancestors exist if they do check their siblings + // if they dont check the elements siblings + ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); + + // Check if any of the new set of ancestors is the label + this.label = ancestor.filter( labelSelector ); + if ( !this.label.length ) { + + // Still not found look inside the ancestors for the label + this.label = ancestor.find( labelSelector ); + } + } + } + }, + + _enhance: function() { + var checked = this.element.is( ":checked" ); + + this._updateIcon( checked ); + this.element.addClass( "ui-helper-hidden-accessible ui-checkboxradio" ); + + this.label.addClass( baseClasses + " ui-" + this.type + "-label" ); + + if ( checked ) { + this.label.addClass( "ui-" + this.type + "-checked ui-state-active" ); + } + if ( this.options.label && this.options.label !== this.originalLabel ) { + this.label.html( this.icon ? this.icon : "" ).append( this.options.label ); + } else if ( this.originalLabel ) { + this.options.label = this.originalLabel; + } + }, + + widget: function() { + return this.label; + }, + + _toggleClasses: function() { + var checked = this.element.is( ":checked" ); + this.label.toggleClass( "ui-" + this.type + "-checked ui-state-active", checked ); + if ( this.options.icon && this.type === "checkbox" ) { + this.icon + .toggleClass( "ui-icon-check", checked ) + .toggleClass( "ui-icon-blank", !checked ); + } + if ( this.type === "radio" ) { + radioGroup( this.element[0] ) + .not( this.element ) + .map(function() { + return $( this ).checkboxradio( "widget" )[ 0 ]; + }) + .removeClass( "ui-state-active ui-radio-checked" ); + } + }, + + _destroy: function() { + this.label.removeClass( baseClasses + " " + typeClasses ); + if ( this.icon ) { + this.icon.remove(); + } + this.element.removeClass( "ui-checkboxradio ui-helper-hidden-accessible" ); + }, + + _setOption: function( key, value ) { + var original; + if ( key === "label" && value === null ) { + original = this.options[ key ]; + } + this._super( key, value ); + if ( key === "disabled" ) { + this.label.toggleClass( "ui-state-disabled", !!value ); + this.element.prop( "disabled", !!value ); + return; + } + if ( key === "label" && value === null ) { + this.options[ key ] = original; + } + this.refresh(); + }, + + _updateIcon: function( checked ) { + var toAdd = "ui-icon ui-icon-background ui-corner-all "; + + if ( this.options.icon ) { + this.label.addClass( "ui-icon-beginning" ); + if ( !this.icon ){ + this.icon = $( "" ); + } + + if ( this.type === "checkbox" ) { + toAdd += checked ? "ui-icon-check" : "ui-icon-blank"; + } + this.icon.addClass( toAdd ).appendTo( this.label ); + } else if ( this.icon !== undefined ) { + this.label.removeClass( "ui-icon-beginning" ); + this.icon.remove(); + delete this.icon; + } + }, + + refresh: function() { + var checked = this.element.is( ":checked" ), + isDisabled = this.element.is( ":disabled" ); + this._updateIcon( checked ); + this.label.toggleClass( "ui-state-active ui-" + this.type + "-checked", checked ); + if ( this.options.label !== null ) { + this.label.html( !!this.icon ? this.icon : "" ).append( this.options.label ); + } + + if ( isDisabled !== this.options.disabled ) { + this._setOptions({ "disabled": isDisabled }); + } + } + +}); + +return $.ui.checkboxradio; + +})); From 0793f657e5bf15bdb1956ee5efc085878c411f2e Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 23 Jul 2014 22:11:03 -0400 Subject: [PATCH 054/107] Checkboxradio: add visual focus outline to checkbox and radio buttons This adds a focus outline matching that roughly from chrome osx --- themes/base/theme.css | 3 +++ ui/checkboxradio.js | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/themes/base/theme.css b/themes/base/theme.css index 6151ee509c0..8e817aa0333 100644 --- a/themes/base/theme.css +++ b/themes/base/theme.css @@ -98,6 +98,9 @@ a.ui-button:focus { color: #2b2b2b/*{fcHover}*/; text-decoration: none; } +.ui-visual-focus { + box-shadow: 0 0 3px 1px rgb(94, 158, 214); +} .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index 684f8fbcca2..965ee2952b6 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -117,10 +117,10 @@ $.widget( "ui.checkboxradio", { this._on({ "change": "_toggleClasses", "focus": function() { - this.label.addClass( "ui-state-focus" ); + this.label.addClass( "ui-state-focus ui-visual-focus" ); }, "blur": function() { - this.label.removeClass( "ui-state-focus" ); + this.label.removeClass( "ui-state-focus ui-visual-focus" ); } }); }, From 9502dadccc5ce809c9c863e7c744094dd3c48eda Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 23 Jul 2014 12:51:42 -0400 Subject: [PATCH 055/107] Checkboxradio: allow the parent of the input to be the label Conflicts: ui/checkboxradio.js --- tests/unit/checkboxradio/checkboxradio.html | 3 + .../unit/checkboxradio/checkboxradio_core.js | 8 ++- .../checkboxradio/checkboxradio_methods.js | 13 ++++- .../checkboxradio/checkboxradio_options.js | 12 ++-- tests/visual/checkboxradio/checkbox.html | 5 +- ui/checkboxradio.js | 57 +++++++++++++------ 6 files changed, 68 insertions(+), 30 deletions(-) diff --git a/tests/unit/checkboxradio/checkboxradio.html b/tests/unit/checkboxradio/checkboxradio.html index e729e71fdc8..e101da5c320 100644 --- a/tests/unit/checkboxradio/checkboxradio.html +++ b/tests/unit/checkboxradio/checkboxradio.html @@ -80,6 +80,9 @@ +
    diff --git a/tests/unit/checkboxradio/checkboxradio_core.js b/tests/unit/checkboxradio/checkboxradio_core.js index ffbf5312459..843fc3ff5f1 100644 --- a/tests/unit/checkboxradio/checkboxradio_core.js +++ b/tests/unit/checkboxradio/checkboxradio_core.js @@ -90,8 +90,8 @@ if ( !$.ui.ie || ( document.documentMode && document.documentMode > 8 ) ) { }, 1 ); }); } -test( "Checkbox creation that requires a matching label does not find label in all cases", function() { - expect( 5 ); +test( "Checkbox creation that requires a matching finds label in all cases", function() { + expect( 6 ); var group = $( "" ); group.find( "input[type=checkbox]" ).checkboxradio(); ok( group.find( "label" ).is( ".ui-button" ) ); @@ -111,6 +111,10 @@ test( "Checkbox creation that requires a matching label does not find label in a group = $( "" ); group.filter( "input[type=checkbox]" ).checkboxradio(); ok( group.find( "label" ).is( ".ui-button" ) ); + + group = $( "" ); + group.find( "input[type=checkbox]" ).checkboxradio(); + ok( group.find( "label" ).is( ".ui-button" ) ); }); asyncTest( "Resetting a button's form should refresh the visual state of the button widget to match.", function() { diff --git a/tests/unit/checkboxradio/checkboxradio_methods.js b/tests/unit/checkboxradio/checkboxradio_methods.js index bcec6d9f059..ee96f556a43 100644 --- a/tests/unit/checkboxradio/checkboxradio_methods.js +++ b/tests/unit/checkboxradio/checkboxradio_methods.js @@ -40,7 +40,7 @@ module( "Checkboxradio: methods" ); "label classes match original after destroy" ); }); - test( "Checkbox: disable / enable", function(){ + test( "Checkbox: disable / enable", function() { var checkbox = $( "#checkbox-method-disable" ); expect( 4 ); @@ -101,7 +101,7 @@ module( "Checkboxradio: methods" ); "label classes match original after destroy" ); }); - test( "Radio: disable / enable", function(){ + test( "Radio: disable / enable", function() { var radio = $( "#checkbox-method-disable" ); expect( 4 ); @@ -127,5 +127,14 @@ module( "Checkboxradio: methods" ); strictEqual( radio.checkboxradio( "widget" ).attr( "id" ), label.attr( "id" ), "widget method returns label" ); }); + test( "Input wrapped in a label preserved on refresh", function() { + var input = $( "#label-with-no-for" ).checkboxradio(), + element = input.checkboxradio( "widget" ); + + expect( 1 ); + + input.checkboxradio( "refresh" ); + strictEqual( input.parent().is( element ), true, "Input preserved" ); + }); })(jQuery); diff --git a/tests/unit/checkboxradio/checkboxradio_options.js b/tests/unit/checkboxradio/checkboxradio_options.js index b372e267064..49c28fb6502 100644 --- a/tests/unit/checkboxradio/checkboxradio_options.js +++ b/tests/unit/checkboxradio/checkboxradio_options.js @@ -1,4 +1,4 @@ -/* +-/* * checkboxradio_methods.js */ @@ -130,7 +130,7 @@ module( "Checkboxradio: checkbox: options" ); strictEqual( checkbox.checkboxradio( "option", "label" ), "checkbox label", "When no value passed on create text from dom is used for option" ); - strictEqual( widget.text(), + strictEqual( widget.contents().not( this.element ), "checkbox label", "When no value passed on create text from dom is used in dom" ); checkbox.checkboxradio( "destroy" ); @@ -141,7 +141,7 @@ module( "Checkboxradio: checkbox: options" ); strictEqual( checkbox.checkboxradio( "option", "label" ), "foo", "When value is passed on create value is used for option" ); - strictEqual( widget.text(), + strictEqual( widget.contents().not( this.element ), "foo", "When value is passed on create value is used in dom" ); checkbox.checkboxradio( "destroy" ); @@ -151,21 +151,21 @@ module( "Checkboxradio: checkbox: options" ); strictEqual( checkbox.checkboxradio( "option", "label" ), "foo", "When null is passed on create text from dom is used for option" ); - strictEqual( widget.text(), + strictEqual( widget.contents().not( this.element ), "foo", "When null is passed on create text from dom is used in dom" ); checkbox.checkboxradio( "option", "label", "bar" ); strictEqual( checkbox.checkboxradio( "option", "label" ), "bar", "When value is passed value is used for option" ); - strictEqual( widget.text(), + strictEqual( widget.contents().not( this.element ), "bar", "When value is passed value is used in dom" ); checkbox.checkboxradio( "option", "label", null ); strictEqual( checkbox.checkboxradio( "option", "label" ), "bar", "When null is passed text from dom is used for option" ); - strictEqual( widget.text(), + strictEqual( widget.contents().not( this.element ), "bar", "When null is passed text from dom is used in dom" ); }); diff --git a/tests/visual/checkboxradio/checkbox.html b/tests/visual/checkboxradio/checkbox.html index f3db979dda0..e1a3267cea2 100644 --- a/tests/visual/checkboxradio/checkbox.html +++ b/tests/visual/checkboxradio/checkbox.html @@ -61,9 +61,8 @@ - - - + + diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index 965ee2952b6..7f841010841 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -54,21 +54,38 @@ var baseClasses = "ui-button ui-widget ui-corner-all", $.widget( "ui.checkboxradio", { version: "@VERSION", - defaultElement: "", options: { disabled: null, label: null, - icon: false + icon: true, + classes: { + "ui-checkboxradio": null, + "ui-checkbox": null, + "ui-radio": null, + "ui-checkbox-label": "ui-corner-all", + "ui-radio-label": "ui-corner-all", + "ui-checkboxradio-icon": "ui-corner-all", + "ui-radio-checked": null, + "ui-checkbox-checked": null + } }, _getCreateOptions: function() { - var options = {}; + var disabled, + that = this, + options = {}; this._readLabel(); - this.originalLabel = this.label.html(); + this.originalLabel = ""; + this.label.contents().not( this.element ).each( function() { + that.originalLabel += ( this.nodeType === 3 ) ? $( this ).text() : this.outerHTML; + }); - this._readDisabled( options ); + disabled = this.element.prop( "disabled" ); + if ( disabled != null ) { + options.disabled = disabled; + } if ( this.originalLabel ) { options.label = this.originalLabel; @@ -95,13 +112,9 @@ $.widget( "ui.checkboxradio", { formElement.off( "reset" + this.eventNamespace, formResetHandler ); formElement.on( "reset" + this.eventNamespace, formResetHandler ); - // If the option is a boolean its been set by either user or by - // _getCreateOptions so we need to make sure the prop matches - // If it is not a boolean the user set it explicitly to null so we need to check the dom - if ( typeof this.options.disabled === "boolean" ) { - this.element.prop( "disabled", this.options.disabled ); - } else { - this._readDisabled( this.options ); + // If it is null the user set it explicitly to null so we need to check the dom + if ( this.options.disabled == null ) { + this.options.disabled = this.element.prop( "disabled" ) || false; } // If the option is true we call set options to add the disabled @@ -134,11 +147,16 @@ $.widget( "ui.checkboxradio", { _readLabel: function() { var ancestor, labelSelector, - labels = this.element[ 0 ].labels; + parent = this.element.closest( "label" ); + + this.parentLabel = false; // Check control.labels first - if ( labels !== undefined && labels.length > 0 ) { - this.label = $( labels[ 0 ] ); + if ( this.element[ 0 ].labels !== undefined && this.element[ 0 ].labels.length > 0 ){ + this.label = $( this.element[ 0 ].labels[ 0 ] ); + } else if ( parent.length > 0 ) { + this.label = parent; + this.parentLabel = true; } else { // We don't search against the document in case the element @@ -241,6 +259,8 @@ $.widget( "ui.checkboxradio", { if ( this.type === "checkbox" ) { toAdd += checked ? "ui-icon-check" : "ui-icon-blank"; + } else { + toAdd += "ui-icon-blank"; } this.icon.addClass( toAdd ).appendTo( this.label ); } else if ( this.icon !== undefined ) { @@ -254,9 +274,12 @@ $.widget( "ui.checkboxradio", { var checked = this.element.is( ":checked" ), isDisabled = this.element.is( ":disabled" ); this._updateIcon( checked ); - this.label.toggleClass( "ui-state-active ui-" + this.type + "-checked", checked ); + console.log( this.options.label ); + this.label.toggleClass( "ui-state-active " + this._classes( "ui-" + this.type + "-checked" ), checked ); if ( this.options.label !== null ) { - this.label.html( !!this.icon ? this.icon : "" ).append( this.options.label ); + this.label.contents().not( this.element.add( this.icon ) ).remove(); + this.label.append( this.options.label ); + } if ( isDisabled !== this.options.disabled ) { From e7ec68e8ecc150fc04ee9486ce53155baa6d762c Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Fri, 7 Nov 2014 23:33:51 -0500 Subject: [PATCH 056/107] Checkboxradio: Fixup demos --- demos/checkboxradio/default.html | 2 +- demos/checkboxradio/{icon.html => icons.html} | 2 +- demos/checkboxradio/index.html | 16 ++++++++++++++++ demos/index.html | 1 + tests/unit/checkboxradio/checkboxradio.html | 4 ++-- tests/visual/index.html | 5 +++++ ui/checkboxradio.js | 2 ++ 7 files changed, 28 insertions(+), 4 deletions(-) rename demos/checkboxradio/{icon.html => icons.html} (95%) create mode 100644 demos/checkboxradio/index.html diff --git a/demos/checkboxradio/default.html b/demos/checkboxradio/default.html index 4bc6c0005eb..e9e9383e016 100644 --- a/demos/checkboxradio/default.html +++ b/demos/checkboxradio/default.html @@ -23,7 +23,7 @@

    Checkbox

    Radio Group

    diff --git a/demos/checkboxradio/icon.html b/demos/checkboxradio/icons.html similarity index 95% rename from demos/checkboxradio/icon.html rename to demos/checkboxradio/icons.html index 28e266a1668..4f46bcc8a34 100644 --- a/demos/checkboxradio/icon.html +++ b/demos/checkboxradio/icons.html @@ -25,7 +25,7 @@

    Checkbox

    Radio Group

    diff --git a/demos/checkboxradio/index.html b/demos/checkboxradio/index.html new file mode 100644 index 00000000000..6d6f47fd586 --- /dev/null +++ b/demos/checkboxradio/index.html @@ -0,0 +1,16 @@ + + + + + + jQuery UI Checkboxradio Demos + + + + + + + diff --git a/demos/index.html b/demos/index.html index f37874a4481..4b4d04e06b5 100644 --- a/demos/index.html +++ b/demos/index.html @@ -11,6 +11,7 @@
  • accordion
  • autocomplete
  • button
  • +
  • checkboxradio
  • datepicker
  • dialog
  • draggable
  • diff --git a/tests/unit/checkboxradio/checkboxradio.html b/tests/unit/checkboxradio/checkboxradio.html index e101da5c320..2f651a2cff5 100644 --- a/tests/unit/checkboxradio/checkboxradio.html +++ b/tests/unit/checkboxradio/checkboxradio.html @@ -7,11 +7,11 @@ - + @@ -19,21 +19,28 @@

    Checkbox and radio button widgets

    Checkbox

    - - - - +
    + Filter by rating + + + + + + + + +

    Radio Group

    - - - - - - +
    + Filter by location: + + + + + +
    diff --git a/demos/checkboxradio/icons.html b/demos/checkboxradio/icons.html index 4f46bcc8a34..75a33ec6136 100644 --- a/demos/checkboxradio/icons.html +++ b/demos/checkboxradio/icons.html @@ -2,7 +2,7 @@ - jQuery UI Button - Icon functionality + jQuery UI Checkboxradio - Icon functionality @@ -22,20 +22,28 @@

    Checkbox and radio button widgets

    Checkbox

    - - -
    diff --git a/demos/checkboxradio/images/jquery-mobile.png b/demos/checkboxradio/images/jquery-mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..fe2c36376d4dd8f1627d34e3982d4e924f138176 GIT binary patch literal 6296 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 literal 0 HcmV?d00001 diff --git a/demos/checkboxradio/images/qunit.png b/demos/checkboxradio/images/qunit.png new file mode 100644 index 0000000000000000000000000000000000000000..048bcfddbdd6f02e3ae9522098014c2510b39f38 GIT binary patch literal 6740 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 literal 0 HcmV?d00001 diff --git a/demos/checkboxradio/images/sizzle.png b/demos/checkboxradio/images/sizzle.png new file mode 100644 index 0000000000000000000000000000000000000000..6145cd8ec488a6ea924ecb9c4ef4fb4a41fac5ac GIT binary patch literal 8875 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 literal 0 HcmV?d00001 diff --git a/demos/checkboxradio/index.html b/demos/checkboxradio/index.html index 6d6f47fd586..ed0c37d4b7b 100644 --- a/demos/checkboxradio/index.html +++ b/demos/checkboxradio/index.html @@ -10,6 +10,8 @@ diff --git a/demos/checkboxradio/product-selector.html b/demos/checkboxradio/product-selector.html new file mode 100644 index 00000000000..0f894b7e3f5 --- /dev/null +++ b/demos/checkboxradio/product-selector.html @@ -0,0 +1,126 @@ + + + + + jQuery UI Checkboxradio - Product Selector + + + + + + + + + + + +
    +
    +

    1.) Select a brand

    +
    + + + + + + + + + + +
    +
    +
    +

    2.) Select a shape

    +
    + + + + + + + + +
    +
    +
    +

    3.) customize

    +
    + + + + + + + + +
    +
    +
    +
    + +
    +

    Examples of the markup that can be used with checkboxs and radio buttons.

    +
    + + diff --git a/demos/checkboxradio/radiogroup.html b/demos/checkboxradio/radiogroup.html new file mode 100644 index 00000000000..2489a334891 --- /dev/null +++ b/demos/checkboxradio/radiogroup.html @@ -0,0 +1,40 @@ + + + + + jQuery UI Checkboxradio - Radio Group + + + + + + + + + + +
    + +

    Radio Group

    +
    + Location: + + + + + +
    +
    + +
    +

    Example markup using a controlgroup to create a radio group

    +
    + + diff --git a/demos/controlgroup/default.html b/demos/controlgroup/default.html new file mode 100644 index 00000000000..9e4bcdd80ef --- /dev/null +++ b/demos/controlgroup/default.html @@ -0,0 +1,90 @@ + + + + + jQuery UI Controlgroup - Default Functionality + + + + + + + + + + + + + + + +
    +

    A Controlgroup featuring various form controls

    +
    +
    +

    Controlgroup

    +
    + Rental Car +
    + + + + + + + + +
    +
    +
    +
    + Rental Car +
    + + + + + + + + +
    +
    +>>>>>>> 423b976... Checkboxradio: Fixed demos and tests +
    + + + diff --git a/demos/controlgroup/index.html b/demos/controlgroup/index.html new file mode 100644 index 00000000000..58e2f7eda7a --- /dev/null +++ b/demos/controlgroup/index.html @@ -0,0 +1,17 @@ + + + + + + jQuery UI Checkboxradio Demos + + + + + + + diff --git a/demos/controlgroup/splitbutton.html b/demos/controlgroup/splitbutton.html new file mode 100644 index 00000000000..5d4c7b3ce55 --- /dev/null +++ b/demos/controlgroup/splitbutton.html @@ -0,0 +1,58 @@ + + + + + jQuery UI Controlgroup - Split Button + + + + + + + + + + + + + + + +
    +

    A Controlgroup creating a split button

    +
    +
    +

    Split button

    +
    + + +
    +
    +
    +

    A Controlgroup creating a split button

    +
    + + diff --git a/demos/controlgroup/toolbar.html b/demos/controlgroup/toolbar.html new file mode 100644 index 00000000000..f90fb304009 --- /dev/null +++ b/demos/controlgroup/toolbar.html @@ -0,0 +1,256 @@ + + + + + jQuery UI Controlgroup - Toolbar + + + + + + + + + + + + + + + +
    +

    A sample editor toolbar

    +

    Highlight text and edit it using the buttons and dropdowns in the toolbar

    +
    +
    + + + + + + + + + + + + +
    +

    +
    +The Rime of the Ancient Mariner (text of 1834)
    +BY SAMUEL TAYLOR COLERIDGE
    +Argument 
    +
    +How a Ship having passed the Line was driven by storms to the cold Country towards the South Pole;
    +and how from thence she made her course to the tropical Latitude of the Great Pacific Ocean; and 
    +of the strange things that befell; and in what manner the Ancyent Marinere came back to his own
    +Country.
    +
    +PART I
    +It is an ancient Mariner,
    +And he stoppeth one of three.
    +'By thy long grey beard and glittering eye,
    +Now wherefore stopp'st thou me?
    +
    +The Bridegroom's doors are opened wide,
    +And I am next of kin;
    +The guests are met, the feast is set:
    +May'st hear the merry din.'
    +
    +He holds him with his skinny hand,
    +'There was a ship,' quoth he.
    +'Hold off! unhand me, grey-beard loon!'
    +Eftsoons his hand dropt he.
    +
    +He holds him with his glittering eye—
    +The Wedding-Guest stood still,
    +And listens like a three years' child:
    +The Mariner hath his will.
    +
    +The Wedding-Guest sat on a stone:
    +He cannot choose but hear;
    +And thus spake on that ancient man,
    +The bright-eyed Mariner.
    +
    +'The ship was cheered, the harbour cleared,
    +Merrily did we drop
    +Below the kirk, below the hill,
    +Below the lighthouse top.
    +
    +The Sun came up upon the left,
    +Out of the sea came he!
    +And he shone bright, and on the right
    +Went down into the sea.
    +
    +Higher and higher every day,
    +Till over the mast at noon—'
    +The Wedding-Guest here beat his breast,
    +For he heard the loud bassoon.
    +
    +The bride hath paced into the hall,
    +Red as a rose is she;
    +Nodding their heads before her goes
    +The merry minstrelsy.
    +
    +The Wedding-Guest he beat his breast,
    +Yet he cannot choose but hear;
    +And thus spake on that ancient man,
    +The bright-eyed Mariner.
    +
    +And now the STORM-BLAST came, and he
    +Was tyrannous and strong:
    +He struck with his o'ertaking wings,
    +And chased us south along.
    +
    +With sloping masts and dipping prow,
    +As who pursued with yell and blow
    +Still treads the shadow of his foe,
    +And forward bends his head,
    +The ship drove fast, loud roared the blast,
    +And southward aye we fled.
    +
    +And now there came both mist and snow,
    +And it grew wondrous cold:
    +And ice, mast-high, came floating by,
    +As green as emerald.
    +
    +And through the drifts the snowy clifts
    +Did send a dismal sheen:
    +Nor shapes of men nor beasts we ken—
    +The ice was all between.
    +
    +The ice was here, the ice was there,
    +The ice was all around:
    +It cracked and growled, and roared and howled,
    +Like noises in a swound!
    +
    +At length did cross an Albatross,
    +Thorough the fog it came;
    +As if it had been a Christian soul,
    +We hailed it in God's name.
    +
    +It ate the food it ne'er had eat,
    +And round and round it flew.
    +The ice did split with a thunder-fit;
    +The helmsman steered us through!
    +
    +And a good south wind sprung up behind;
    +The Albatross did follow,
    +And every day, for food or play,
    +Came to the mariner's hollo!
    +
    +In mist or cloud, on mast or shroud,
    +It perched for vespers nine;
    +Whiles all the night, through fog-smoke white,
    +Glimmered the white Moon-shine.'
    +
    +'God save thee, ancient Mariner!
    +From the fiends, that plague thee thus!—
    +Why look'st thou so?'—With my cross-bow
    +I shot the ALBATROSS.
    +
    + + diff --git a/tests/unit/checkboxradio/checkboxradio_core.js b/tests/unit/checkboxradio/checkboxradio_core.js index 843fc3ff5f1..35f162a8c8c 100644 --- a/tests/unit/checkboxradio/checkboxradio_core.js +++ b/tests/unit/checkboxradio/checkboxradio_core.js @@ -14,7 +14,7 @@ test("Checkbox", function() { ok( !label.hasClass(".ui-button)") ); input.checkboxradio(); strictEqual( input.attr( "class" ), "ui-helper-hidden-accessible ui-checkboxradio" ); - strictEqual( label.attr( "class" ), "ui-button ui-widget ui-corner-all ui-checkbox-label" ); + strictEqual( label.attr( "class" ), "ui-button ui-widget ui-checkbox-label ui-corner-all" ); }); test("Radios", function() { @@ -87,7 +87,7 @@ if ( !$.ui.ie || ( document.documentMode && document.documentMode > 8 ) ) { setTimeout(function() { $( "#check2" ).checkboxradio( "widget" ).simulate( "click" ); start(); - }, 1 ); + }); }); } test( "Checkbox creation that requires a matching finds label in all cases", function() { @@ -141,4 +141,12 @@ test( "Checkbox label selector works for ids with \":\"", function() { ok( group.find( "label" ).is( ".ui-button" ), "Found an id with a :" ); }); +test( "Calling checkboxradio on an unsupported element throws an error", function() { + expect( 1 ); + throws( $( "
    " ).checkboxradio, "Error thrown" ); +}); +test( "Calling checkboxradio oan input with no label throws an error", function() { + expect( 1 ); + throws( $( "" ).checkboxradio, "Error thrown" ); +}); })(jQuery); diff --git a/tests/visual/checkboxradio/checkbox.html b/tests/visual/checkboxradio/checkbox.html index e1a3267cea2..6e85f8763c8 100644 --- a/tests/visual/checkboxradio/checkbox.html +++ b/tests/visual/checkboxradio/checkbox.html @@ -54,7 +54,7 @@ - +
    diff --git a/tests/visual/index.html b/tests/visual/index.html index 432fec9013a..a24f4f1b4eb 100644 --- a/tests/visual/index.html +++ b/tests/visual/index.html @@ -33,7 +33,7 @@

    Button

    Checkboxradio

    Dialog

    diff --git a/themes/base/checkboxradio.css b/themes/base/checkboxradio.css index 7e90394df5d..c522e2d22f3 100644 --- a/themes/base/checkboxradio.css +++ b/themes/base/checkboxradio.css @@ -22,7 +22,7 @@ border-radius: 1em; overflow: visible; border: none; - background-color: rgb( 0, 0, 0 ); + background-color: rgb( 192, 192, 192 ); background-color: rgba( 0, 0, 0, .3 ); opacity: .3; } diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index 3611ffcf3c3..d91f3dbd4d1 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -24,10 +24,9 @@ } }(function( $ ) { -var baseClasses = "ui-button ui-widget ui-corner-all", - typeClasses = " ui-icon ui-icon-background ui-state-focus ui-icon-check ui-icon-blank" + - " ui-radio-label ui-checkbox-label ui-state-active ui-icon-beginning ui-icon-end" + - " ui-icon-top ui-icon-bottom ui-radio-checked ui-checkbox-checked", +var baseClasses = "ui-button ui-widget", + typeClasses = "ui-state-focus ui-radio-label ui-checkbox-label ui-state-active " + + "ui-icon-beginning ui-icon-end ui-icon-top ui-icon-bottom ui-radio-checked ui-checkbox-checked", formResetHandler = function() { var form = $( this ); setTimeout(function() { @@ -98,35 +97,18 @@ $.widget( "ui.checkboxradio", { return options; }, - _readDisabled: function( options ) { - var isDisabled = this.element.prop( "disabled" ); - - if ( isDisabled !== undefined ) { - options.disabled = isDisabled; - } else { - options.disabled = false; - } - }, - _create: function() { var formElement = $( this.element[ 0 ].form ); // We don't use _on and _off here because we want all the checkboxes in the same form to use - // single handler which handles all the checkboxradio widgets in the form + // a single handler which handles all the checkboxradio widgets in the form formElement.off( "reset" + this.eventNamespace, formResetHandler ); formElement.on( "reset" + this.eventNamespace, formResetHandler ); - // If it is null the user set it explicitly to null so we need to check the dom if ( this.options.disabled == null ) { this.options.disabled = this.element.prop( "disabled" ) || false; } - // If the option is true we call set options to add the disabled - // classes and ensure the element is not focused - if ( this.options.disabled === true ){ - this._setOption( "disabled", true ); - } - this._readType(); this._enhance(); @@ -145,7 +127,7 @@ $.widget( "ui.checkboxradio", { _readType: function() { this.type = this.element[ 0 ].type; if ( !/radio|checkbox/.test( this.type ) ) { - throw new Error( "Can't create checkboxradio widget for type " + this.type ); + $.error( "Can't create checkboxradio widget for type " + this.type ); } }, @@ -156,7 +138,7 @@ $.widget( "ui.checkboxradio", { this.parentLabel = false; // Check control.labels first - if ( this.element[ 0 ].labels !== undefined && this.element[ 0 ].labels.length > 0 ){ + if ( this.element[ 0 ].labels !== undefined && this.element[ 0 ].labels.length > 0 ) { this.label = $( this.element[ 0 ].labels[ 0 ] ); } else if ( parent.length > 0 ) { this.label = parent; @@ -172,8 +154,8 @@ $.widget( "ui.checkboxradio", { this.label = ancestor.find( labelSelector ); if ( !this.label.length ) { - // The label was not found make sure ancestors exist if they do check their siblings - // if they dont check the elements siblings + // The label was not found, make sure ancestors exist. If they do check their + // siblings, if they dont check the elements siblings ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); // Check if any of the new set of ancestors is the label @@ -182,6 +164,9 @@ $.widget( "ui.checkboxradio", { // Still not found look inside the ancestors for the label this.label = ancestor.find( labelSelector ); + if ( this.label.length === 0 ) { + $.error( "No label found for checkboxradio widget" ); + } } } } @@ -190,6 +175,7 @@ $.widget( "ui.checkboxradio", { _enhance: function() { var checked = this.element.is( ":checked" ); + this._setOption( "disabled", this.options.disabled ); this._updateIcon( checked ); this.element.addClass( "ui-helper-hidden-accessible " + this._classes( "ui-checkboxradio" ) ); @@ -231,7 +217,8 @@ $.widget( "ui.checkboxradio", { }, _destroy: function() { - this.label.removeClass( baseClasses + " " + typeClasses ); + this.label.removeClass( this._classes( "ui-radio-label ui-checkbox-label" ) + " " + + baseClasses + " " + typeClasses ); if ( this.icon ) { this.icon.remove(); } @@ -262,7 +249,7 @@ $.widget( "ui.checkboxradio", { if ( this.options.icon ) { this.label.addClass( "ui-icon-beginning" ); - if ( !this.icon ){ + if ( !this.icon ) { this.icon = $( "" ); } From f76bbbd7da4e0ed658a67bdbcb8e7da2f60be3d9 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Thu, 23 Oct 2014 13:29:52 -0400 Subject: [PATCH 060/107] Checkboxradio: change all classes to be prefixed with ui-checkboxradio And simplify css --- .../checkboxradio/checkboxradio_common.js | 13 ++--- .../unit/checkboxradio/checkboxradio_core.js | 3 +- .../checkboxradio/checkboxradio_methods.js | 4 +- .../checkboxradio/checkboxradio_options.js | 35 +++++++----- themes/base/checkboxradio.css | 11 ++-- ui/button.js | 4 +- ui/checkboxradio.js | 54 +++++++++++++------ 7 files changed, 75 insertions(+), 49 deletions(-) diff --git a/tests/unit/checkboxradio/checkboxradio_common.js b/tests/unit/checkboxradio/checkboxradio_common.js index 0d2a62a9caa..d46aca55436 100644 --- a/tests/unit/checkboxradio/checkboxradio_common.js +++ b/tests/unit/checkboxradio/checkboxradio_common.js @@ -3,16 +3,13 @@ TestHelpers.commonWidgetTests( "checkboxradio", { defaults: { disabled: null, label: null, - icon: false, + icon: true, classes: { - "ui-checkboxradio": null, - "ui-checkbox": null, - "ui-radio": null, - "ui-checkbox-label": "ui-corner-all", - "ui-radio-label": "ui-corner-all", + "ui-checkboxradio": "", + "ui-checkboxradio-label": "ui-corner-all", + "ui-checkboxradio-radio-label": "", "ui-checkboxradio-icon": "ui-corner-all", - "ui-radio-checked": null, - "ui-checkbox-checked": null + "ui-checkboxradio-checked": "" }, // Callbacks diff --git a/tests/unit/checkboxradio/checkboxradio_core.js b/tests/unit/checkboxradio/checkboxradio_core.js index 35f162a8c8c..ed7e1330be0 100644 --- a/tests/unit/checkboxradio/checkboxradio_core.js +++ b/tests/unit/checkboxradio/checkboxradio_core.js @@ -14,7 +14,8 @@ test("Checkbox", function() { ok( !label.hasClass(".ui-button)") ); input.checkboxradio(); strictEqual( input.attr( "class" ), "ui-helper-hidden-accessible ui-checkboxradio" ); - strictEqual( label.attr( "class" ), "ui-button ui-widget ui-checkbox-label ui-corner-all" ); + strictEqual( label.attr( "class" ), "ui-icon-beginning ui-button ui-widget" + + " ui-checkboxradio-label ui-corner-all" ); }); test("Radios", function() { diff --git a/tests/unit/checkboxradio/checkboxradio_methods.js b/tests/unit/checkboxradio/checkboxradio_methods.js index ee96f556a43..618f254b449 100644 --- a/tests/unit/checkboxradio/checkboxradio_methods.js +++ b/tests/unit/checkboxradio/checkboxradio_methods.js @@ -21,7 +21,7 @@ module( "Checkboxradio: methods" ); strictEqual( widget.find( ".ui-icon" ).length, 1, "Icon is recreated on refresh" ); checkbox.prop( "checked", true ); checkbox.checkboxradio( "refresh" ); - strictEqual( widget.hasClass( "ui-checkbox-checked" ), true, + strictEqual( widget.hasClass( "ui-checkboxradio-checked" ), true, "State updated based on checked property" ); }); @@ -82,7 +82,7 @@ module( "Checkboxradio: methods" ); strictEqual( widget.find( ".ui-icon" ).length, 1, "Icon is recreated on refresh" ); radio.prop( "checked", true ); radio.checkboxradio( "refresh" ); - strictEqual( widget.hasClass( "ui-radio-checked" ), true, + strictEqual( widget.hasClass( "ui-checkboxradio-checked" ), true, "State updated based on checked property" ); }); diff --git a/tests/unit/checkboxradio/checkboxradio_options.js b/tests/unit/checkboxradio/checkboxradio_options.js index d58a130268e..46fd9e904b0 100644 --- a/tests/unit/checkboxradio/checkboxradio_options.js +++ b/tests/unit/checkboxradio/checkboxradio_options.js @@ -60,7 +60,7 @@ module( "Checkboxradio: checkbox: options" ); expect( 9 ); - checkbox.checkboxradio(); + checkbox.checkboxradio({ icon: false }); widget = checkbox.checkboxradio( "widget" ); @@ -75,8 +75,8 @@ module( "Checkboxradio: checkbox: options" ); strictEqual( widget.find( "span" ).length, 1, "Label contains a span when created with icon:true" ); - strictEqual( widget.find( "span" ).attr( "class" ), - "ui-checkboxradio-icon ui-corner-all ui-icon ui-icon-background ui-icon-blank", + strictEqual( widget.find( "span" ).is( ".ui-checkboxradio-icon.ui-corner-all.ui-icon." + + "ui-icon-background.ui-icon-blank" ), true, "Icon span has proper classes when created not checked" ); checkbox.checkboxradio( "destroy" ).prop( "checked", true ); @@ -85,8 +85,8 @@ module( "Checkboxradio: checkbox: options" ); icon: true }); - strictEqual( widget.find( "span" ).attr( "class" ), - "ui-checkboxradio-icon ui-corner-all ui-icon ui-icon-background ui-icon-check", + strictEqual( widget.find( "span" ).is( ".ui-checkboxradio-icon.ui-corner-all.ui-icon." + + "ui-icon-background.ui-icon-check" ), true, "Icon span has proper classes when created checked" ); checkbox.checkboxradio( "option", "icon", false ); @@ -96,8 +96,8 @@ module( "Checkboxradio: checkbox: options" ); checkbox.checkboxradio( "option", "icon", true ); - strictEqual( widget.find( "span" ).attr( "class" ), - "ui-checkboxradio-icon ui-corner-all ui-icon ui-icon-background ui-icon-check", + strictEqual( widget.find( "span" ).is( ".ui-checkboxradio-icon.ui-corner-all.ui-icon." + + "ui-icon-background.ui-icon-check" ), true, "Icon span has proper classes when option set to true and :is( checked )" ); checkbox.prop( "checked", false ).checkboxradio( "refresh" ); @@ -108,8 +108,8 @@ module( "Checkboxradio: checkbox: options" ); checkbox.checkboxradio( "option", "icon", true ); - strictEqual( widget.find( "span" ).attr( "class" ), - "ui-checkboxradio-icon ui-corner-all ui-icon ui-icon-background ui-icon-blank", + strictEqual( widget.find( "span" ).is( ".ui-checkboxradio-icon.ui-corner-all.ui-icon." + + "ui-icon-background.ui-icon-blank" ), true, "Icon span has proper classes when option set to true and not checked" ); checkbox.checkboxradio( "destroy" ); @@ -118,6 +118,13 @@ module( "Checkboxradio: checkbox: options" ); "Label does not contain a span after destroy when icon true" ); }); + function getLabelText( label, element ) { + var text = ""; + label.contents().not( element ).each( function() { + text += ( this.nodeType === 3 ) ? $( this ).text() : ""; + }); + return text; + } test( "options: label", function() { var checkbox = $( "#checkbox-option-label" ), widget; @@ -130,7 +137,7 @@ module( "Checkboxradio: checkbox: options" ); strictEqual( checkbox.checkboxradio( "option", "label" ), "checkbox label", "When no value passed on create text from dom is used for option" ); - strictEqual( widget.contents().not( this.element ), + strictEqual( getLabelText( widget, checkbox ), "checkbox label", "When no value passed on create text from dom is used in dom" ); checkbox.checkboxradio( "destroy" ); @@ -141,7 +148,7 @@ module( "Checkboxradio: checkbox: options" ); strictEqual( checkbox.checkboxradio( "option", "label" ), "foo", "When value is passed on create value is used for option" ); - strictEqual( widget.contents().not( this.element ), + strictEqual( getLabelText( widget, checkbox ), "foo", "When value is passed on create value is used in dom" ); checkbox.checkboxradio( "destroy" ); @@ -151,21 +158,21 @@ module( "Checkboxradio: checkbox: options" ); strictEqual( checkbox.checkboxradio( "option", "label" ), "foo", "When null is passed on create text from dom is used for option" ); - strictEqual( widget.contents().not( this.element ), + strictEqual( getLabelText( widget, checkbox ), "foo", "When null is passed on create text from dom is used in dom" ); checkbox.checkboxradio( "option", "label", "bar" ); strictEqual( checkbox.checkboxradio( "option", "label" ), "bar", "When value is passed value is used for option" ); - strictEqual( widget.contents().not( this.element ), + strictEqual( getLabelText( widget, checkbox ), "bar", "When value is passed value is used in dom" ); checkbox.checkboxradio( "option", "label", null ); strictEqual( checkbox.checkboxradio( "option", "label" ), "bar", "When null is passed text from dom is used for option" ); - strictEqual( widget.contents().not( this.element ), + strictEqual( getLabelText( widget, checkbox ), "bar", "When null is passed text from dom is used in dom" ); }); diff --git a/themes/base/checkboxradio.css b/themes/base/checkboxradio.css index c522e2d22f3..52c17c0ffd8 100644 --- a/themes/base/checkboxradio.css +++ b/themes/base/checkboxradio.css @@ -9,14 +9,11 @@ * http://api.jqueryui.com/checkboxradio/#theming */ -.ui-checkbox { - display: none; -} -.ui-checkbox-label .ui-icon-background { +.ui-checkboxradio-label .ui-icon-background { border-radius: .12em; border: none; } -.ui-radio-label .ui-icon.ui-icon-background { +.ui-checkboxradio-radio-label .ui-icon-background { width: 16px; height: 16px; border-radius: 1em; @@ -26,8 +23,8 @@ background-color: rgba( 0, 0, 0, .3 ); opacity: .3; } -.ui-radio-label.ui-radio-checked .ui-icon, -.ui-radio-label.ui-radio-checked:hover .ui-icon { +.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon, +.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon { background-image: none; background-color: #fff; width: 8px; diff --git a/ui/button.js b/ui/button.js index 1faaf749987..02549e13e57 100644 --- a/ui/button.js +++ b/ui/button.js @@ -57,7 +57,7 @@ $.widget( "ui.button", { _getCreateOptions: function() { var disabled, - options = {}; + options = this._super() || {}; this.isInput = this.element.is( "input" ); this.originalLabel = this.isInput ? this.element.val() : this.element.html(); @@ -232,7 +232,7 @@ $.widget( "ui.button", { }); // DEPRECATED -if ( $.uiBackCompat ) { +if ( $.uiBackCompat === false ) { // Text and Icons options $.widget( "ui.button", $.ui.button, { diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index d91f3dbd4d1..d7c68fac22a 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -26,7 +26,8 @@ var baseClasses = "ui-button ui-widget", typeClasses = "ui-state-focus ui-radio-label ui-checkbox-label ui-state-active " + - "ui-icon-beginning ui-icon-end ui-icon-top ui-icon-bottom ui-radio-checked ui-checkbox-checked", + "ui-icon-beginning ui-icon-end ui-icon-top ui-icon-bottom ui-checkboxradio-radio-checked " + + "ui-checkboxradio-checkbox-checked", formResetHandler = function() { var form = $( this ); setTimeout(function() { @@ -62,21 +63,18 @@ $.widget( "ui.checkboxradio", { icon: false, >>>>>>> db16c96... Checkboxradio: add classes option classes: { - "ui-checkboxradio": null, - "ui-checkbox": null, - "ui-radio": null, - "ui-checkbox-label": "ui-corner-all", - "ui-radio-label": "ui-corner-all", + "ui-checkboxradio": "", + "ui-checkboxradio-label": "ui-corner-all", + "ui-checkboxradio-radio-label": "", "ui-checkboxradio-icon": "ui-corner-all", - "ui-radio-checked": null, - "ui-checkbox-checked": null + "ui-checkboxradio-checked": "" } }, _getCreateOptions: function() { var disabled, that = this, - options = {}; + options = this._super() || {}; this._readLabel(); @@ -180,10 +178,14 @@ $.widget( "ui.checkboxradio", { this.element.addClass( "ui-helper-hidden-accessible " + this._classes( "ui-checkboxradio" ) ); - this.label.addClass( baseClasses + " " + this._classes( "ui-" + this.type + "-label" ) ); + this.label.addClass( baseClasses + " " + this._classes( "ui-checkboxradio-label" ) ); + + if ( this.type === "radio" ) { + this.label.addClass( "ui-checkboxradio-radio-label" ); + } if ( checked ) { - this.label.addClass( this._classes( "ui-" + this.type + "-checked" ) + + this.label.addClass( this._classes( "ui-checkboxradio-checked" ) + " ui-state-active" ); } if ( this.options.label && this.options.label !== this.originalLabel ) { @@ -199,7 +201,7 @@ $.widget( "ui.checkboxradio", { _toggleClasses: function() { var checked = this.element.is( ":checked" ); - this.label.toggleClass( this._classes( "ui-" + this.type + "-checked" ) + + this.label.toggleClass( this._classes( "ui-checkboxradio-checked" ) + " ui-state-active", checked ); if ( this.options.icon && this.type === "checkbox" ) { this.icon @@ -212,12 +214,12 @@ $.widget( "ui.checkboxradio", { .map(function() { return $( this ).checkboxradio( "widget" )[ 0 ]; }) - .removeClass( "ui-state-active " + this._classes( "ui-radio-checked" ) ); + .removeClass( "ui-state-active " + this._classes( "ui-checkboxradio-checked" ) ); } }, _destroy: function() { - this.label.removeClass( this._classes( "ui-radio-label ui-checkbox-label" ) + " " + + this.label.removeClass( this._classes( "ui-checkboxradio-radio-label ui-checkboxradio-label" ) + " " + baseClasses + " " + typeClasses ); if ( this.icon ) { this.icon.remove(); @@ -226,6 +228,28 @@ $.widget( "ui.checkboxradio", { " ui-helper-hidden-accessible" ); }, + _elementsFromClassKey: function( classKey ) { + var parts = classKey.split( "-" ), + checkedType = parts[ 2 ] === this.type || parts[ 2 ] === undefined, + checkedClass = parts[ 3 ] === "checked" || this.element.is( ":checked" ); + switch ( classKey ) { + case "ui-checkboxradio": + case "ui-checkboxradio-radio-label": + case "ui-checkboxradio-label": + case "ui-checkboxradio-checked": + if ( checkedType && checkedClass ) { + return this.label; + } + return $(); + case "ui-checkboxradio-icon": + if ( this.icon ) { + return this.icon; + } + return $(); + } + return this._superApply( arguments ); + }, + _setOption: function( key, value ) { var original; if ( key === "label" && value === null ) { @@ -270,7 +294,7 @@ $.widget( "ui.checkboxradio", { var checked = this.element.is( ":checked" ), isDisabled = this.element.is( ":disabled" ); this._updateIcon( checked ); - this.label.toggleClass( "ui-state-active " + this._classes( "ui-" + this.type + "-checked" ), checked ); + this.label.toggleClass( "ui-state-active " + this._classes( "ui-checkboxradio-checked" ), checked ); if ( this.options.label !== null ) { this.label.contents().not( this.element.add( this.icon ) ).remove(); this.label.append( this.options.label ); From 30415302e23353f5dcfd6a4199711aa4a965d1b3 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Fri, 22 Aug 2014 23:39:35 -0400 Subject: [PATCH 061/107] Controlgroup: Inital commit of new widget This widget replaces the buttonset widget --- demos/button/icons.html | 1 + demos/controlgroup/default.html | 104 +++++++++++++ demos/controlgroup/index.html | 3 + demos/controlgroup/toolbar.html | 2 +- demos/index.html | 1 + demos/tooltip/video-player.html | 7 +- tests/unit/controlgroup/controlgroup.html | 61 ++++++++ .../unit/controlgroup/controlgroup_common.js | 15 ++ tests/unit/controlgroup/controlgroup_core.js | 89 +++++++++++ .../unit/controlgroup/controlgroup_methods.js | 130 ++++++++++++++++ .../unit/controlgroup/controlgroup_options.js | 92 +++++++++++ themes/base/base.css | 1 + themes/base/button.css | 18 +++ themes/base/controlgroup.css | 26 ++++ themes/base/core.css | 26 ---- ui/controlgroup.js | 143 ++++++++++++++++++ 16 files changed, 690 insertions(+), 29 deletions(-) create mode 100644 tests/unit/controlgroup/controlgroup.html create mode 100644 tests/unit/controlgroup/controlgroup_common.js create mode 100644 tests/unit/controlgroup/controlgroup_methods.js create mode 100644 tests/unit/controlgroup/controlgroup_options.js create mode 100644 themes/base/controlgroup.css create mode 100644 ui/controlgroup.js diff --git a/demos/button/icons.html b/demos/button/icons.html index 3982ab7fc48..089e669ff75 100644 --- a/demos/button/icons.html +++ b/demos/button/icons.html @@ -36,6 +36,7 @@

    Widget

    +

    CSS

    diff --git a/demos/controlgroup/default.html b/demos/controlgroup/default.html index 9e4bcdd80ef..37090024285 100644 --- a/demos/controlgroup/default.html +++ b/demos/controlgroup/default.html @@ -2,7 +2,11 @@ +<<<<<<< HEAD jQuery UI Controlgroup - Default Functionality +======= + jQuery UI Controlgroup - Default Funstionality +>>>>>>> 14168e2... Controlgroup: Inital commit of new widget @@ -29,13 +33,17 @@ .ui-controlgroup-vertical select { width: 100%; } +<<<<<<< HEAD .ui-controlgroup.ui-controlgroup-vertical > button.ui-button { text-align: center; } +======= +>>>>>>> 14168e2... Controlgroup: Inital commit of new widget
    +<<<<<<< HEAD

    A Controlgroup featuring various form controls

    @@ -86,5 +94,101 @@

    Controlgroup

    >>>>>>> 423b976... Checkboxradio: Fixed demos and tests
    +======= +

    Some buttons with various combinations of text and icons.

    +
    +
    +

    Widget

    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    +
    +
    +

    CSS

    +
    + + + + + +
    +
    +
    + + + + + +
    +
    +>>>>>>> 14168e2... Controlgroup: Inital commit of new widget diff --git a/demos/controlgroup/index.html b/demos/controlgroup/index.html index 58e2f7eda7a..8fd3f752f89 100644 --- a/demos/controlgroup/index.html +++ b/demos/controlgroup/index.html @@ -9,7 +9,10 @@ diff --git a/demos/controlgroup/toolbar.html b/demos/controlgroup/toolbar.html index f90fb304009..ab02b83fb10 100644 --- a/demos/controlgroup/toolbar.html +++ b/demos/controlgroup/toolbar.html @@ -142,7 +142,7 @@
     The Rime of the Ancient Mariner (text of 1834)
     BY SAMUEL TAYLOR COLERIDGE
    -Argument 
    +Argument
     
     How a Ship having passed the Line was driven by storms to the cold Country towards the South Pole;
     and how from thence she made her course to the tropical Latitude of the Great Pacific Ocean; and 
    diff --git a/demos/index.html b/demos/index.html
    index 4b4d04e06b5..89375dde704 100644
    --- a/demos/index.html
    +++ b/demos/index.html
    @@ -12,6 +12,7 @@
     	
  • autocomplete
  • button
  • checkboxradio
  • +
  • controlgroup
  • datepicker
  • dialog
  • draggable
  • diff --git a/demos/tooltip/video-player.html b/demos/tooltip/video-player.html index 23747bb204f..986be0d25da 100644 --- a/demos/tooltip/video-player.html +++ b/demos/tooltip/video-player.html @@ -10,6 +10,7 @@ + @@ -78,8 +79,10 @@ notify( button ); }); }); - $( ".set" ).buttonset({ - items: "button" + $( ".set" ).controlgroup({ + items: { + "button" : "button" + } }); $( "button.menu" ) diff --git a/tests/unit/controlgroup/controlgroup.html b/tests/unit/controlgroup/controlgroup.html new file mode 100644 index 00000000000..5b97d5378ec --- /dev/null +++ b/tests/unit/controlgroup/controlgroup.html @@ -0,0 +1,61 @@ + + + + + jQuery UI Controlgroup Test Suite + + + + + + + + + + + + + + + + +
    +
    +
    + + + + + + + +
    +
    + + diff --git a/tests/unit/controlgroup/controlgroup_common.js b/tests/unit/controlgroup/controlgroup_common.js new file mode 100644 index 00000000000..53f722b7ce2 --- /dev/null +++ b/tests/unit/controlgroup/controlgroup_common.js @@ -0,0 +1,15 @@ +TestHelpers.commonWidgetTests( "controlgroup", { + defaults: { + disabled: null, + items: { + "button": "input[type=button], input[type=submit], input[type=reset], button, a", + "checkboxradio": "input[type='checkbox'], input[type='radio']", + "selectmenu": "select" + }, + direction: "horizontal", + excludeInvisible: true, + + // Callbacks + create: null + } +}); diff --git a/tests/unit/controlgroup/controlgroup_core.js b/tests/unit/controlgroup/controlgroup_core.js index e69de29bb2d..98c53170f67 100644 --- a/tests/unit/controlgroup/controlgroup_core.js +++ b/tests/unit/controlgroup/controlgroup_core.js @@ -0,0 +1,89 @@ +module( "Controlgroup: Core" ); + +function hasCornerClass( className, element ) { + if ( className ) { + return element.hasClass( className ); + } + + return element.attr( "class" ).match( /ui-corner/g ); +} + +test( "selectmenu: open/close corners", function() { + expect( 1 ); + var element = $( ".controlgroup" ).controlgroup(), + selects = element.find( "select" ), + selectButton = selects.eq( 0 ).selectmenu( "widget" ); + + expect( 12 ); + + selects.eq( 0 ).selectmenu( "open" ); + + strictEqual( selectButton.hasClass( "ui-corner-tl" ), true, + "Horizontal: First selectmenu gets ui-corner-tl when opened" ); + + selects.eq( 0 ).selectmenu( "close" ); + + strictEqual( selectButton.hasClass( "ui-corner-left" ), true, + "Horizontal: First selectmenu gets ui-corner-left when closed" ); + + selectButton = selects.eq( 1 ).selectmenu( "widget" ); + + selects.eq( 1 ).selectmenu( "open" ); + + strictEqual( !!hasCornerClass( false, selectButton ), false, + "Horizontal: Middle selectmenu does not get corner class when opened" ); + + selects.eq( 1 ).selectmenu( "close" ); + + strictEqual( !!hasCornerClass( false, selectButton ), false, + "Horizontal: Middle selectmenu does not get corner class when closed" ); + + selectButton = selects.eq( 2 ).selectmenu( "widget" ); + + selects.eq( 2 ).selectmenu( "open" ); + + strictEqual( selectButton.hasClass( "ui-corner-tr" ), true, + "Horizontal: Last selectmenu gets ui-corner-tr when opened" ); + + selects.eq( 2 ).selectmenu( "close" ); + + strictEqual( selectButton.hasClass( "ui-corner-right" ), true, + "Horizontal: Last selectmenu gets ui-corner-right when closed" ); + + element.controlgroup( "option", "direction", "vertical" ); + selectButton = selects.eq( 0 ).selectmenu( "widget" ); + + selects.eq( 0 ).selectmenu( "open" ); + + strictEqual( selectButton.hasClass( "ui-corner-top" ), true, + "vertical: First selectmenu gets ui-corner-top when opened" ); + + selects.eq( 0 ).selectmenu( "close" ); + + strictEqual( selectButton.hasClass( "ui-corner-top" ), true, + "vertical: First selectmenu gets ui-corner-top when closed" ); + + selectButton = selects.eq( 1 ).selectmenu( "widget" ); + + selects.eq( 1 ).selectmenu( "open" ); + + strictEqual( !!hasCornerClass( false, selectButton ), false, + "vertical: Middle selectmenu does not get corner class when opened" ); + + selects.eq( 1 ).selectmenu( "close" ); + + strictEqual( !!hasCornerClass( false, selectButton ), false, + "vertical: Middle selectmenu does not get corner class when closed" ); + + selectButton = selects.eq( 2 ).selectmenu( "widget" ); + + selects.eq( 2 ).selectmenu( "open" ); + + strictEqual( !!hasCornerClass( false, selectButton ), false, + "vertical: Last selectmenu does not get corner class when opened" ); + + selects.eq( 2 ).selectmenu( "close" ); + + strictEqual( selectButton.hasClass( "ui-corner-bottom" ), true, + "vertical: Last selectmenu gets ui-corner-bottom when closed" ); +}); \ No newline at end of file diff --git a/tests/unit/controlgroup/controlgroup_methods.js b/tests/unit/controlgroup/controlgroup_methods.js new file mode 100644 index 00000000000..90715055a6e --- /dev/null +++ b/tests/unit/controlgroup/controlgroup_methods.js @@ -0,0 +1,130 @@ +module( "Controlgroup: methods" ); + +test( "destroy", function() { + expect( 1 ); + domEqual( ".controlgroup", function() { + $( ".controlgroup" ).controlgroup().controlgroup( "destroy" ); + }); +}); +test( "disable", function() { + var tests = 1, + element = $( ".controlgroup" ).controlgroup().controlgroup( "disable" ); + strictEqual( element.hasClass( "ui-state-disabled" ), false, + "ui-state-disabled is not present on widget after disabling" ); + $.each( $.ui.controlgroup.prototype.options.items, function( widget, selector ){ + element.children( selector ).each(function(){ + expect( ++tests ); + strictEqual( $( this )[ widget ]( "widget" ).hasClass( "ui-state-disabled"), true, + "Child " + widget + " widgets are disabled" ); + }); + }); +}); + +test( "enable", function() { + var tests = 1, + element = $( ".controlgroup" ).controlgroup().controlgroup( "enable" ); + strictEqual( element.hasClass( "ui-state-disabled" ), false, + "ui-state-disabled is not present on widget after enabling" ); + $.each( $.ui.controlgroup.prototype.options.items, function( widget, selector ){ + element.children( selector ).each(function(){ + expect( ++tests ); + strictEqual( $( this )[ widget ]( "widget" ).hasClass( "ui-state-disabled"), false, + "Child " + widget + " widgets are not disabled" ); + }); + }); +}); + +function hasCornerClass( className, element ) { + if ( className ) { + return element.hasClass( className ); + } + + return element.attr( "class" ).match( /ui-corner/g ); +} +test( "refresh", function() { + var count = 0, + tests = { + "checkboxradio": "", + "selectmenu": "", + "button": " + + + + + Button with icon on the bottom + +
    +
    + + +
    + + + + Button with icon on the bottom + +
    diff --git a/tests/unit/controlgroup/controlgroup_common.js b/tests/unit/controlgroup/controlgroup_common.js index 53f722b7ce2..21acab744ac 100644 --- a/tests/unit/controlgroup/controlgroup_common.js +++ b/tests/unit/controlgroup/controlgroup_common.js @@ -8,6 +8,11 @@ TestHelpers.commonWidgetTests( "controlgroup", { }, direction: "horizontal", excludeInvisible: true, + classes: { + "ui-controlgroup": "", + "ui-controlgroup-horizontal": "", + "ui-controlgroup-vertical": "" + }, // Callbacks create: null diff --git a/tests/unit/controlgroup/controlgroup_options.js b/tests/unit/controlgroup/controlgroup_options.js index aa99352c555..4228a51639a 100644 --- a/tests/unit/controlgroup/controlgroup_options.js +++ b/tests/unit/controlgroup/controlgroup_options.js @@ -52,6 +52,39 @@ test( "items", function() { expect( 2 ); }); +test( "items: custom selector", function() { + var element = $( ".controlgroup-custom-selector" ).controlgroup({ + items: { + "button": ".button" + } + }); + strictEqual( element.children( ".ui-button" ).length, 5, + "Correct child widgets are called when custom selector used" ); + expect( 1 ); +}); + +$.widget( "ui.test", { + _create: function (){ + this.element.addClass( "ui-test ui-button" ); + }, + refresh: function() { + return; + } +}); +test( "items: custom widget", function() { + var element = $( ".controlgroup-custom-widget" ).controlgroup({ + items: { + "test": ".test" + } + }); + + strictEqual( element.children( ".ui-button" ).length, 7, + "Correct child widgets are called when custom selector used" ); + strictEqual( element.children( ".ui-test" ).length, 1, + "Custom widget called" ); + expect( 2 ); +}); + test( "excludeInvisible", function() { var element = $( ".controlgroup" ).controlgroup(), buttons = element.children( ".ui-button" ); diff --git a/themes/base/controlgroup.css b/themes/base/controlgroup.css index 0aff19d5edd..c708d60e0a2 100644 --- a/themes/base/controlgroup.css +++ b/themes/base/controlgroup.css @@ -11,14 +11,14 @@ .ui-controlgroup > .ui-button { - margin-left: -2px; - margin-right: -1px; + margin-left: -.14em; + margin-right: -.14em; } .ui-controlgroup.ui-controlgroup-vertical > .ui-button { display: block; width: 100%; - margin-top: -1px; - margin-bottom: -1px; + margin-top: 0; + margin-bottom: 0; text-align: left; } .ui-controlgroup-vertical label.ui-button { diff --git a/ui/controlgroup.js b/ui/controlgroup.js index c0a3ab1589c..2a5a0af275f 100644 --- a/ui/controlgroup.js +++ b/ui/controlgroup.js @@ -35,52 +35,19 @@ $.widget( "ui.controlgroup", { "selectmenu": "select" }, direction: "horizontal", - excludeInvisible: true + excludeInvisible: true, + classes: { + "ui-controlgroup": "", + "ui-controlgroup-horizontal": "", + "ui-controlgroup-vertical": "" + } }, _create: function() { this._enhance(); - this._on( this.element, { - "selectmenuopen": "_handleSelectmenuOpen", - "selectmenuclose": "_handleSelectmenuClose" - }); - }, - - _handleSelectmenuOpen: function( event ) { - var target = $( event.target ), - widget = target.selectmenu ( "widget" ), - vertical = this.options.direction === "vertical"; - if ( widget[ 0 ] !== this.first[ 0 ] || !vertical ) { - widget.removeClass( "ui-corner-top" ); - } - if ( vertical && widget[ 0 ] === this.last[ 0 ] ) { - widget.removeClass( "ui-corner-bottom" ); - } - if ( widget[ 0 ] === this.first[ 0 ] ) { - widget.removeClass( "ui-corner-left" ) - .addClass( "ui-corner-" + ( vertical ? "top" : "tl" ) ); - } - if ( widget[ 0 ] === this.last[ 0 ] ) { - widget.removeClass( "ui-corner-right" ) - .addClass( vertical ? "" : "ui-corner-tr" ); - } - }, - - _handleSelectmenuClose: function( event ) { - var target = $( event.target ), - widget = target.selectmenu ( "widget" ), - vertical = this.options.direction === "vertical"; - widget.removeClass( "ui-corner-all" ); - if ( widget[ 0 ] === this.first[ 0 ] ) { - widget.removeClass( "ui-corner-left" ) - .addClass( "ui-corner-" + ( vertical ? "top" : "left" ) ); - } - if ( widget[ 0 ] === this.last[ 0 ] ) { - widget.removeClass( "ui-corner-right" ) - .addClass( vertical ? "ui-corner-bottom" : "ui-corner-right" ); - } }, + // To support enhanced option in jQuery mobile we isolate dom manipulation here _enhance: function() { this.element.attr( "role", "toolbar" ); this.refresh(); @@ -89,20 +56,75 @@ $.widget( "ui.controlgroup", { _destroy: function() { this._callChildMethod( "destroy" ); this.element.removeAttr( "role" ); - this.element.removeClass( "ui-controlgroup ui-selectmenu-vertical ui-controlgroup-horizontal" ) - .children().removeClass( "ui-corner-all ui-corner-top" + + this.element.removeClass( + this._classes( "ui-controlgroup ui-controlgroup-vertical ui-controlgroup-horizontal" ) + ).children().removeClass( "ui-corner-all ui-corner-top" + " ui-corner-bottom ui-corner-left ui-corner-tl ui-corner-tr" ); }, _callChildMethod: function( method, filter ) { var that = this; $.each( this.options.items, function( widget, selector ) { + var options = {}; + switch ( widget ) { + case "button": + options.classes = { + "ui-button": null + }; + break; + case "checkboxradio": + options.classes = { + "ui-checkbox-label": null, + "ui-radio-label": null + }; + break; + case "selectmenu": + options.classes = { + "ui-selectmenu-button-open": null, + "ui-selectmenu-button-closed": null + }; + break; + } if ( $.fn[ widget ] && selector ) { - that.element.children( selector ).not( filter )[ widget ]( method ); + that.element.children( selector ).not( filter )[ widget ]( method ? + method : options ); } }); }, + _button_options: function() { + return { + classes: { + "ui-button": "" + } + }; + }, + + _checkboxradio_options: function() { + return { + classes: { + "ui-checkbox-label": "", + "ui-radio-label": "" + } + }; + }, + + _selectmenu_options: function() { + return { + classes: { + "ui-selectmenu-button-open": "", + "ui-selectmenu-button-closed": "" + } + }; + }, + + _elementsFromClassKey: function( classKey ) { + if ( this.options.direction !== classKey.split( "-" )[ 2 ] ) { + return $(); + } + return this._superApply( arguments ); + }, + _setOption: function( key, value ) { var original = this.options[ key ]; @@ -120,8 +142,11 @@ $.widget( "ui.controlgroup", { }, refresh: function() { - var vertical = ( this.options.direction === "vertical" ); - this.element.addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction ); + var firstClasses = {}, + lastClasses = {}, + vertical = ( this.options.direction === "vertical" ); + this.element.addClass( this._classes( "ui-controlgroup ui-controlgroup-" + + this.options.direction ) ); this._callChildMethod( undefined ); this.visible = this.element.children( ".ui-button" ).removeClass( function(index, css) { return ( css.match( /ui-corner-[a-z]*/g ) || [] ).join( " " ); @@ -131,7 +156,26 @@ $.widget( "ui.controlgroup", { .addClass( "ui-corner-" + ( vertical ? "top" : "left" ) ); this.last = this.visible.filter( ":last" ) .addClass( "ui-corner-" + ( vertical ? "bottom" : "right" ) ); - this.element.find( this.options.items.selectmenu ).selectmenu( "refresh" ); + if ( $.ui.selectmenu ) { + if ( this.first.is( ".ui-selectmenu-button" ) && !vertical ) { + firstClasses[ "ui-selectmenu-button-open" ] = "ui-corner-tl"; + firstClasses[ "ui-selectmenu-button-closed" ] = "ui-corner-left"; + $( "#" + this.first.attr( "id" ).replace( /-button/, "" ) ) + .selectmenu( "option", "classes", firstClasses ); + } + if ( this.last.is( ".ui-selectmenu-button" ) ) { + if ( vertical ) { + lastClasses[ "ui-selectmenu-button-open" ] = null; + lastClasses[ "ui-selectmenu-button-closed" ] = "ui-corner-bottom"; + } else { + lastClasses[ "ui-selectmenu-button-open" ] = "ui-corner-tr"; + lastClasses[ "ui-selectmenu-button-closed" ] = "ui-corner-right"; + } + $( "#" + this.last.attr( "id" ).replace( /-button/, "" ) ) + .selectmenu( "option", "classes", lastClasses ); + } + this.element.find( this.options.items.selectmenu ).selectmenu( "refresh" ); + } this._callChildMethod( "refresh" ); } From 2a037482bb9b502846e6d416c5711d0b45c41d82 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 22 Oct 2014 09:32:41 -0400 Subject: [PATCH 063/107] Controlgroup: Add extension points for special options and refresh Methods of new widgets added via the items option. --- ui/controlgroup.js | 61 +++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/ui/controlgroup.js b/ui/controlgroup.js index 2a5a0af275f..0a518f7f993 100644 --- a/ui/controlgroup.js +++ b/ui/controlgroup.js @@ -62,31 +62,15 @@ $.widget( "ui.controlgroup", { " ui-corner-bottom ui-corner-left ui-corner-tl ui-corner-tr" ); }, - _callChildMethod: function( method, filter ) { + _callChildMethod: function( method ) { var that = this; $.each( this.options.items, function( widget, selector ) { var options = {}; - switch ( widget ) { - case "button": - options.classes = { - "ui-button": null - }; - break; - case "checkboxradio": - options.classes = { - "ui-checkbox-label": null, - "ui-radio-label": null - }; - break; - case "selectmenu": - options.classes = { - "ui-selectmenu-button-open": null, - "ui-selectmenu-button-closed": null - }; - break; + if ( that[ "_" + widget + "_options" ] ) { + options = that[ "_" + widget + "_options" ](); } if ( $.fn[ widget ] && selector ) { - that.element.children( selector ).not( filter )[ widget ]( method ? + that.element.children( selector )[ widget ]( method ? method : options ); } }); @@ -130,8 +114,7 @@ $.widget( "ui.controlgroup", { this._super( key, value ); if ( key === "direction" ) { - this.element.removeClass( "ui-controlgroup-" + original ) - .addClass( "ui-controlgroup-" + value ); + this.element.removeClass( "ui-controlgroup-" + original ); } if ( key === "disabled" ) { this._callChildMethod( value ? "disable" : "enable" ); @@ -141,21 +124,11 @@ $.widget( "ui.controlgroup", { }, - refresh: function() { + _refresh_selectmenu: function() { var firstClasses = {}, lastClasses = {}, vertical = ( this.options.direction === "vertical" ); - this.element.addClass( this._classes( "ui-controlgroup ui-controlgroup-" + - this.options.direction ) ); - this._callChildMethod( undefined ); - this.visible = this.element.children( ".ui-button" ).removeClass( function(index, css) { - return ( css.match( /ui-corner-[a-z]*/g ) || [] ).join( " " ); - }).filter( this.options.excludeInvisible ? ":visible" : "*" ); - this.first = this.visible.filter( ":first" ) - .addClass( "ui-corner-" + ( vertical ? "top" : "left" ) ); - this.last = this.visible.filter( ":last" ) - .addClass( "ui-corner-" + ( vertical ? "bottom" : "right" ) ); if ( $.ui.selectmenu ) { if ( this.first.is( ".ui-selectmenu-button" ) && !vertical ) { firstClasses[ "ui-selectmenu-button-open" ] = "ui-corner-tl"; @@ -176,6 +149,28 @@ $.widget( "ui.controlgroup", { } this.element.find( this.options.items.selectmenu ).selectmenu( "refresh" ); } + }, + + refresh: function() { + var that = this, + vertical = ( this.options.direction === "vertical" ); + this.element.addClass( this._classes( "ui-controlgroup ui-controlgroup-" + + this.options.direction ) ); + this._callChildMethod( undefined ); + this.visible = this.element.children( ".ui-button" ).removeClass( function(index, css) { + return ( css.match( /ui-corner-[a-z]*/g ) || [] ).join( " " ); + }).filter( this.options.excludeInvisible ? ":visible" : "*" ); + + this.first = this.visible.eq( 0 ) + .addClass( "ui-corner-" + ( vertical ? "top" : "left" ) ); + this.last = this.visible.last() + .addClass( "ui-corner-" + ( vertical ? "bottom" : "right" ) ); + + $.each( this.options.items, function( widget ) { + if ( that[ "_refresh_" + widget ] ) { + that[ "_refresh_" + widget ](); + } + }); this._callChildMethod( "refresh" ); } From 696fbb0070d1594dfddacceeff128dcc9990bbd7 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 12 Nov 2014 12:14:38 -0500 Subject: [PATCH 064/107] Button: breakup deprecated tests --- demos/controlgroup/default.html | 105 ------------------ demos/controlgroup/index.html | 3 - tests/unit/button/button.html | 3 + tests/unit/button/button_common_deprecated.js | 22 ++++ tests/unit/button/button_core_deprecated.js | 12 ++ tests/unit/button/button_deprecated.html | 80 +++++++++++++ ui/button.js | 13 ++- ui/checkboxradio.js | 20 ++-- 8 files changed, 132 insertions(+), 126 deletions(-) create mode 100644 tests/unit/button/button_common_deprecated.js create mode 100644 tests/unit/button/button_core_deprecated.js create mode 100644 tests/unit/button/button_deprecated.html diff --git a/demos/controlgroup/default.html b/demos/controlgroup/default.html index 75c8c89fc4f..de865b1f476 100644 --- a/demos/controlgroup/default.html +++ b/demos/controlgroup/default.html @@ -2,11 +2,7 @@ -<<<<<<< HEAD jQuery UI Controlgroup - Default Functionality -======= - jQuery UI Controlgroup - Default Funstionality ->>>>>>> 14168e2... Controlgroup: Inital commit of new widget @@ -34,17 +30,13 @@ .ui-controlgroup-vertical select { width: 100%; } -<<<<<<< HEAD .ui-controlgroup.ui-controlgroup-vertical > button.ui-button { text-align: center; } -======= ->>>>>>> 14168e2... Controlgroup: Inital commit of new widget
    -<<<<<<< HEAD

    A Controlgroup featuring various form controls

    @@ -93,102 +85,5 @@

    Controlgroup

    - -======= -

    Some buttons with various combinations of text and icons.

    - -
    -

    Widget

    -
    - - - - - - - -
    -
    -
    - - - - - - - -
    -
    -
    -

    CSS

    -
    - - - - - -
    -
    -
    - - - - - -
    -
    ->>>>>>> 14168e2... Controlgroup: Inital commit of new widget diff --git a/demos/controlgroup/index.html b/demos/controlgroup/index.html index 8fd3f752f89..58e2f7eda7a 100644 --- a/demos/controlgroup/index.html +++ b/demos/controlgroup/index.html @@ -9,10 +9,7 @@ diff --git a/tests/unit/button/button.html b/tests/unit/button/button.html index b334575e892..ad68882b953 100644 --- a/tests/unit/button/button.html +++ b/tests/unit/button/button.html @@ -5,6 +5,9 @@ jQuery UI Button Test Suite + diff --git a/tests/unit/button/button_common_deprecated.js b/tests/unit/button/button_common_deprecated.js new file mode 100644 index 00000000000..cfcccb38d94 --- /dev/null +++ b/tests/unit/button/button_common_deprecated.js @@ -0,0 +1,22 @@ +TestHelpers.commonWidgetTests( "button", { + defaults: { + disabled: null, + showLabel: true, + label: null, + icon: null, + iconPosition: "beginning", + text: true, + icons: { + primary: null, + secondary: null + }, + classes: { + "ui-button": "ui-corner-all", + "ui-button-icon-only": "", + "ui-button-icon": "" + }, + + // Callbacks + create: null + } +}); diff --git a/tests/unit/button/button_core_deprecated.js b/tests/unit/button/button_core_deprecated.js new file mode 100644 index 00000000000..3db47a7ec85 --- /dev/null +++ b/tests/unit/button/button_core_deprecated.js @@ -0,0 +1,12 @@ +/* + * button_core.js + */ + + +(function($) { + +module( "Button: core deprecated" ); + + + +})(jQuery); diff --git a/tests/unit/button/button_deprecated.html b/tests/unit/button/button_deprecated.html new file mode 100644 index 00000000000..feb5bfd603b --- /dev/null +++ b/tests/unit/button/button_deprecated.html @@ -0,0 +1,80 @@ + + + + + jQuery UI Button Test Suite + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + +
    + + + +
    +
    + + + +
    + +
    + + + +
    + +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    + + + + +
    + + + +
    + + diff --git a/ui/button.js b/ui/button.js index 02549e13e57..53a8f7102af 100644 --- a/ui/button.js +++ b/ui/button.js @@ -62,7 +62,7 @@ $.widget( "ui.button", { this.isInput = this.element.is( "input" ); this.originalLabel = this.isInput ? this.element.val() : this.element.html(); - disabled = this.element.prop( "disabled" ); + disabled = this.element[ 0 ].disabled; if ( disabled != null ) { options.disabled = disabled; } @@ -83,7 +83,7 @@ $.widget( "ui.button", { formElement.on( "reset" + this.eventNamespace, formResetHandler ); if ( this.options.disabled == null ) { - this.options.disabled = this.element.prop( "disabled" ) || false; + this.options.disabled = this.element[ 0 ].disabled || false; } this.hasTitle = this.element.attr( "title" ); @@ -212,7 +212,8 @@ $.widget( "ui.button", { } this._super( key, value ); if ( key === "disabled" ) { - this.element.toggleClass( "ui-state-disabled", value ).prop( "disabled", value ).blur(); + this.element.toggleClass( "ui-state-disabled", value )[ 0 ].disabled = value; + this.element.blur(); } }, @@ -221,7 +222,7 @@ $.widget( "ui.button", { // Make sure to only check disabled if its an element that supports this otherwise // check for the disabled class to determine state var isDisabled = this.element.is( "input, button" ) ? - this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" ); + this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" ); if ( isDisabled !== this.options.disabled ) { this._setOptions({ "disabled": isDisabled }); @@ -232,7 +233,7 @@ $.widget( "ui.button", { }); // DEPRECATED -if ( $.uiBackCompat === false ) { +if ( $.uiBackCompat !== false ) { // Text and Icons options $.widget( "ui.button", $.ui.button, { @@ -279,7 +280,7 @@ if ( $.uiBackCompat === false ) { }); $.fn.button = (function( orig ) { return function() { - if ( this[ 0 ].tagName === "input" && ( this.attr( "type") === "checkbox" || + if ( this.tagName === "input" && ( this.attr( "type") === "checkbox" || this.attr( "type" ) === "radio" ) ) { if ( $.ui.checkboxradio ) { if ( arguments.length === 0 ) { diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index d7c68fac22a..16c1365afc7 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -57,11 +57,7 @@ $.widget( "ui.checkboxradio", { options: { disabled: null, label: null, -<<<<<<< HEAD icon: true, -======= - icon: false, ->>>>>>> db16c96... Checkboxradio: add classes option classes: { "ui-checkboxradio": "", "ui-checkboxradio-label": "ui-corner-all", @@ -83,7 +79,7 @@ $.widget( "ui.checkboxradio", { that.originalLabel += ( this.nodeType === 3 ) ? $( this ).text() : this.outerHTML; }); - disabled = this.element.prop( "disabled" ); + disabled = this.element[ 0 ].disabled; if ( disabled != null ) { options.disabled = disabled; } @@ -104,7 +100,7 @@ $.widget( "ui.checkboxradio", { formElement.on( "reset" + this.eventNamespace, formResetHandler ); if ( this.options.disabled == null ) { - this.options.disabled = this.element.prop( "disabled" ) || false; + this.options.disabled = this.element[ 0 ].disabled || false; } this._readType(); @@ -171,7 +167,7 @@ $.widget( "ui.checkboxradio", { }, _enhance: function() { - var checked = this.element.is( ":checked" ); + var checked = this.element[ 0 ].checked; this._setOption( "disabled", this.options.disabled ); this._updateIcon( checked ); @@ -200,7 +196,7 @@ $.widget( "ui.checkboxradio", { }, _toggleClasses: function() { - var checked = this.element.is( ":checked" ); + var checked = this.element[ 0 ].checked; this.label.toggleClass( this._classes( "ui-checkboxradio-checked" ) + " ui-state-active", checked ); if ( this.options.icon && this.type === "checkbox" ) { @@ -231,7 +227,7 @@ $.widget( "ui.checkboxradio", { _elementsFromClassKey: function( classKey ) { var parts = classKey.split( "-" ), checkedType = parts[ 2 ] === this.type || parts[ 2 ] === undefined, - checkedClass = parts[ 3 ] === "checked" || this.element.is( ":checked" ); + checkedClass = parts[ 3 ] === "checked" || this.element[ 0 ].checked; switch ( classKey ) { case "ui-checkboxradio": case "ui-checkboxradio-radio-label": @@ -258,7 +254,7 @@ $.widget( "ui.checkboxradio", { this._super( key, value ); if ( key === "disabled" ) { this.label.toggleClass( "ui-state-disabled", !!value ); - this.element.prop( "disabled", !!value ); + this.element[ 0 ].disabled = !!value; return; } if ( key === "label" && value === null ) { @@ -291,8 +287,8 @@ $.widget( "ui.checkboxradio", { }, refresh: function() { - var checked = this.element.is( ":checked" ), - isDisabled = this.element.is( ":disabled" ); + var checked = this.element[ 0 ].checked, + isDisabled = this.element[ 0 ].disabled; this._updateIcon( checked ); this.label.toggleClass( "ui-state-active " + this._classes( "ui-checkboxradio-checked" ), checked ); if ( this.options.label !== null ) { From 46e444b089b19f53da7935501810cff46e492146 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 3 Dec 2014 11:55:18 -0500 Subject: [PATCH 065/107] Button: Add backcompat tests and fix backcompat issues --- tests/unit/button/button_core_deprecated.js | 18 +++ tests/unit/button/button_deprecated.html | 13 +- .../unit/button/button_methods_deprecated.js | 37 +++++ tests/unit/button/button_options.js | 17 +-- .../unit/button/button_options_deprecated.js | 141 ++++++++++++++++++ ui/button.js | 45 ++++-- 6 files changed, 243 insertions(+), 28 deletions(-) create mode 100644 tests/unit/button/button_methods_deprecated.js create mode 100644 tests/unit/button/button_options_deprecated.js diff --git a/tests/unit/button/button_core_deprecated.js b/tests/unit/button/button_core_deprecated.js index 3db47a7ec85..bdba0cf1d81 100644 --- a/tests/unit/button/button_core_deprecated.js +++ b/tests/unit/button/button_core_deprecated.js @@ -7,6 +7,24 @@ module( "Button: core deprecated" ); +test( "Calling button on a checkbox input calls checkboxradio widget", function(){ + var checkbox = $( "#checkbox01" ); + expect( 2 ); + checkbox.button(); + equal( checkbox.is( ":ui-checkboxradio" ), true, + "Calling button on a checkbox creats checkboxradio instance" ); + equal( checkbox.checkboxradio( "option", "icon" ), false, + "Calling button on a checkbox sets the checkboxradio icon option to false" ); +}); +test( "Calling buttonset calls controlgroup", function(){ + var controlgroup = $( ".buttonset" ); + + expect( 1 ); + controlgroup.buttonset(); + + equal( controlgroup.is( ":ui-controlgroup" ), true, + "Calling buttonset creats controlgroup instance" ); +}); })(jQuery); diff --git a/tests/unit/button/button_deprecated.html b/tests/unit/button/button_deprecated.html index feb5bfd603b..02c05fcc9ca 100644 --- a/tests/unit/button/button_deprecated.html +++ b/tests/unit/button/button_deprecated.html @@ -15,18 +15,21 @@ js: [ "ui/core.js", "ui/widget.js", - "ui/button.js" + "ui/button.js", + "ui/checkboxradio.js", + "ui/controlgroup.js" ] }); - - - + + + + @@ -34,7 +37,7 @@
    -
    +
    diff --git a/tests/unit/button/button_methods_deprecated.js b/tests/unit/button/button_methods_deprecated.js new file mode 100644 index 00000000000..bad97c24a33 --- /dev/null +++ b/tests/unit/button/button_methods_deprecated.js @@ -0,0 +1,37 @@ +/* + * button_methods.js + */ +(function($) { + +module( "Button: methods deprecated" ); + +test( "destroy", function() { + expect( 1 ); + domEqual( "#checkbox02", function() { + $( "#checkbox02" ).button().button( "destroy" ); + }); +}); + +test( "refresh: Ensure disabled state is preserved correctly.", function() { + expect( 4 ); + var element = null; + + element = $( "#checkbox02" ); + element.button( { disabled: true } ).button( "refresh" ); + ok( element.button( "option", "disabled" ), "Checkboxes should remain disabled after refresh"); + + element = $( "#radio02" ); + element.button( { disabled: true } ).button( "refresh" ); + ok( element.button( "option", "disabled" ), "Radio buttons should remain disabled after refresh"); + + element = $( "#checkbox02" ); + element.button( { disabled: true} ).prop( "disabled", false ).button( "refresh" ); + ok( !element.button( "option", "disabled" ), "Changing a checkbox's disabled property should update the state after refresh."); + + element = $( "#radio02" ); + element.button( { disabled: true} ).prop( "disabled", false ).button( "refresh" ); + ok( !element.button( "option", "disabled" ), "Changing a radio button's disabled property should update the state after refresh."); + +}); + +})(jQuery); \ No newline at end of file diff --git a/tests/unit/button/button_options.js b/tests/unit/button/button_options.js index 37a93eae3bc..9b3be9b50fc 100644 --- a/tests/unit/button/button_options.js +++ b/tests/unit/button/button_options.js @@ -8,13 +8,13 @@ module( "button: options" ); test( "disabled, explicit value", function( assert ) { expect( 7 ); - var element = $( "#radio01" ).button({ disabled: false }); + var element = $( "#button" ).button({ disabled: false }); deepEqual( element.button( "option", "disabled" ), false, "disabled option set to false" ); deepEqual( element.prop( "disabled" ), false, "element is disabled" ); assert.lacksClasses( element.button( "widget" ), "ui-state-disabled ui-button-disabled" ); - element = $( "#radio02" ).button({ disabled: true }); + element = $( "#button" ).button({ disabled: true }); ok( !element.button( "widget" ).attr( "aria-disabled" ), "element does not get aria-disabled" ); assert.hasClasses( element.button( "widget" ), "ui-button-disabled ui-state-disabled" ); @@ -24,16 +24,11 @@ test( "disabled, explicit value", function( assert ) { }); test( "disabled, null", function() { - expect( 4 ); - $( "#radio01" ).button({ disabled: null }); - strictEqual( $("#radio01").button("option", "disabled"), false, + expect( 2 ); + $( "#button" ).button({ disabled: null }); + strictEqual( $("#button").button("option", "disabled"), false, "disabled option set to false"); - strictEqual( $("#radio01").prop("disabled"), false, "element is disabled"); - - $( "#radio02" ).prop( "disabled", true ).button({ disabled: null }); - deepEqual( true, $( "#radio02" ).button( "option", "disabled" ), - "disabled option set to true" ); - deepEqual( true, $( "#radio02" ).prop( "disabled" ), "element is not disabled" ); + strictEqual( $("#button").prop("disabled"), false, "element is disabled"); }); <<<<<<< HEAD diff --git a/tests/unit/button/button_options_deprecated.js b/tests/unit/button/button_options_deprecated.js new file mode 100644 index 00000000000..3ddcea82075 --- /dev/null +++ b/tests/unit/button/button_options_deprecated.js @@ -0,0 +1,141 @@ +/* + * button_options_deprecated.js + */ +(function($) { + +module( "button: options deprecated" ); + +test( "Setting items option on button set sets the button properties on the items option", function() { + expect( 2 ); + + var controlgroup = $( ".buttonset" ); + + controlgroup.buttonset({ items: "bar" }); + equal( controlgroup.controlgroup( "option", "items.button" ), "bar", + "items.button set when setting items option on init on buttonset" ); + + controlgroup.buttonset( "option", "items", "foo" ); + equal( controlgroup.controlgroup( "option", "items.button" ), "foo", + "items.button set when setting items option on buttonset" ); +}); + +test( "disabled, null", function() { + expect( 2 ); + + $( "#radio02" ).prop( "disabled", true ).button({ disabled: null }); + deepEqual( true, $( "#radio02" ).button( "option", "disabled" ), + "disabled option set to true" ); + deepEqual( true, $( "#radio02" ).prop( "disabled" ), "element is not disabled" ); +}); + +test( "text and showLabel options proxied", function(){ + expect( 8 ); + var button = $( "#button" ); + button.button({ + "text": false, + "icon": "ui-icon-gear" + }); + equal( button.button( "option", "showLabel" ), false, + "Setting the text option to false sets the showLabel option to false on init" ); + button.button( "option", "showLabel", true ); + equal( button.button( "option", "text" ), true, + "Setting showLabel true with option method sets text option to true" ); + button.button( "option", "text", false ); + equal( button.button( "option", "showLabel" ), false, + "Setting text false with option method sets showLabel option to false" ); + button.button( "option", "text", true ); + equal( button.button( "option", "showLabel" ), true, + "Setting text true with option method sets showLabel option to true" ); + button.button( "option", "showLabel", false ); + equal( button.button( "option", "text" ), false, + "Setting showLabel false with option method sets text option to false" ); + button.button( "destroy" ); + button.button({ + "text": true, + "icon": "ui-icon-gear" + }); + equal( button.button( "option", "showLabel" ), true, + "Setting the text option to false sets the showLabel option to true on init" ); + button.button( "destroy" ); + button.button({ + "showLabel": true, + "icon": "ui-icon-gear" + }); + equal( button.button( "option", "text" ), true, + "Setting the showLabel option to true sets the text option to true on init" ); + button.button( "destroy" ); + button.button({ + "showLabel": false, + "icon": "ui-icon-gear" + }); + equal( button.button( "option", "text" ), false, + "Setting the showLabel option to false sets the text option to false on init" ); +}); + +test( "icon and icons options properly proxied", function(){ + expect( 10 ); + + var button = $( "#button" ); + + button.button({ + "icon": "foo" + }); + + equal( button.button( "option", "icons.primary" ), "foo", + "Icon option properly proxied on init" ); + + button.button({ + "icon": "bar" + }); + + equal( button.button( "option", "icons.primary" ), "bar", + "Icon option properly proxied with option method" ); + + button.button({ + "icons": { + primary: "foo" + } + }); + + equal( button.button( "option", "icon" ), "foo", + "Icons primary option properly proxied with option method" ); + equal( button.button( "option", "iconPosition" ), "beginning", + "Icons primary option sets iconPosition option to beginning" ); + + button.button({ + "icons": { + secondary: "bar" + } + }); + + equal( button.button( "option", "icon" ), "bar", + "Icons secondary option properly proxied with option method" ); + equal( button.button( "option", "iconPosition" ), "end", + "Icons secondary option sets iconPosition option to end" ); + + button.button( "destroy" ); + + button.button({ + "icons": { + primary: "foo" + } + }); + + equal( button.button( "option", "icon" ), "foo", + "Icons primary option properly proxied on init" ); + equal( button.button( "option", "iconPosition" ), "beginning", + "Icons primary option sets iconPosition option to beginning on init" ); + + button.button({ + "icons": { + secondary: "bar" + } + }); + + equal( button.button( "option", "icon" ), "bar", + "Icons secondary option properly proxied on init" ); + equal( button.button( "option", "iconPosition" ), "end", + "Icons secondary option sets iconPosition option to end on init" ); +}); + +})(jQuery); \ No newline at end of file diff --git a/ui/button.js b/ui/button.js index 53a8f7102af..a79728dfcc5 100644 --- a/ui/button.js +++ b/ui/button.js @@ -189,7 +189,7 @@ $.widget( "ui.button", { // Make sure we can't end up with a button that has no text nor icon if ( key === "showLabel" ) { - if ( ( !value && !this.options.icon ) || value ) { + if ( ( !value && this.options.icon ) || value ) { this.element.toggleClass( this._classes( "ui-button-icon-only" ), !value ) .toggleClass( this.options.iconPosition, !!value ); this._updateTooltip(); @@ -249,6 +249,9 @@ if ( $.uiBackCompat !== false ) { if ( this.options.showLabel && !this.options.text ) { this.options.showLabel = this.options.text; } + if ( !this.options.showLabel && this.options.text ) { + this.options.text = this.options.showLabel; + } if ( !this.options.icon && ( this.options.icons.primary || this.options.icons.secondary ) ) { if ( this.options.icons.primary ) { @@ -258,6 +261,9 @@ if ( $.uiBackCompat !== false ) { this.options.iconPosition = "end"; } } + if ( this.options.icon ) { + this.options.icons.primary = this.options.icon; + } this._super(); }, @@ -265,13 +271,19 @@ if ( $.uiBackCompat !== false ) { if ( key === "text" ) { this._setOption( "showLabel", value ); } + if ( key === "showLabel" ) { + this.options.text = value; + } + if ( key === "icon" ) { + this.options.icons.primary = value; + } if ( key === "icons" ) { this._setOption( "icon", value ); if ( value.primary ) { - this._setOption( "icon", value ); + this._setOption( "icon", value.primary ); this._setOption( "iconPosition", "beginning" ); } else if ( value.secondary ) { - this._setOption( "icon", value ); + this._setOption( "icon", value.secondary ); this._setOption( "iconPosition", "end" ); } } @@ -280,15 +292,15 @@ if ( $.uiBackCompat !== false ) { }); $.fn.button = (function( orig ) { return function() { - if ( this.tagName === "input" && ( this.attr( "type") === "checkbox" || - this.attr( "type" ) === "radio" ) ) { + if ( this.length > 0 && this[ 0 ].tagName === "INPUT" && + ( this.attr( "type") === "checkbox" || this.attr( "type" ) === "radio" ) ) { if ( $.ui.checkboxradio ) { if ( arguments.length === 0 ) { return this.checkboxradio({ "icon": false }); } else { - return this.checkboxradio.apply( arguments ); + return this.checkboxradio.apply( this, arguments ); } } else { $.error( "Checkboxradio widget missing" ); @@ -298,13 +310,22 @@ if ( $.uiBackCompat !== false ) { } }; })( $.fn.button ); - $.fn.buttonset = function( method, key, value ) { - if ( method === "option" && key === "items" ) { - value = { - "button": value - }; + $.fn.buttonset = function() { + if ( $.ui.controlgroup ) { + if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) { + return this.controlgroup.apply( this, + [ arguments[ 0 ], "items.button", arguments[ 2 ] ] ); + } else if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) { + arguments[ 0 ].items = { + button: arguments[ 0 ].items + }; + } else if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) { + return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] ); + } + return this.controlgroup.apply( this, arguments ); + } else { + $.error( "Controlgroup widget missing" ); } - this.controlgroup.call( method, key, value ); }; } From 540f91f5bb0e2f80e4abb1c09ce363be519cc6fb Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 3 Dec 2014 11:56:44 -0500 Subject: [PATCH 066/107] Checkboxradio: formatting --- ui/checkboxradio.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index 16c1365afc7..cbe32e7b4a8 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -290,7 +290,8 @@ $.widget( "ui.checkboxradio", { var checked = this.element[ 0 ].checked, isDisabled = this.element[ 0 ].disabled; this._updateIcon( checked ); - this.label.toggleClass( "ui-state-active " + this._classes( "ui-checkboxradio-checked" ), checked ); + this.label.toggleClass( "ui-state-active " + + this._classes( "ui-checkboxradio-checked" ), checked ); if ( this.options.label !== null ) { this.label.contents().not( this.element.add( this.icon ) ).remove(); this.label.append( this.options.label ); From e824c5ce401a9deec322a6f4068e49263a45f39c Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 7 Jan 2015 21:48:24 -0500 Subject: [PATCH 067/107] Button: Updates based on new classes api --- tests/unit/button/button_common.js | 4 +- tests/unit/button/button_common_deprecated.js | 4 +- ui/button.js | 61 ++++++------------- 3 files changed, 20 insertions(+), 49 deletions(-) diff --git a/tests/unit/button/button_common.js b/tests/unit/button/button_common.js index d13f1e1c3a9..4364c163589 100644 --- a/tests/unit/button/button_common.js +++ b/tests/unit/button/button_common.js @@ -7,9 +7,7 @@ TestHelpers.commonWidgetTests( "button", { icon: null, iconPosition: "beginning", classes: { - "ui-button": "ui-corner-all", - "ui-button-icon-only": "", - "ui-button-icon": "" + "ui-button": "ui-corner-all" }, // Callbacks diff --git a/tests/unit/button/button_common_deprecated.js b/tests/unit/button/button_common_deprecated.js index cfcccb38d94..0607c596196 100644 --- a/tests/unit/button/button_common_deprecated.js +++ b/tests/unit/button/button_common_deprecated.js @@ -11,9 +11,7 @@ TestHelpers.commonWidgetTests( "button", { secondary: null }, classes: { - "ui-button": "ui-corner-all", - "ui-button-icon-only": "", - "ui-button-icon": "" + "ui-button": "ui-corner-all" }, // Callbacks diff --git a/ui/button.js b/ui/button.js index a79728dfcc5..608e36fbaa6 100644 --- a/ui/button.js +++ b/ui/button.js @@ -29,9 +29,7 @@ } }(function( $ ) { -var typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons" + - " ui-button-text-only ui-icon-beginning ui-icon-end ui-icon-top ui-icon-bottom", - formResetHandler = function() { +var formResetHandler = function() { var form = $( this ); setTimeout(function() { form.find( ".ui-button" ).filter( ":ui-button" ).button( "refresh" ); @@ -49,9 +47,7 @@ $.widget( "ui.button", { icon: null, iconPosition: "beginning", classes: { - "ui-button": "ui-corner-all", - "ui-button-icon-only": "", - "ui-button-icon": "" + "ui-button": "ui-corner-all" } }, @@ -103,9 +99,8 @@ $.widget( "ui.button", { _enhance: function() { this._setOption( "disabled", this.options.disabled ); - this.element - .addClass( this._classes( "ui-button" ) + " ui-widget" ) - .attr( "role", "button" ); + this._addClass( "ui-button", " ui-widget" ); + this.element.attr( "role", "button" ); // Check to see if the label needs to be set or if its already correct if ( this.options.label && this.options.label !== this.originalLabel ) { @@ -130,26 +125,24 @@ $.widget( "ui.button", { _updateIcon: function( icon ) { if ( !this.icon ) { - this.icon = $( "" ).addClass( this._classes( "ui-button-icon" ) + " ui-icon" ); + this.icon = $( "" ); + this._addClass( this.icon, "ui-button-icon", " ui-icon" ); if ( !this.options.showLabel ) { - this.element.addClass( this._classes( "ui-button-icon-only" ) ); + this._addClass( "ui-button-icon-only" ); } else { - this.element.addClass( "ui-icon-" + this.options.iconPosition ); + this._addClass( null, "ui-icon-" + this.options.iconPosition ); } } else { - this.icon.removeClass( this.options.icon ); + this._removeClass( this.icon, null, this.options.icon ); } - - this.icon.addClass( icon ).appendTo( this.element ); + this._addClass( this.icon, null, icon ); + this.icon.appendTo( this.element ); return this; }, _destroy: function() { - this.element - .removeClass( this._classes( "ui-button ui-button-icon-only" ) + " ui-widget" + - " ui-state-active " + typeClasses ) - .removeAttr( "role" ); + this.element.removeAttr( "role" ); if ( this.icon ) { this.icon.remove(); @@ -159,46 +152,29 @@ $.widget( "ui.button", { } }, - _elementsFromClassKey: function( classKey ) { - switch ( classKey ) { - case "ui-button-icon-only": - if ( this.options.showLabel ) { - return $(); - } - break; - case "ui-button-icon": - if ( this.icon ) { - return this.icon; - } - return $(); - default: - return this._superApply( arguments ); - } - }, - _setOption: function( key, value ) { if ( key === "icon" ) { if ( value !== null ) { this._updateIcon( value ); } else { this.icon.remove(); - this.element.removeClass( this._classes( "ui-button-icon" ) + " ui-icon-" + - this.options.iconPosition ); + this._removeClass( "ui-button-icon", " ui-icon-" + this.options.iconPosition ); } } // Make sure we can't end up with a button that has no text nor icon if ( key === "showLabel" ) { if ( ( !value && this.options.icon ) || value ) { - this.element.toggleClass( this._classes( "ui-button-icon-only" ), !value ) - .toggleClass( this.options.iconPosition, !!value ); + this._toggleClass( this._classes( "ui-button-icon-only" ), null, !value ) + ._toggleClass( null, this.options.iconPosition, value ); this._updateTooltip(); } else { value = true; } } if ( key === "iconPosition" && this.options.icon ) { - this.element.addClass( value ).removeClass( this.options.iconPosition ); + this._addClass( null, value ) + ._removeClass( null, this.options.iconPosition ); } if ( key === "label" ) { if ( this.isInput ) { @@ -212,7 +188,7 @@ $.widget( "ui.button", { } this._super( key, value ); if ( key === "disabled" ) { - this.element.toggleClass( "ui-state-disabled", value )[ 0 ].disabled = value; + this._toggleClass( null, "ui-state-disabled", value ).element[ 0 ].disabled = value; this.element.blur(); } }, @@ -278,7 +254,6 @@ if ( $.uiBackCompat !== false ) { this.options.icons.primary = value; } if ( key === "icons" ) { - this._setOption( "icon", value ); if ( value.primary ) { this._setOption( "icon", value.primary ); this._setOption( "iconPosition", "beginning" ); From 0365ebd14fac9c30a40a6445a225cfd85e3c8387 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 7 Jan 2015 21:49:27 -0500 Subject: [PATCH 068/107] Checkboxradio: updates based on new classes api --- .../checkboxradio/checkboxradio_common.js | 5 +- .../unit/checkboxradio/checkboxradio_core.js | 7 +- ui/checkboxradio.js | 89 ++++++------------- 3 files changed, 32 insertions(+), 69 deletions(-) diff --git a/tests/unit/checkboxradio/checkboxradio_common.js b/tests/unit/checkboxradio/checkboxradio_common.js index d46aca55436..e4ce2d205e1 100644 --- a/tests/unit/checkboxradio/checkboxradio_common.js +++ b/tests/unit/checkboxradio/checkboxradio_common.js @@ -5,11 +5,8 @@ TestHelpers.commonWidgetTests( "checkboxradio", { label: null, icon: true, classes: { - "ui-checkboxradio": "", "ui-checkboxradio-label": "ui-corner-all", - "ui-checkboxradio-radio-label": "", - "ui-checkboxradio-icon": "ui-corner-all", - "ui-checkboxradio-checked": "" + "ui-checkboxradio-icon": "ui-corner-all" }, // Callbacks diff --git a/tests/unit/checkboxradio/checkboxradio_core.js b/tests/unit/checkboxradio/checkboxradio_core.js index ed7e1330be0..572162d3224 100644 --- a/tests/unit/checkboxradio/checkboxradio_core.js +++ b/tests/unit/checkboxradio/checkboxradio_core.js @@ -13,9 +13,10 @@ test("Checkbox", function() { ok( input.is( ":visible" ) ); ok( !label.hasClass(".ui-button)") ); input.checkboxradio(); - strictEqual( input.attr( "class" ), "ui-helper-hidden-accessible ui-checkboxradio" ); - strictEqual( label.attr( "class" ), "ui-icon-beginning ui-button ui-widget" + - " ui-checkboxradio-label ui-corner-all" ); + equal( input.is( ".ui-helper-hidden-accessible.ui-checkboxradio" ), true, + "Input has proper classes" ); + equal( label.is( ".ui-icon-beginning.ui-button.ui-widget.ui-checkboxradio-label.ui-corner-all" ), + true, "Label has proper classes" ); }); test("Radios", function() { diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index cbe32e7b4a8..9ebd9d00325 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -24,11 +24,7 @@ } }(function( $ ) { -var baseClasses = "ui-button ui-widget", - typeClasses = "ui-state-focus ui-radio-label ui-checkbox-label ui-state-active " + - "ui-icon-beginning ui-icon-end ui-icon-top ui-icon-bottom ui-checkboxradio-radio-checked " + - "ui-checkboxradio-checkbox-checked", - formResetHandler = function() { +var formResetHandler = function() { var form = $( this ); setTimeout(function() { form.find( ".ui-checkboxradio" ).checkboxradio( "refresh" ); @@ -59,11 +55,8 @@ $.widget( "ui.checkboxradio", { label: null, icon: true, classes: { - "ui-checkboxradio": "", "ui-checkboxradio-label": "ui-corner-all", - "ui-checkboxradio-radio-label": "", - "ui-checkboxradio-icon": "ui-corner-all", - "ui-checkboxradio-checked": "" + "ui-checkboxradio-icon": "ui-corner-all" } }, @@ -110,10 +103,10 @@ $.widget( "ui.checkboxradio", { this._on({ "change": "_toggleClasses", "focus": function() { - this.label.addClass( "ui-state-focus ui-visual-focus" ); + this._addClass( this.label, null, "ui-state-focus ui-visual-focus" ); }, "blur": function() { - this.label.removeClass( "ui-state-focus ui-visual-focus" ); + this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" ); } }); }, @@ -171,18 +164,15 @@ $.widget( "ui.checkboxradio", { this._setOption( "disabled", this.options.disabled ); this._updateIcon( checked ); - this.element.addClass( "ui-helper-hidden-accessible " + - this._classes( "ui-checkboxradio" ) ); + this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible " ); - this.label.addClass( baseClasses + " " + this._classes( "ui-checkboxradio-label" ) ); + this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); if ( this.type === "radio" ) { - this.label.addClass( "ui-checkboxradio-radio-label" ); + this._addClass( this.label, "ui-checkboxradio-radio-label" ); } - if ( checked ) { - this.label.addClass( this._classes( "ui-checkboxradio-checked" ) + - " ui-state-active" ); + this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" ); } if ( this.options.label && this.options.label !== this.originalLabel ) { this.label.html( this.icon ? this.icon : "" ).append( this.options.label ); @@ -197,53 +187,29 @@ $.widget( "ui.checkboxradio", { _toggleClasses: function() { var checked = this.element[ 0 ].checked; - this.label.toggleClass( this._classes( "ui-checkboxradio-checked" ) + - " ui-state-active", checked ); + this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); if ( this.options.icon && this.type === "checkbox" ) { - this.icon - .toggleClass( "ui-icon-check", checked ) - .toggleClass( "ui-icon-blank", !checked ); + this._toggleClass( this.icon, null, "ui-icon-check", checked ) + ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); } if ( this.type === "radio" ) { radioGroup( this.element[0] ) .not( this.element ) - .map(function() { - return $( this ).checkboxradio( "widget" )[ 0 ]; - }) - .removeClass( "ui-state-active " + this._classes( "ui-checkboxradio-checked" ) ); + .each( function(){ + var instance = $( this ).checkboxradio( "instance" ); + + if ( instance ) { + instance._removeClass( instance.label, + "ui-checkboxradio-checked", "ui-state-active" ); + } + }); } }, _destroy: function() { - this.label.removeClass( this._classes( "ui-checkboxradio-radio-label ui-checkboxradio-label" ) + " " + - baseClasses + " " + typeClasses ); if ( this.icon ) { this.icon.remove(); } - this.element.removeClass( this._classes( "ui-checkboxradio" ) + - " ui-helper-hidden-accessible" ); - }, - - _elementsFromClassKey: function( classKey ) { - var parts = classKey.split( "-" ), - checkedType = parts[ 2 ] === this.type || parts[ 2 ] === undefined, - checkedClass = parts[ 3 ] === "checked" || this.element[ 0 ].checked; - switch ( classKey ) { - case "ui-checkboxradio": - case "ui-checkboxradio-radio-label": - case "ui-checkboxradio-label": - case "ui-checkboxradio-checked": - if ( checkedType && checkedClass ) { - return this.label; - } - return $(); - case "ui-checkboxradio-icon": - if ( this.icon ) { - return this.icon; - } - return $(); - } - return this._superApply( arguments ); }, _setOption: function( key, value ) { @@ -253,8 +219,8 @@ $.widget( "ui.checkboxradio", { } this._super( key, value ); if ( key === "disabled" ) { - this.label.toggleClass( "ui-state-disabled", !!value ); - this.element[ 0 ].disabled = !!value; + this._toggleClass( this.label, null, "ui-state-disabled", value ); + this.element[ 0 ].disabled = value; return; } if ( key === "label" && value === null ) { @@ -264,11 +230,10 @@ $.widget( "ui.checkboxradio", { }, _updateIcon: function( checked ) { - var toAdd = this._classes( "ui-checkboxradio-icon" ) + - " ui-icon ui-icon-background "; + var toAdd = "ui-icon ui-icon-background "; if ( this.options.icon ) { - this.label.addClass( "ui-icon-beginning" ); + this._addClass( this.label, null, "ui-icon-beginning" ); if ( !this.icon ) { this.icon = $( "" ); } @@ -278,9 +243,10 @@ $.widget( "ui.checkboxradio", { } else { toAdd += "ui-icon-blank"; } - this.icon.addClass( toAdd ).appendTo( this.label ); + this._addClass( this.icon, "ui-checkboxradio-icon", toAdd ); + this.icon.appendTo( this.label ); } else if ( this.icon !== undefined ) { - this.label.removeClass( "ui-icon-beginning" ); + this._removeClass( this.label, null, "ui-icon-beginning" ); this.icon.remove(); delete this.icon; } @@ -290,8 +256,7 @@ $.widget( "ui.checkboxradio", { var checked = this.element[ 0 ].checked, isDisabled = this.element[ 0 ].disabled; this._updateIcon( checked ); - this.label.toggleClass( "ui-state-active " + - this._classes( "ui-checkboxradio-checked" ), checked ); + this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); if ( this.options.label !== null ) { this.label.contents().not( this.element.add( this.icon ) ).remove(); this.label.append( this.options.label ); From c5364e6c7ee532fead0f187d921c056df90b391c Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 7 Jan 2015 21:50:19 -0500 Subject: [PATCH 069/107] Controlgroup: updates based on new classes api --- .../unit/controlgroup/controlgroup_common.js | 6 +- ui/controlgroup.js | 147 +++++++++--------- 2 files changed, 71 insertions(+), 82 deletions(-) diff --git a/tests/unit/controlgroup/controlgroup_common.js b/tests/unit/controlgroup/controlgroup_common.js index 21acab744ac..1df62e53d5f 100644 --- a/tests/unit/controlgroup/controlgroup_common.js +++ b/tests/unit/controlgroup/controlgroup_common.js @@ -8,11 +8,7 @@ TestHelpers.commonWidgetTests( "controlgroup", { }, direction: "horizontal", excludeInvisible: true, - classes: { - "ui-controlgroup": "", - "ui-controlgroup-horizontal": "", - "ui-controlgroup-vertical": "" - }, + classes: {}, // Callbacks create: null diff --git a/ui/controlgroup.js b/ui/controlgroup.js index 0a518f7f993..6fe130ae21e 100644 --- a/ui/controlgroup.js +++ b/ui/controlgroup.js @@ -36,11 +36,7 @@ $.widget( "ui.controlgroup", { }, direction: "horizontal", excludeInvisible: true, - classes: { - "ui-controlgroup": "", - "ui-controlgroup-horizontal": "", - "ui-controlgroup-vertical": "" - } + classes: {} }, _create: function() { @@ -54,12 +50,14 @@ $.widget( "ui.controlgroup", { }, _destroy: function() { + var that = this; + $.each( this.options.items, function( widget, selector ) { + that.element.children( selector ).map(function(){ + return $( this )[ widget ]( "widget" )[ 0 ]; + }).removeData( "ui-controlgroup-data" ); + }); this._callChildMethod( "destroy" ); this.element.removeAttr( "role" ); - this.element.removeClass( - this._classes( "ui-controlgroup ui-controlgroup-vertical ui-controlgroup-horizontal" ) - ).children().removeClass( "ui-corner-all ui-corner-top" + - " ui-corner-bottom ui-corner-left ui-corner-tl ui-corner-tr" ); }, _callChildMethod: function( method ) { @@ -67,46 +65,72 @@ $.widget( "ui.controlgroup", { $.each( this.options.items, function( widget, selector ) { var options = {}; if ( that[ "_" + widget + "_options" ] ) { - options = that[ "_" + widget + "_options" ](); + options = that[ "_" + widget + "_options" ]( "middle" ); } if ( $.fn[ widget ] && selector ) { - that.element.children( selector )[ widget ]( method ? - method : options ); + that.element + .children( selector )[ widget ]( method ? method: options ) + .each(function(){ + if ( method !== "destroy" ) { + $( this )[ widget ]( "widget" ).data( "ui-controlgroup-data", { + "type": widget, + "element": $( this ) + }); + } + }); } }); }, - _button_options: function() { - return { - classes: { - "ui-button": "" - } - }; - }, + _button_options: function( position ) { + var cornerClasses = { + "middle": null, + "first": "ui-corner-" + ( ( this.options.direction === "vertical" )? "top" : "left" ), + "last": "ui-corner-" + ( ( this.options.direction === "vertical" )? "bottom" : "right" ) + }; - _checkboxradio_options: function() { return { classes: { - "ui-checkbox-label": "", - "ui-radio-label": "" + "ui-button": cornerClasses[ position ] } }; }, - _selectmenu_options: function() { + _checkboxradio_options: function( position ) { + var cornerClasses = { + "middle": null, + "first": "ui-corner-" + ( ( this.options.direction === "vertical" )? "top" : "left" ), + "last": "ui-corner-" + ( ( this.options.direction === "vertical" )? "bottom" : "right" ) + }; + return { classes: { - "ui-selectmenu-button-open": "", - "ui-selectmenu-button-closed": "" + "ui-checkboxradio-label": cornerClasses[ position ] } }; }, - _elementsFromClassKey: function( classKey ) { - if ( this.options.direction !== classKey.split( "-" )[ 2 ] ) { - return $(); - } - return this._superApply( arguments ); + _selectmenu_options: function( position ) { + var classes = { + middle: { + "ui-selectmenu-button-open": null, + "ui-selectmenu-button-closed": null + }, + first: { + "ui-selectmenu-button-open": + "ui-corner-" + ( ( this.options.direction === "vertical" )? "top": "tl" ), + "ui-selectmenu-button-closed": + "ui-corner-" + ( ( this.options.direction === "vertical" )? "top": "left" ) + }, + last: { + "ui-selectmenu-button-open": + ( this.options.direction === "vertical" )? null: "ui-corner-tr", + "ui-selectmenu-button-closed": + "ui-corner-" + ( ( this.options.direction === "vertical" )? "bottom": "right" ) + } + + }; + return { classes: classes[ position ] }; }, _setOption: function( key, value ) { @@ -124,55 +148,24 @@ $.widget( "ui.controlgroup", { }, - _refresh_selectmenu: function() { - var firstClasses = {}, - lastClasses = {}, - vertical = ( this.options.direction === "vertical" ); - - if ( $.ui.selectmenu ) { - if ( this.first.is( ".ui-selectmenu-button" ) && !vertical ) { - firstClasses[ "ui-selectmenu-button-open" ] = "ui-corner-tl"; - firstClasses[ "ui-selectmenu-button-closed" ] = "ui-corner-left"; - $( "#" + this.first.attr( "id" ).replace( /-button/, "" ) ) - .selectmenu( "option", "classes", firstClasses ); - } - if ( this.last.is( ".ui-selectmenu-button" ) ) { - if ( vertical ) { - lastClasses[ "ui-selectmenu-button-open" ] = null; - lastClasses[ "ui-selectmenu-button-closed" ] = "ui-corner-bottom"; - } else { - lastClasses[ "ui-selectmenu-button-open" ] = "ui-corner-tr"; - lastClasses[ "ui-selectmenu-button-closed" ] = "ui-corner-right"; - } - $( "#" + this.last.attr( "id" ).replace( /-button/, "" ) ) - .selectmenu( "option", "classes", lastClasses ); - } - this.element.find( this.options.items.selectmenu ).selectmenu( "refresh" ); - } - }, - refresh: function() { - var that = this, - vertical = ( this.options.direction === "vertical" ); - this.element.addClass( this._classes( "ui-controlgroup ui-controlgroup-" + - this.options.direction ) ); - this._callChildMethod( undefined ); - this.visible = this.element.children( ".ui-button" ).removeClass( function(index, css) { - return ( css.match( /ui-corner-[a-z]*/g ) || [] ).join( " " ); - }).filter( this.options.excludeInvisible ? ":visible" : "*" ); - - this.first = this.visible.eq( 0 ) - .addClass( "ui-corner-" + ( vertical ? "top" : "left" ) ); - this.last = this.visible.last() - .addClass( "ui-corner-" + ( vertical ? "bottom" : "right" ) ); - - $.each( this.options.items, function( widget ) { - if ( that[ "_refresh_" + widget ] ) { - that[ "_refresh_" + widget ](); - } - }); - this._callChildMethod( "refresh" ); + var children, + that = this; + + this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction ); + this._callChildMethod(); + children = this.element.children( ".ui-button" ); + if ( this.options.excludeInvisible ) { + children = children.filter( ":visible" ); + } + if ( children.length ) { + [ "first", "last" ].forEach( function( value ){ + var data = children[ value ]().data( "ui-controlgroup-data" ); + data.element[ data.type ]( that[ "_" + data.type + "_options" ]( value ) ); + }); + this._callChildMethod( "refresh" ); + } } }); From a83a2843f9a739beb8613bf2c13a781de284acda Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 7 Jan 2015 21:50:51 -0500 Subject: [PATCH 070/107] Selectmenu: updates based on new classes implementation in button --- ui/selectmenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/selectmenu.js b/ui/selectmenu.js index 5c066e3a7b6..d4098ea1914 100644 --- a/ui/selectmenu.js +++ b/ui/selectmenu.js @@ -112,7 +112,7 @@ return $.widget( "ui.selectmenu", { .insertAfter( this.element ); this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed", - "ui-widget ui-state-default" ); + "ui-button ui-icon-end ui-widget ui-state-default" ); icon = $( "" ).prependTo( this.button ); this._addClass( icon, null, "ui-icon " + this.options.icons.button ); From 84b9aec4b41245c4ce91e6879d1d48f76df66a67 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 7 Jan 2015 21:51:38 -0500 Subject: [PATCH 071/107] Spinner: Updates for new button widget and classes option --- ui/spinner.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ui/spinner.js b/ui/spinner.js index d9509e17bfd..95b38825415 100644 --- a/ui/spinner.js +++ b/ui/spinner.js @@ -227,17 +227,19 @@ return $.widget( "ui.spinner", { // button bindings this.buttons = uiSpinner.find( "a" ) .attr( "tabIndex", -1 ) - .button(); + .button({ + classes: { + "ui-button": "" + } + }); // Right now button does not support classes this is already updated in button PR this._removeClass( this.buttons, "ui-corner-all" ); this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); - this._addClass( this.buttons.first().find( ".ui-button-text span" ), null, - "ui-icon " + this.options.icons.up ); - this._addClass( this.buttons.last().find( ".ui-button-text span" ), null, - "ui-icon " + this.options.icons.down ); + this.buttons.first().button( "option", "icon", this.options.icons.up ); + this.buttons.last().button( "option", "icon", this.options.icons.down ); // IE 6 doesn't understand height: 50% for the buttons // unless the wrapper has an explicit height From 93bd806892488d5d9a35e1ea8dd1e10630750243 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 7 Jan 2015 22:39:45 -0500 Subject: [PATCH 072/107] Checkboxradio: ensure we are escaping the id before its use in selector --- ui/checkboxradio.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index 9ebd9d00325..cc4a6811542 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -30,6 +30,7 @@ var formResetHandler = function() { form.find( ".ui-checkboxradio" ).checkboxradio( "refresh" ); }); }, + escapeId = new RegExp( /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g ), radioGroup = function( radio ) { var name = radio.name, form = radio.form, @@ -137,7 +138,8 @@ $.widget( "ui.checkboxradio", { ancestor = this.element.parents().last(); // Look for the label based on the id - labelSelector = "label[for='" + this.element.attr( "id" ) + "']"; + labelSelector = "label[for='" + + this.element.attr( "id" ).replace( escapeId, "\\$1" ) + "']"; this.label = ancestor.find( labelSelector ); if ( !this.label.length ) { @@ -165,7 +167,6 @@ $.widget( "ui.checkboxradio", { this._setOption( "disabled", this.options.disabled ); this._updateIcon( checked ); this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible " ); - this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); if ( this.type === "radio" ) { From 4fd59f5af3798d6326f47ec7ab040de59ad30ac8 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 7 Jan 2015 22:42:39 -0500 Subject: [PATCH 073/107] Controlgroup: Switch to using float instead of inline-block --- themes/base/controlgroup.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/themes/base/controlgroup.css b/themes/base/controlgroup.css index c708d60e0a2..ea180efef5a 100644 --- a/themes/base/controlgroup.css +++ b/themes/base/controlgroup.css @@ -11,11 +11,13 @@ .ui-controlgroup > .ui-button { - margin-left: -.14em; - margin-right: -.14em; + float: left; + margin-left: 0; + margin-right: 0; } .ui-controlgroup.ui-controlgroup-vertical > .ui-button { display: block; + float: none; width: 100%; margin-top: 0; margin-bottom: 0; From 57894ea75f23dc807c7c0f25feb4244973f63ae3 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 7 Jan 2015 22:43:20 -0500 Subject: [PATCH 074/107] Button: Add comment about filtering for performance --- ui/button.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/button.js b/ui/button.js index 608e36fbaa6..2db8dad1c87 100644 --- a/ui/button.js +++ b/ui/button.js @@ -32,6 +32,9 @@ var formResetHandler = function() { var form = $( this ); setTimeout(function() { + // We find .ui-button first then filer by :ui-button because doing a + // widget pseudo selectors are very very slow but we need to filter out + // css only buttons form.find( ".ui-button" ).filter( ":ui-button" ).button( "refresh" ); }); }; From a481cfe8880c9b0d88b8b159d88b9c79dfe7a5b6 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Thu, 8 Jan 2015 08:13:16 -0500 Subject: [PATCH 075/107] Checkboxradio: Moving radio group to be private instance method --- ui/checkboxradio.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index cc4a6811542..deab34778c0 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -30,24 +30,7 @@ var formResetHandler = function() { form.find( ".ui-checkboxradio" ).checkboxradio( "refresh" ); }); }, - escapeId = new RegExp( /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g ), - radioGroup = function( radio ) { - var name = radio.name, - form = radio.form, - radios = $( [] ); - if ( name ) { - name = name.replace( /'/g, "\\'" ); - if ( form ) { - radios = $( form ).find( "[name='" + name + "']" ); - } else { - radios = $( "[name='" + name + "']", radio.ownerDocument ) - .filter(function() { - return !this.form; - }); - } - } - return radios; - }; + escapeId = new RegExp( /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g ); $.widget( "ui.checkboxradio", { version: "@VERSION", @@ -186,6 +169,24 @@ $.widget( "ui.checkboxradio", { return this.label; }, + _getRadioGroup: function( radio ) { + var name = this.element[0].name, + form = this.element[0].form, + radios = $( [] ); + if ( name ) { + name = name.replace( /'/g, "\\'" ); + if ( form ) { + radios = $( form ).find( "[name='" + name + "']" ); + } else { + radios = $( "[name='" + name + "']", radio.ownerDocument ) + .filter(function() { + return !this.form; + }); + } + } + return radios.not( this.element ); + }, + _toggleClasses: function() { var checked = this.element[ 0 ].checked; this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); @@ -194,8 +195,7 @@ $.widget( "ui.checkboxradio", { ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); } if ( this.type === "radio" ) { - radioGroup( this.element[0] ) - .not( this.element ) + this._getRadioGroup() .each( function(){ var instance = $( this ).checkboxradio( "instance" ); From 9a4004dbe1074145f9365753956a2c7784d476e1 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Thu, 8 Jan 2015 08:17:36 -0500 Subject: [PATCH 076/107] Checkboxradio: Fixing refrence to ownerDocument --- ui/checkboxradio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index deab34778c0..c28ebe8b95d 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -178,7 +178,7 @@ $.widget( "ui.checkboxradio", { if ( form ) { radios = $( form ).find( "[name='" + name + "']" ); } else { - radios = $( "[name='" + name + "']", radio.ownerDocument ) + radios = $( "[name='" + name + "']", this.document ) .filter(function() { return !this.form; }); From cbf7fcca5503c7dbe7f21a8e29b9113f4a050391 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Tue, 3 Feb 2015 22:30:19 -0500 Subject: [PATCH 077/107] Controlgroup: Adjust selectmenu styling --- ui/controlgroup.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/controlgroup.js b/ui/controlgroup.js index 6fe130ae21e..827490263b4 100644 --- a/ui/controlgroup.js +++ b/ui/controlgroup.js @@ -130,7 +130,10 @@ $.widget( "ui.controlgroup", { } }; - return { classes: classes[ position ] }; + return { + width: "auto", + classes: classes[ position ] + }; }, _setOption: function( key, value ) { From 417e76053b7f7889353fa34c5cd7267257ed9989 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Tue, 3 Feb 2015 22:31:10 -0500 Subject: [PATCH 078/107] Checkboxradio: Fix reference to ownerDocument and remove argument --- ui/checkboxradio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js index c28ebe8b95d..ea0de73f328 100644 --- a/ui/checkboxradio.js +++ b/ui/checkboxradio.js @@ -169,7 +169,7 @@ $.widget( "ui.checkboxradio", { return this.label; }, - _getRadioGroup: function( radio ) { + _getRadioGroup: function() { var name = this.element[0].name, form = this.element[0].form, radios = $( [] ); From 6d138dcba63ccd3cae0bfe089830049757995b52 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 4 Feb 2015 10:50:27 -0500 Subject: [PATCH 079/107] Button: Switch to placing contents in the flow rather then positioning --- demos/button/icons.html | 23 ++++++------ themes/base/accordion.css | 12 ------ themes/base/button.css | 77 ++------------------------------------ themes/base/core.css | 17 +++++---- themes/base/datepicker.css | 11 ++++++ ui/button.js | 14 +++++-- 6 files changed, 46 insertions(+), 108 deletions(-) diff --git a/demos/button/icons.html b/demos/button/icons.html index 089e669ff75..32eeb12edff 100644 --- a/demos/button/icons.html +++ b/demos/button/icons.html @@ -41,25 +41,24 @@

    Widget

    CSS

    + - - +
    diff --git a/themes/base/accordion.css b/themes/base/accordion.css index edf368eca76..baffce488b1 100644 --- a/themes/base/accordion.css +++ b/themes/base/accordion.css @@ -16,18 +16,6 @@ padding: .5em .5em .5em .7em; font-size: 100%; } -.ui-accordion .ui-accordion-icons { - padding-left: 2.2em; -} -.ui-accordion .ui-accordion-icons .ui-accordion-icons { - padding-left: 2.2em; -} -.ui-accordion .ui-accordion-header .ui-accordion-header-icon { - position: absolute; - left: .5em; - top: 50%; - margin-top: -8px; -} .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; diff --git a/themes/base/button.css b/themes/base/button.css index 2659890c958..e4e85b7aa0a 100644 --- a/themes/base/button.css +++ b/themes/base/button.css @@ -9,7 +9,7 @@ * http://api.jqueryui.com/button/#theming */ .ui-button { - padding: .4em 1em; + padding: .4em; display: inline-block; position: relative; line-height: normal; @@ -34,93 +34,24 @@ /* to make room for the icon, a width needs to be set here */ .ui-button-icon-only { - width: 2.2em; + width: 2em; box-sizing: border-box; text-indent: -9999px; white-space: nowrap; } -.ui-icon { - position: absolute; - display: block; -} - /* no icon support for input elements, provide padding by default */ -input.ui-button.ui-icon-end, -input.ui-button.ui-icon-beginning, -input.ui-button.ui-icon-top, -input.ui-button.ui-icon-bottom{ - padding: .4em 1em; -} input.ui-button.ui-button-icon-only { text-indent: 0; } /* button icon element(s) */ -.ui-button.ui-icon-end .ui-icon { - left: auto; - right: .5em; -} - -.ui-button.ui-icon-top .ui-icon, -.ui-button.ui-icon-bottom .ui-icon { - left: 50%; - margin-left: -11px; -} - -.ui-button.ui-icon-top .ui-icon { - top: .6em; -} - -.ui-button.ui-icon-bottom .ui-icon { - top: auto; - bottom: .05em; - -} - .ui-button-icon-only .ui-icon { - left: 50%; - margin-left: -8px; -} - -.ui-button .ui-icon { position: absolute; - display: block; top: 50%; + left: 50%; margin-top: -8px; -} - -.ui-button.ui-icon-beginning { - padding-left: 2.4em; -} - -.ui-button.ui-icon-end { - padding: .4em 2.1em .4em 1em; -} - -.ui-button.ui-icon-top { - padding: 1.1em 1em .4em 1em; -} - -.ui-button.ui-icon-bottom { - padding: .4em 1em 1.1em 1em; -} - -.ui-button.ui-icon-notext .ui-icon { - padding: 0; - width: 2.1em; - height: 2.1em; - text-indent: -9999px; - white-space: nowrap; - -} - -input.ui-button.ui-icon-notext .ui-icon { - width: auto; - height: auto; - text-indent: 0; - white-space: normal; - padding: .4em 1em; + margin-left: -8px; } /* workarounds */ diff --git a/themes/base/core.css b/themes/base/core.css index 90fc17cd5ee..36877405059 100644 --- a/themes/base/core.css +++ b/themes/base/core.css @@ -68,17 +68,18 @@ /* Icons ----------------------------------*/ - .ui-icon { - display: block; - text-indent: -99999px; - overflow: hidden; - background-repeat: no-repeat; - left: .5em; - top: .3em; + display: inline-block; + vertical-align: middle; + margin-top: -.25em; + position: relative; } - +.ui-icon-display-block { + left: 50%; + margin-left: -8px; + display: block; +} /* Misc visuals ----------------------------------*/ diff --git a/themes/base/datepicker.css b/themes/base/datepicker.css index a77eab7b2ab..ddb8c17ddf6 100644 --- a/themes/base/datepicker.css +++ b/themes/base/datepicker.css @@ -173,3 +173,14 @@ border-right-width: 0; border-left-width: 1px; } + +/* Icons */ +.ui-datepicker .ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; + left: .5em; + top: .3em; +} + diff --git a/ui/button.js b/ui/button.js index 2db8dad1c87..30bbe861f0b 100644 --- a/ui/button.js +++ b/ui/button.js @@ -127,20 +127,28 @@ $.widget( "ui.button", { }, _updateIcon: function( icon ) { + var placementMethod = + ( this.options.iconPosition === "top" || + this.options.iconPosition === "beginning" ) ? + "prependTo" : + "appendTo", + displayBlock = + ( this.options.iconPosition === "top" || + this.options.iconPosition === "bottom" ); if ( !this.icon ) { this.icon = $( "" ); this._addClass( this.icon, "ui-button-icon", " ui-icon" ); if ( !this.options.showLabel ) { this._addClass( "ui-button-icon-only" ); - } else { - this._addClass( null, "ui-icon-" + this.options.iconPosition ); + } else if ( displayBlock ) { + this._addClass( this.icon, null, "ui-icon-display-block" ); } } else { this._removeClass( this.icon, null, this.options.icon ); } this._addClass( this.icon, null, icon ); - this.icon.appendTo( this.element ); + this.icon[ placementMethod ]( this.element ); return this; }, From 2a00b4eba066027709dc5e1bc7f3f4dcd3fd20b1 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Sat, 7 Feb 2015 18:26:03 -0500 Subject: [PATCH 080/107] Button: Switch to use inline icons --- demos/button/default.html | 4 +- demos/button/icons.html | 10 ++--- tests/unit/button/button_common.js | 1 - tests/unit/button/button_options.js | 66 +++-------------------------- themes/base/button.css | 2 +- ui/button.js | 27 ++++++++---- 6 files changed, 33 insertions(+), 77 deletions(-) diff --git a/demos/button/default.html b/demos/button/default.html index f4fdd672284..b9b780ace6a 100644 --- a/demos/button/default.html +++ b/demos/button/default.html @@ -36,8 +36,8 @@

    CSS Buttons

    Examples of the markup that can be used for buttons: A button element, an input of type submit and an anchor.

    -

    Buttons can be styled via the button widget for by adding the classes yourself to avoid the javascript overhead if you dont need any of the methods provided by the button widget

    p> -

    Here you can see examples of both buttons styled with css only and done using the button widget

    +

    Buttons can be styled via the button widget for by adding the classes yourself to avoid the javascript overhead if you dont need any of the methods provided by the button widget

    +

    Here you can see examples of buttons using the button widget and styled with css only.

    diff --git a/demos/button/icons.html b/demos/button/icons.html index 32eeb12edff..85bde00cb1d 100644 --- a/demos/button/icons.html +++ b/demos/button/icons.html @@ -15,15 +15,15 @@ icon: "ui-icon-gear", showLabel: false }).next().button({ - icon: "ui-icon-triangle-1-w" + icon: "ui-icon-gear" }).next().button({ - icon: "ui-icon-triangle-1-e", + icon: "ui-icon-gear", iconPosition: "end" }).next().button({ - icon: "ui-icon-triangle-1-s", + icon: "ui-icon-gear", iconPosition: "bottom" }).next().button({ - icon: "ui-icon-triangle-1-n", + icon: "ui-icon-gear", iconPosition: "top" }); }); @@ -58,7 +58,7 @@

    CSS

    - +
    diff --git a/tests/unit/button/button_common.js b/tests/unit/button/button_common.js index 4364c163589..39f7fcb364a 100644 --- a/tests/unit/button/button_common.js +++ b/tests/unit/button/button_common.js @@ -1,6 +1,5 @@ TestHelpers.commonWidgetTests( "button", { defaults: { - classes: {}, disabled: null, showLabel: true, label: null, diff --git a/tests/unit/button/button_options.js b/tests/unit/button/button_options.js index 9b3be9b50fc..6536f261094 100644 --- a/tests/unit/button/button_options.js +++ b/tests/unit/button/button_options.js @@ -5,19 +5,21 @@ module( "button: options" ); -test( "disabled, explicit value", function( assert ) { - expect( 7 ); +test( "disabled, explicit value", function() { + expect( 9 ); var element = $( "#button" ).button({ disabled: false }); deepEqual( element.button( "option", "disabled" ), false, "disabled option set to false" ); deepEqual( element.prop( "disabled" ), false, "element is disabled" ); - assert.lacksClasses( element.button( "widget" ), "ui-state-disabled ui-button-disabled" ); + ok( !element.button( "widget" ).hasClass( "ui-state-disabled" ), "element gets ui-state-disabled" ); + ok( !element.button( "widget" ).hasClass( "ui-button-disabled" ), "element gets ui-button-disabled" ); element = $( "#button" ).button({ disabled: true }); + ok( element.button( "widget" ).hasClass( "ui-state-disabled" ), "element gets ui-state-disabled" ); ok( !element.button( "widget" ).attr( "aria-disabled" ), "element does not get aria-disabled" ); - assert.hasClasses( element.button( "widget" ), "ui-button-disabled ui-state-disabled" ); + ok( element.button( "widget" ).hasClass( "ui-button-disabled" ), "element gets ui-button-disabled" ); deepEqual( element.button( "option", "disabled" ), true, "disabled option set to true" ); deepEqual( element.prop( "disabled" ), true, "element is not disabled" ); @@ -31,46 +33,7 @@ test( "disabled, null", function() { strictEqual( $("#button").prop("disabled"), false, "element is disabled"); }); -<<<<<<< HEAD -test( "disabled, ui-state-active is removed unless checkbox or radio", function( assert ) { - expect( 12 ); - var elements = [ - $( "" ), - $( "" ), - $( "" ), - $( "
    " ), - $( "" ), - $( "" ) - ]; - - $.each( elements, function() { - var element = $( this ).first().button(), - buttonElement = element.button( "widget" ), - elementType = element.prop( "nodeName" ).toLowerCase(); - - if ( element.is( "input" ) ) { - elementType += ":" + element.attr( "type" ); - } - - element.trigger( "mousedown" ); - assert.hasClasses( buttonElement, "ui-state-active", - "[" + elementType + "] has ui-state-active class after mousedown." ); - - element.button( "disable" ); - if ( element.is( "[type=checkbox], [type=radio]" ) ) { - assert.hasClasses( buttonElement, "ui-state-active", - "Disabled [" + elementType + "] has ui-state-active class." ); - } else { - assert.lacksClasses( buttonElement, "ui-state-active", - "Disabled [" + elementType + "] does not have ui-state-active class." ); - } - }); -}); - -test("text false without icon", function() { -======= test( "showLabel false without icon", function() { ->>>>>>> Button: Inital commit of button refactor expect( 1 ); $( "#button" ).button({ showLabel: false @@ -135,22 +98,7 @@ test( "icons", function() { }); strictEqual( $( "#button" ).find( "span.ui-icon.iconclass" ).length, 1 ); -<<<<<<< HEAD - $("#button").button("destroy"); -}); - -test( "#5295 - button does not remove hoverstate if disabled" , function( assert ) { - expect( 1 ); - var btn = $("#button").button(); - btn.hover( function() { - btn.button( "disable" ); - }); - btn.trigger( "mouseenter" ); - btn.trigger( "mouseleave" ); - assert.lacksClasses( btn, "ui-state-hover" ); -======= $( "#button" ).button( "destroy" ); ->>>>>>> Button: Inital commit of button refactor }); -})(jQuery); +})(jQuery); \ No newline at end of file diff --git a/themes/base/button.css b/themes/base/button.css index e4e85b7aa0a..068e2e4fd1b 100644 --- a/themes/base/button.css +++ b/themes/base/button.css @@ -9,7 +9,7 @@ * http://api.jqueryui.com/button/#theming */ .ui-button { - padding: .4em; + padding: .4em 1em; display: inline-block; position: relative; line-height: normal; diff --git a/ui/button.js b/ui/button.js index 30bbe861f0b..23cb391e629 100644 --- a/ui/button.js +++ b/ui/button.js @@ -31,8 +31,11 @@ var formResetHandler = function() { var form = $( this ); + + // Wait for the form reset to actually happen before refreshing setTimeout(function() { - // We find .ui-button first then filer by :ui-button because doing a + + // We find .ui-button first then filter by :ui-button because doing a // widget pseudo selectors are very very slow but we need to filter out // css only buttons form.find( ".ui-button" ).filter( ":ui-button" ).button( "refresh" ); @@ -127,16 +130,17 @@ $.widget( "ui.button", { }, _updateIcon: function( icon ) { - var placementMethod = - ( this.options.iconPosition === "top" || - this.options.iconPosition === "beginning" ) ? - "prependTo" : - "appendTo", + var prepend = + ( this.options.iconPosition === "top" || this.options.iconPosition === "beginning" )? + true : + false, displayBlock = ( this.options.iconPosition === "top" || this.options.iconPosition === "bottom" ); if ( !this.icon ) { this.icon = $( "" ); + this.iconSpace = $( " " ); + this._addClass( this.icon, "ui-button-icon", " ui-icon" ); if ( !this.options.showLabel ) { @@ -148,7 +152,10 @@ $.widget( "ui.button", { this._removeClass( this.icon, null, this.options.icon ); } this._addClass( this.icon, null, icon ); - this.icon[ placementMethod ]( this.element ); + this.icon[ prepend ? "prependTo" : "appendTo" ]( this.element ); + if ( !displayBlock ) { + this.icon[ prepend ? "after" : "before" ]( this.iconSpace ); + } return this; }, @@ -157,6 +164,7 @@ $.widget( "ui.button", { if ( this.icon ) { this.icon.remove(); + this.iconSpace.remove(); } if ( !this.hasTitle ) { this.element.removeAttr( "title" ); @@ -169,6 +177,7 @@ $.widget( "ui.button", { this._updateIcon( value ); } else { this.icon.remove(); + this.iconSpace.remove(); this._removeClass( "ui-button-icon", " ui-icon-" + this.options.iconPosition ); } } @@ -194,7 +203,7 @@ $.widget( "ui.button", { // If there us an icon append it else nothing then append the value // this avoids removal of the icon when setting label text - this.element.html( !!this.icon ? "" : this.icon ).append( value ); + this.element.html( !!this.icon ? this.icon : "" ).append( value ); } } this._super( key, value ); @@ -278,7 +287,7 @@ if ( $.uiBackCompat !== false ) { }); $.fn.button = (function( orig ) { return function() { - if ( this.length > 0 && this[ 0 ].tagName === "INPUT" && + if ( this.length && this[ 0 ].tagName === "INPUT" && ( this.attr( "type") === "checkbox" || this.attr( "type" ) === "radio" ) ) { if ( $.ui.checkboxradio ) { if ( arguments.length === 0 ) { From 5f78188cdfe5df98b9130cd5d199f5a884e1587f Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Sat, 7 Feb 2015 18:27:36 -0500 Subject: [PATCH 081/107] Checkboxradio: Use inline icons --- demos/checkboxradio/default.html | 31 +++++------ demos/checkboxradio/index.html | 2 +- demos/checkboxradio/no-icons.html | 52 +++++++++++++++++++ demos/checkboxradio/product-selector.html | 9 ++-- demos/checkboxradio/radiogroup.html | 2 +- .../unit/checkboxradio/checkboxradio_core.js | 2 +- .../checkboxradio/checkboxradio_options.js | 4 +- themes/base/checkboxradio.css | 1 - ui/checkboxradio.js | 15 +++--- 9 files changed, 87 insertions(+), 31 deletions(-) create mode 100644 demos/checkboxradio/no-icons.html diff --git a/demos/checkboxradio/default.html b/demos/checkboxradio/default.html index 0e75bc91573..54e2797e173 100644 --- a/demos/checkboxradio/default.html +++ b/demos/checkboxradio/default.html @@ -19,27 +19,28 @@

    Checkbox and radio button widgets

    Checkbox

    +
    - Filter by rating - - - - - - - - + Rating + + + + + + + +

    Radio Group

    - Filter by location: - - + Location: + + - - + +
    diff --git a/demos/checkboxradio/index.html b/demos/checkboxradio/index.html index ed0c37d4b7b..08e598dbc82 100644 --- a/demos/checkboxradio/index.html +++ b/demos/checkboxradio/index.html @@ -9,7 +9,7 @@ diff --git a/demos/checkboxradio/no-icons.html b/demos/checkboxradio/no-icons.html new file mode 100644 index 00000000000..b54101c660c --- /dev/null +++ b/demos/checkboxradio/no-icons.html @@ -0,0 +1,52 @@ + + + + + jQuery UI Checkboxradio - No Icons + + + + + + + + + +
    +

    Checkbox and radio button widgets

    +

    Checkbox

    +
    + Filter by rating + + + + + + + + +
    +

    Radio Group

    +
    + Filter by location: + + + + + +
    +
    + +
    +

    Examples of the markup that can be used with checkboxs and radio buttons, here showing both without icons.

    +
    + + \ No newline at end of file diff --git a/demos/checkboxradio/product-selector.html b/demos/checkboxradio/product-selector.html index 0f894b7e3f5..101bc00f93f 100644 --- a/demos/checkboxradio/product-selector.html +++ b/demos/checkboxradio/product-selector.html @@ -39,10 +39,11 @@ -
    -

    A Controlgroup featuring various form controls

    -

    Controlgroup

    @@ -85,5 +81,8 @@

    Controlgroup

    +
    +

    A Controlgroup featuring various form controls, with either a horizontal or vertical layout.

    +
    From 1349f285d1e8975619d7da4d097eb78e6a4c6557 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Sat, 7 Feb 2015 18:30:41 -0500 Subject: [PATCH 085/107] Controlgroup: Add to unit test index --- tests/unit/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/index.html b/tests/unit/index.html index fe358cb6c81..625006cf198 100644 --- a/tests/unit/index.html +++ b/tests/unit/index.html @@ -41,6 +41,7 @@

    Widgets

  • Autocomplete
  • Button
  • Checkboxradio
  • +
  • Checkboxradio
  • Datepicker
  • Dialog
  • Menu
  • From fe204ff00503e20a069a596a24d67b2944273b4f Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Sat, 7 Feb 2015 18:31:19 -0500 Subject: [PATCH 086/107] Controlgroup: update to avoid dom traversal in refresh --- ui/controlgroup.js | 71 +++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/ui/controlgroup.js b/ui/controlgroup.js index 827490263b4..e2e727976ca 100644 --- a/ui/controlgroup.js +++ b/ui/controlgroup.js @@ -24,7 +24,7 @@ } }(function( $ ) { -$.widget( "ui.controlgroup", { +return $.widget( "ui.controlgroup", { version: "@VERSION", defaultElement: "
    ", options: { @@ -52,8 +52,8 @@ $.widget( "ui.controlgroup", { _destroy: function() { var that = this; $.each( this.options.items, function( widget, selector ) { - that.element.children( selector ).map(function(){ - return $( this )[ widget ]( "widget" )[ 0 ]; + that.element.children( selector ).map( function() { + return $( this )[ widget ]( "widget" ).removeData( "ui-controlgroup-data" )[ 0 ]; }).removeData( "ui-controlgroup-data" ); }); this._callChildMethod( "destroy" ); @@ -62,6 +62,8 @@ $.widget( "ui.controlgroup", { _callChildMethod: function( method ) { var that = this; + + this.buttons = $(); $.each( this.options.items, function( widget, selector ) { var options = {}; if ( that[ "_" + widget + "_options" ] ) { @@ -69,15 +71,17 @@ $.widget( "ui.controlgroup", { } if ( $.fn[ widget ] && selector ) { that.element - .children( selector )[ widget ]( method ? method: options ) - .each(function(){ - if ( method !== "destroy" ) { - $( this )[ widget ]( "widget" ).data( "ui-controlgroup-data", { - "type": widget, - "element": $( this ) - }); - } - }); + .find( selector )[ widget ]( method ? method : options ) + .each( function() { + if ( method !== "destroy" ) { + var button = + $( this )[ widget ]( "widget" ).data( "ui-controlgroup-data", { + "widgetType": widget, + "element": $( this ) + }); + that.buttons = that.buttons.add( button ); + } + }); } }); }, @@ -85,29 +89,29 @@ $.widget( "ui.controlgroup", { _button_options: function( position ) { var cornerClasses = { "middle": null, - "first": "ui-corner-" + ( ( this.options.direction === "vertical" )? "top" : "left" ), - "last": "ui-corner-" + ( ( this.options.direction === "vertical" )? "bottom" : "right" ) + "first": "ui-corner-" + ( this.options.direction === "vertical" ? "top" : "left" ), + "last": "ui-corner-" + ( this.options.direction === "vertical" ? "bottom" : "right" ) }; return { - classes: { - "ui-button": cornerClasses[ position ] - } - }; + classes: { + "ui-button": cornerClasses[ position ] + } + }; }, _checkboxradio_options: function( position ) { var cornerClasses = { "middle": null, - "first": "ui-corner-" + ( ( this.options.direction === "vertical" )? "top" : "left" ), - "last": "ui-corner-" + ( ( this.options.direction === "vertical" )? "bottom" : "right" ) + "first": "ui-corner-" + ( this.options.direction === "vertical" ? "top" : "left" ), + "last": "ui-corner-" + ( this.options.direction === "vertical" ? "bottom" : "right" ) }; return { - classes: { - "ui-checkboxradio-label": cornerClasses[ position ] - } - }; + classes: { + "ui-checkboxradio-label": cornerClasses[ position ] + } + }; }, _selectmenu_options: function( position ) { @@ -118,15 +122,15 @@ $.widget( "ui.controlgroup", { }, first: { "ui-selectmenu-button-open": - "ui-corner-" + ( ( this.options.direction === "vertical" )? "top": "tl" ), + "ui-corner-" + ( this.options.direction === "vertical" ? "top" : "tl" ), "ui-selectmenu-button-closed": - "ui-corner-" + ( ( this.options.direction === "vertical" )? "top": "left" ) + "ui-corner-" + ( this.options.direction === "vertical" ? "top" : "left" ) }, last: { "ui-selectmenu-button-open": - ( this.options.direction === "vertical" )? null: "ui-corner-tr", + ( this.options.direction === "vertical" )? null : "ui-corner-tr", "ui-selectmenu-button-closed": - "ui-corner-" + ( ( this.options.direction === "vertical" )? "bottom": "right" ) + "ui-corner-" + ( ( this.options.direction === "vertical" )? "bottom" : "right" ) } }; @@ -157,15 +161,18 @@ $.widget( "ui.controlgroup", { this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction ); this._callChildMethod(); - children = this.element.children( ".ui-button" ); + + children = this.buttons; if ( this.options.excludeInvisible ) { children = children.filter( ":visible" ); } if ( children.length ) { - [ "first", "last" ].forEach( function( value ){ + [ "first", "last" ].forEach( function( value ) { var data = children[ value ]().data( "ui-controlgroup-data" ); - data.element[ data.type ]( that[ "_" + data.type + "_options" ]( value ) ); + if ( that[ "_" + data.widgetType + "_options" ] ) { + data.element[ data.widgetType ]( that[ "_" + data.widgetType + "_options" ]( value ) ); + } }); this._callChildMethod( "refresh" ); } @@ -173,6 +180,4 @@ $.widget( "ui.controlgroup", { }); -return $.ui.controlgroup; - })); From 88df484eb7ce203472849f09509f1d3459a32f5a Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Sat, 7 Feb 2015 18:31:53 -0500 Subject: [PATCH 087/107] Checkboxradio: Rename demo based on new default icon value --- demos/checkboxradio/icons.html | 53 ---------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 demos/checkboxradio/icons.html diff --git a/demos/checkboxradio/icons.html b/demos/checkboxradio/icons.html deleted file mode 100644 index 75a33ec6136..00000000000 --- a/demos/checkboxradio/icons.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - jQuery UI Checkboxradio - Icon functionality - - - - - - - - - -
    -

    Checkbox and radio button widgets

    -

    Checkbox

    - -
    - Rating - - - - - - - - -
    -

    Radio Group

    -
    - Location: - - - - - -
    -
    - -
    -

    Examples of the markup that can be used with checkboxs and radio buttons.

    -
    - - From 5f51ed7fe3f43987eb28990b67299c0b8add72e3 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Sun, 8 Feb 2015 07:56:02 -0500 Subject: [PATCH 088/107] Controlgroup: fixup --- demos/controlgroup/splitbutton.html | 18 ++++++++---------- demos/controlgroup/toolbar.html | 4 ++-- themes/base/controlgroup.css | 4 +++- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/demos/controlgroup/splitbutton.html b/demos/controlgroup/splitbutton.html index eeedb02ea06..554f2d18ab2 100644 --- a/demos/controlgroup/splitbutton.html +++ b/demos/controlgroup/splitbutton.html @@ -19,22 +19,17 @@ $( "select" ).selectmenu({ classes: { "ui-selectmenu-button": "ui-button-icon-only" + }, + change: function(){ + $( ".output" ).append( "
  • " + this.value + "
  • " ); } - }).selectmenu( "widget" ).removeClass( "ui-icon-end" ); - $( ".controlgroup" ).controlgroup(); - $( "select" ).on( "selectmenuchange", function(){ - alert( this.value ); }); + $( ".controlgroup" ).controlgroup(); $( "button" ).click(function() { - alert( "Running the last action" ); + $( ".output" ).append( "
  • Running Last Action...
  • " ); }); }); -
    @@ -47,6 +42,9 @@

    Split button

    +
    +

    Output:

    +

      A Controlgroup creating a split button

      diff --git a/demos/controlgroup/toolbar.html b/demos/controlgroup/toolbar.html index 8f1e42bffef..be2949c9810 100644 --- a/demos/controlgroup/toolbar.html +++ b/demos/controlgroup/toolbar.html @@ -43,7 +43,7 @@ contents[ 0 ].execCommand( this.id ); }); $( "#fontsize, #forecolor, #hilitecolor, #backcolor, #fontname" ).on( "change selectmenuchange", function() { - contents[ 0 ].execCommand( this.id ,false, $( this ).val() ); + contents[ 0 ].execCommand( this.id, false, $( this ).val() ); }); $( ".toolbar" ).controlgroup(); $( "#zoom" ).on( "selectmenuchange", function() { @@ -57,7 +57,7 @@ + + +
      + css for new checkbox widget +
      +
      + + + + + + + + +
      +
      + + + + + + + +
      + + From 992a69f964577ff2d2eae32ee9fc9ea68fcd3454 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 11 Feb 2015 11:50:43 -0500 Subject: [PATCH 104/107] Checkboxradio: remove unneeded visual test --- tests/visual/checkboxradio/checkbox.html | 69 ------------------------ 1 file changed, 69 deletions(-) delete mode 100644 tests/visual/checkboxradio/checkbox.html diff --git a/tests/visual/checkboxradio/checkbox.html b/tests/visual/checkboxradio/checkbox.html deleted file mode 100644 index 6e85f8763c8..00000000000 --- a/tests/visual/checkboxradio/checkbox.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - jQuery UI Button - Checkboxes - - - - - - - - - - - -
      - css for new checkbox widget -
      -
      - - - - - - - - -
      -
      - - - - - - - -
      - - From aacfe9922856d45caf0b7e69eaf3cfe663864fa4 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 11 Feb 2015 17:46:01 -0500 Subject: [PATCH 105/107] Dialog: fixup --- tests/unit/dialog/dialog_options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/dialog/dialog_options.js b/tests/unit/dialog/dialog_options.js index 83966060cf7..57d465e47da 100644 --- a/tests/unit/dialog/dialog_options.js +++ b/tests/unit/dialog/dialog_options.js @@ -216,7 +216,7 @@ test("closeText", function() { element.remove(); element = $("
      ").dialog().dialog("option", "closeText", "bar"); - equal(element.dialog("widget").find(".ui-dialog-titlebar-close").text(), "bar", + equal(element.dialog("widget").find(".ui-dialog-titlebar-close").text(), " bar", "closeText via option method"); element.remove(); }); From c76731cf3bfdcb8b1d420197e00c59208d229f92 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 11 Feb 2015 17:46:19 -0500 Subject: [PATCH 106/107] Button: fixup --- ui/button.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/button.js b/ui/button.js index 234054d45d3..9b802969013 100644 --- a/ui/button.js +++ b/ui/button.js @@ -222,7 +222,7 @@ $.widget( "ui.button", { this._super( key, value ); if ( key === "disabled" ) { this._toggleClass( null, "ui-state-disabled", value ); - this.element.element[ 0 ].disabled = value; + this.element[ 0 ].disabled = value; if ( value ) { this.element.blur(); } From 45cba0f18de24194aba4da89d6bd81358b734095 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 11 Feb 2015 17:46:35 -0500 Subject: [PATCH 107/107] Controlgroup: fixup --- ui/controlgroup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/controlgroup.js b/ui/controlgroup.js index 893237cbc0f..ed86aca42a4 100644 --- a/ui/controlgroup.js +++ b/ui/controlgroup.js @@ -169,7 +169,7 @@ return $.widget( "ui.controlgroup", { data.element[ data.widgetType ]( that[ "_" + data.widgetType + "_options" ]( value, - this.options.direction === "vertical" + that.options.direction === "vertical" ) ); }