From 6e70f94aa09a86ac9be888791c3d895e3eb20931 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Fri, 7 Nov 2014 23:32:35 -0500 Subject: Build: add box-sizing: false to .csslintrc We can use this now that we dont support IE < 8 --- .csslintrc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.csslintrc b/.csslintrc index 5d9db072c..2138bd580 100644 --- a/.csslintrc +++ b/.csslintrc @@ -1,11 +1,13 @@ { "adjoining-classes": false, "box-model": false, + "box-sizing": false, "compatible-vendor-prefixes": false, "duplicate-background-images": false, "import": false, "important": false, "outline-none": false, "overqualified-elements": false, - "text-indent": false + "text-indent": false, + "box-sizing": false } -- cgit v1.2.3 From 79d312f3f5cb5629d1bd7f9f899b41f304c388ef Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Tue, 21 Apr 2015 12:45:02 -0400 Subject: Tests: Allow widgets to not have a default element --- tests/lib/common.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/lib/common.js b/tests/lib/common.js index c3e898535..d0d72ab8a 100644 --- a/tests/lib/common.js +++ b/tests/lib/common.js @@ -70,7 +70,9 @@ exports.testWidget = function( widget, settings ) { exports.testJshint( "/widgets/" + widget ); testWidgetDefaults( widget, settings.defaults ); testWidgetOverrides( widget ); - testBasicUsage( widget ); + if ( !settings.noDefaultElement ) { + testBasicUsage( widget ); + } test( "version", function() { expect( 1 ); ok( "version" in $.ui[ widget ].prototype, "version property exists" ); -- cgit v1.2.3 From 02033262ee0fb1d9f33c361b3c2ddfa168604854 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 22 Jan 2014 12:02:32 -0500 Subject: Button: Initial commit of button re-factor Move to using element stats rather then js class states remove ui-button-text spans. Removed button set --- demos/button/checkbox.html | 38 --- demos/button/default.html | 28 +- demos/button/icons.html | 78 +++-- demos/button/index.html | 4 - demos/button/radio.html | 33 -- tests/unit/button/button.html | 47 +-- tests/unit/button/common-deprecated.js | 27 ++ tests/unit/button/common.js | 12 +- tests/unit/button/core.js | 220 +----------- tests/unit/button/deprecated.html | 60 ++++ tests/unit/button/deprecated.js | 196 +++++++++++ tests/unit/button/events.js | 30 +- tests/unit/button/methods.js | 51 +-- tests/unit/button/options.js | 222 ++++++------ tests/visual/button/button.html | 28 +- themes/base/accordion.css | 12 - themes/base/button.css | 89 ++--- themes/base/core.css | 15 +- themes/base/datepicker.css | 11 + themes/base/theme.css | 33 +- ui/widgets/button.js | 597 +++++++++++++++------------------ 21 files changed, 849 insertions(+), 982 deletions(-) delete mode 100644 demos/button/checkbox.html delete mode 100644 demos/button/radio.html create mode 100644 tests/unit/button/common-deprecated.js create mode 100644 tests/unit/button/deprecated.html create mode 100644 tests/unit/button/deprecated.js diff --git a/demos/button/checkbox.html b/demos/button/checkbox.html deleted file mode 100644 index 87abbf90f..000000000 --- a/demos/button/checkbox.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - jQuery UI Button - Checkboxes - - - - - - - - - - - - - -
- - - -
- -
-

A checkbox is styled as a toggle button with the button widget. The label element associated with the checkbox is used for the button text.

-

This demo also demonstrates three checkboxes styled as a button set by calling .buttonset() on a common container.

-
- - diff --git a/demos/button/default.html b/demos/button/default.html index 88c666e9a..5418fd8c9 100644 --- a/demos/button/default.html +++ b/demos/button/default.html @@ -11,25 +11,33 @@ +
+

Widget Buttons

+ - + - + 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.

+

Buttons can be styled via the button widget or by adding the classes yourself. This avoids the JavaScript overhead if you don't need any of the methods provided by the button widget.

diff --git a/demos/button/icons.html b/demos/button/icons.html index 0744218b2..f0b0f90fb 100644 --- a/demos/button/icons.html +++ b/demos/button/icons.html @@ -11,38 +11,58 @@ - - - - - - +
+

Widget

+ + + + + + +
+
+

CSS

+ + + + + + +

Some buttons with various combinations of text and icons.

diff --git a/demos/button/index.html b/demos/button/index.html index 5e1b8b7b3..55eacffd8 100644 --- a/demos/button/index.html +++ b/demos/button/index.html @@ -9,11 +9,7 @@ diff --git a/demos/button/radio.html b/demos/button/radio.html deleted file mode 100644 index 86c55a39a..000000000 --- a/demos/button/radio.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - jQuery UI Button - Radios - - - - - - - - - - -
-
- - - -
-
- -
-

A set of three radio buttons transformed into a button set.

-
- - diff --git a/tests/unit/button/button.html b/tests/unit/button/button.html index 7ba400645..09b5a4c23 100644 --- a/tests/unit/button/button.html +++ b/tests/unit/button/button.html @@ -6,54 +6,23 @@ - +
+
+
-
- -
- - - -
-
- - - -
- -
- - - -
-
-
-
- - - -
+
-
-
- - - -
-
- - - -
- - +
+ + Anchor Button +
diff --git a/tests/unit/button/common-deprecated.js b/tests/unit/button/common-deprecated.js new file mode 100644 index 000000000..1441d3a8a --- /dev/null +++ b/tests/unit/button/common-deprecated.js @@ -0,0 +1,27 @@ +define( [ + "lib/common", + "ui/button" +], function( common ) { + +common.testWidget( "button", { + defaults: { + classes: { + "ui-button": "ui-corner-all" + }, + disabled: null, + icon: null, + iconPosition: "beginning", + icons: { + primary: null, + secondary: null + }, + label: null, + showLabel: true, + text: true, + + // Callbacks + create: null + } +} ); + +} ); diff --git a/tests/unit/button/common.js b/tests/unit/button/common.js index 4ef136fac..91ce1cff9 100644 --- a/tests/unit/button/common.js +++ b/tests/unit/button/common.js @@ -5,14 +5,14 @@ define( [ common.testWidget( "button", { defaults: { - classes: {}, - disabled: null, - icons: { - primary: null, - secondary: null + classes: { + "ui-button": "ui-corner-all" }, + disabled: null, + icon: null, + iconPosition: "beginning", label: null, - text: true, + showLabel: true, // Callbacks create: null diff --git a/tests/unit/button/core.js b/tests/unit/button/core.js index f4e5d35a7..a7c164a33 100644 --- a/tests/unit/button/core.js +++ b/tests/unit/button/core.js @@ -3,227 +3,19 @@ define( [ "ui/widgets/button" ], 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" ); - } ); -} ); - -test( "radio groups", function( assert ) { - expect( 12 ); - - function assertClasses( noForm, form1, form2 ) { - assert.hasClasses( $( "#radio0 .ui-button" + noForm ), "ui-state-active" ); - assert.hasClasses( $( "#radio1 .ui-button" + form1 ), "ui-state-active" ); - assert.hasClasses( $( "#radio2 .ui-button" + form2 ), "ui-state-active" ); - } - - $( "input[type=radio]" ).button(); - assertClasses( ":eq(0)", ":eq(1)", ":eq(2)" ); - - // Click outside of forms - $( "#radio0 .ui-button:eq(1)" ).trigger( "click" ); - assertClasses( ":eq(1)", ":eq(1)", ":eq(2)" ); - - // Click in first form - $( "#radio1 .ui-button:eq(0)" ).trigger( "click" ); - assertClasses( ":eq(1)", ":eq(0)", ":eq(2)" ); - - // Click in second form - $( "#radio2 .ui-button:eq(0)" ).trigger( "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() { +asyncTest( "Disabled button loses focus", function() { expect( 2 ); - var input = $( "#submit" ); - deepEqual( input.children().length, 0 ); - input.button(); - 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().on( "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(); - - // If a button has been removed, refresh should not be called on it when - // its corresponding form is reset. - button.remove(); + var element = $( "#button" ).button(); + element.focus(); 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.trigger( "focus" ); - setTimeout( function() { - assert.hasClasses( label, "ui-state-focus" ); - start(); - } ); -} ); - -test( "#7534 - Button label selector works for ids with \":\"", function( assert ) { - expect( 1 ); - var group = $( "" ); - group.find( "input" ).button(); - assert.hasClasses( group.find( "label" ), "ui-button", "Found an id with a :" ); -} ); + equal( element[ 0 ], $.ui.safeActiveElement( document ), "Button is focused" ); -asyncTest( "#9169 - Disabled button maintains ui-state-focus", function( assert ) { - expect( 2 ); - var element = $( "#button1" ).button(); - element[ 0 ].focus(); - setTimeout( function() { - assert.hasClasses( element, "ui-state-focus" ); element.button( "disable" ); - assert.lacksClasses( element, "ui-state-focus", - "button does not have ui-state-focus when disabled" ); + notEqual( element[ 0 ], $.ui.safeActiveElement( document ), "Button has had focus removed" ); start(); } ); } ); diff --git a/tests/unit/button/deprecated.html b/tests/unit/button/deprecated.html new file mode 100644 index 000000000..788d2eeeb --- /dev/null +++ b/tests/unit/button/deprecated.html @@ -0,0 +1,60 @@ + + + + + jQuery UI Button Deprecated Test Suite + + + + + + + +
+
+ +
+ +
+ + + +
+
+ + + +
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+ + + + +
+ + +Anchor Button + +
+ + diff --git a/tests/unit/button/deprecated.js b/tests/unit/button/deprecated.js new file mode 100644 index 000000000..bb023ab4f --- /dev/null +++ b/tests/unit/button/deprecated.js @@ -0,0 +1,196 @@ +define( [ + "jquery", + "ui/button" +], function( $ ) { + +module( "Button (deprecated): core" ); + +test( "Calling button on a checkbox input calls checkboxradio widget", function() { + var checkbox = $( "#checkbox01" ); + + expect( 2 ); + checkbox.button(); + + ok( !!checkbox.checkboxradio( "instance" ), + "Calling button on a checkbox creates checkboxradio instance" ); + ok( !checkbox.checkboxradio( "option", "icon" ), + "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(); + + ok( controlgroup.is( ":ui-controlgroup" ), "Calling buttonset creates controlgroup instance" ); +} ); + +module( "Button (deprecated): methods" ); + +test( "destroy", function( assert ) { + expect( 1 ); + assert.domEqual( "#checkbox02", function() { + $( "#checkbox02" ).button().button( "destroy" ); + } ); +} ); + +test( "refresh: Ensure disabled state is preserved correctly.", function() { + expect( 5 ); + var element = null; + + element = $( "#checkbox02" ); + element.button( { disabled: true } ).button( "refresh" ); + ok( element.button( "option", "disabled" ), "Checkboxes should remain disabled after refresh" ); + ok( element.prop( "disabled" ), "Input remains 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." ); + +} ); + +module( "button (deprecated): options" ); + +test( "Setting items option on buttonset 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( $( "#radio02" ).button( "option", "disabled" ), true, + "disabled option set to true" ); + deepEqual( true, $( "#radio02" ).prop( "disabled" ), "element is not disabled" ); +} ); + +test( "text / 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 true 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 / 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" ); +} ); + +} ); diff --git a/tests/unit/button/events.js b/tests/unit/button/events.js index 15a285046..0bec5a7d2 100644 --- a/tests/unit/button/events.js +++ b/tests/unit/button/events.js @@ -3,34 +3,18 @@ define( [ "ui/widgets/button" ], function( $ ) { -module( "button: events" ); +module( "Button: events" ); -test( "buttonset works with single-quote named elements (#7505)", function() { - expect( 1 ); - $( "#radio3" ).buttonset(); - $( "#radio33" ).on( "click", function() { - ok( true, "button clicks work with single-quote named elements" ); - } ).trigger( "click" ); -} ); - -asyncTest( "when button loses focus, ensure active state is removed (#8559)", function( assert ) { +asyncTest( "Anchor recieves click event when spacebar is pressed", function() { expect( 1 ); + var element = $( "#anchor-button" ).button(); - var element = $( "#button" ).button(); - - element.one( "keypress", function() { - element.one( "blur", function() { - assert.lacksClasses( element, "ui-state-active", "button loses active state appropriately" ); - start(); - } ).trigger( "blur" ); + element.on( "click", function() { + ok( true, "click occcured as a result of spacebar" ); + start(); } ); - element.trigger( "focus" ); - setTimeout( function() { - element - .simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ) - .simulate( "keypress", { keyCode: $.ui.keyCode.ENTER } ); - } ); + element.trigger( $.Event( "keyup", { keyCode: $.ui.keyCode.SPACE } ) ); } ); } ); diff --git a/tests/unit/button/methods.js b/tests/unit/button/methods.js index 0bafd90f9..09a91bbc0 100644 --- a/tests/unit/button/methods.js +++ b/tests/unit/button/methods.js @@ -3,7 +3,7 @@ define( [ "ui/widgets/button" ], function( $ ) { -module( "button: methods" ); +module( "Button: methods" ); test( "destroy", function( assert ) { expect( 1 ); @@ -13,61 +13,22 @@ test( "destroy", function( assert ) { } ); test( "refresh: Ensure disabled state is preserved correctly.", function() { - expect( 8 ); + expect( 3 ); var element = $( "" ); element.button( { disabled: true } ).button( "refresh" ); - ok( element.button( "option", "disabled" ), "Anchor button should remain disabled after refresh" ); //See #8237 - - element = $( "
" ); - element.button( { disabled: true } ).button( "refresh" ); - ok( element.button( "option", "disabled" ), "
buttons should remain disabled after refresh" ); + ok( element.button( "option", "disabled" ), + "Anchor button should remain disabled after refresh" ); element = $( "" ); 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 " ), - $( "" ), - $( "
" ), - $( "" ), - $( "" ) - ]; - - $.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( "showLabel, false, without icon", function( assert ) { + expect( 4 ); -test( "text false without icon", function() { - expect( 1 ); - $( "#button" ).button( { - text: false + var button = $( "#button" ).button( { + showLabel: false } ); - ok( $( "#button" ).is( ".ui-button-text-only:not(.ui-button-icon-only)" ) ); - $( "#button" ).button( "destroy" ); + assert.lacksClasses( button, "ui-button-icon-only" ); + strictEqual( button.button( "option", "showLabel" ), true, + "showLabel false only allowed if icon true" ); + + button.button( "option", "showLabel", false ); + assert.lacksClasses( button, "ui-button-icon-only" ); + strictEqual( button.button( "option", "showLabel" ), true, + "showLabel false only allowed if icon true" ); } ); -test( "text false with icon", function() { +test( "showLabel, false, with icon", function( assert ) { expect( 1 ); - $( "#button" ).button( { - text: false, - icons: { - primary: "iconclass" - } + var button = $( "#button" ).button( { + showLabel: false, + icon: "iconclass" } ); - ok( $( "#button" ).is( ".ui-button-icon-only:not(.ui-button-text):has(span.ui-icon.iconclass)" ) ); - - $( "#button" ).button( "destroy" ); + assert.hasClasses( button, "ui-button ui-corner-all ui-widget ui-button-icon-only" ); } ); test( "label, default", function() { expect( 2 ); - $( "#button" ).button(); - deepEqual( $( "#button" ).text(), "Label" ); - deepEqual( $( "#button" ).button( "option", "label" ), "Label" ); + var button = $( "#button" ).button(); - $( "#button" ).button( "destroy" ); + deepEqual( button.text(), "Label" ); + deepEqual( button.button( "option", "label" ), "Label" ); } ); -test( "label", function() { +test( "label, explicit value", function() { expect( 2 ); - $( "#button" ).button( { + var button = $( "#button" ).button( { label: "xxx" } ); - deepEqual( $( "#button" ).text(), "xxx" ); - deepEqual( $( "#button" ).button( "option", "label" ), "xxx" ); - $( "#button" ).button( "destroy" ); + deepEqual( button.text(), "xxx" ); + deepEqual( button.button( "option", "label" ), "xxx" ); } ); -test( "label default with input type submit", function() { +test( "label, default, with input type submit", function() { expect( 2 ); - deepEqual( $( "#submit" ).button().val(), "Label" ); - deepEqual( $( "#submit" ).button( "option", "label" ), "Label" ); + var button = $( "#submit" ).button(); + + deepEqual( button.val(), "Label" ); + deepEqual( button.button( "option", "label" ), "Label" ); } ); -test( "label with input type submit", function() { +test( "label, explicit value, with input type submit", function() { expect( 2 ); - var label = $( "#submit" ).button( { + var button = $( "#submit" ).button( { label: "xxx" - } ).val(); - deepEqual( label, "xxx" ); - deepEqual( $( "#submit" ).button( "option", "label" ), "xxx" ); + } ); + + deepEqual( button.val(), "xxx" ); + deepEqual( button.button( "option", "label" ), "xxx" ); } ); -test( "icons", function() { - expect( 1 ); - $( "#button" ).button( { - text: false, - icons: { - primary: "iconclass", - secondary: "iconclass2" - } - } ); - ok( $( "#button" ).is( ":has(span.ui-icon.ui-button-icon-primary.iconclass):has(span.ui-icon.ui-button-icon-secondary.iconclass2)" ) ); +test( "icon", function( assert ) { + expect( 4 ); + var button = $( "#button" ).button( { + showLabel: false, + icon: "iconclass" + } ), + icon = button.find( ".ui-icon" ); + + assert.hasClasses( icon, "iconclass" ); + equal( icon.length, 1, "button with icon option set has icon" ); + + button.button( "option", "icon", false ); + equal( button.find( ".ui-icon" ).length, 0, "setting icon to false removes the icon" ); + + button.button( "option", "icon", "iconclass" ); + ok( button.find( ".ui-icon" ).length, "setting icon to a value adds the icon" ); - $( "#button" ).button( "destroy" ); } ); -test( "#5295 - button does not remove hoverstate if disabled", function( assert ) { - expect( 1 ); - var btn = $( "#button" ).button(); - btn.on( "hover", function() { - btn.button( "disable" ); - } ); - btn.trigger( "mouseenter" ); - btn.trigger( "mouseleave" ); - assert.lacksClasses( btn, "ui-state-hover" ); +test( "icon position", function( assert ) { + expect( 22 ); + + var button = $( "#button" ).button( { + icon: "ui-icon-gear" + } ), + icon = button.find( ".ui-icon" ), + space = button.find( ".ui-button-icon-space" ); + + equal( icon.length, 1, "button with icon option set has icon" ); + equal( button.button( "option", "iconPosition" ), "beginning", + "Button has iconPosition beginning by default" ); + equal( button.contents()[ 0 ], icon[ 0 ], "icon is prepended when position is begining" ); + equal( icon.next()[ 0 ], space[ 0 ], "icon is followed by a space when position is begining" ); + equal( space.text(), " ", + "ui-button-icon-space contains a breaking space iconPosition:beginning" ); + assert.lacksClasses( icon, "ui-widget-icon-block" ); + + button.button( "option", "iconPosition", "end" ); + icon = button.find( ".ui-icon" ); + space = button.find( ".ui-button-icon-space" ); + equal( icon.length, 1, "Changing position to end does not re-create or duplicate icon" ); + equal( button.button( "option", "iconPosition" ), "end", "Button has iconPosition end" ); + equal( button.contents().last()[ 0 ], icon[ 0 ], "icon is appended when position is end" ); + equal( icon.prev()[ 0 ], space[ 0 ], "icon is preceeded by a space when position is end" ); + equal( space.text(), " ", + "ui-button-icon-space contains a breaking space iconPosition:beginning" ); + assert.lacksClasses( icon, "ui-widget-icon-block" ); + + button.button( "option", "iconPosition", "top" ); + icon = button.find( ".ui-icon" ); + equal( icon.length, 1, "Changing position to top does not re-create or duplicate icon" ); + equal( button.button( "option", "iconPosition" ), "top", "Button has iconPosition top" ); + equal( button.contents()[ 0 ], icon[ 0 ], "icon is prepended when position is top" ); + ok( !button.find( "ui-button-icon-space" ).length, + "Button should not have an iconSpace with position: top" ); + assert.hasClasses( icon, "ui-widget-icon-block" ); + + button.button( "option", "iconPosition", "bottom" ); + icon = button.find( ".ui-icon" ); + equal( icon.length, 1, "Changing position to bottom does not re-create or duplicate icon" ); + equal( button.button( "option", "iconPosition" ), "bottom", "Button has iconPosition top" ); + equal( button.contents().last()[ 0 ], icon[ 0 ], "icon is prepended when position is bottom" ); + ok( !button.find( "ui-button-icon-space" ).length, + "Button should not have an iconSpace with position: bottom" ); + assert.hasClasses( icon, "ui-widget-icon-block" ); + } ); } ); diff --git a/tests/visual/button/button.html b/tests/visual/button/button.html index 1d82cf665..bb80d8a85 100644 --- a/tests/visual/button/button.html +++ b/tests/visual/button/button.html @@ -10,17 +10,13 @@ $( this ).children() .eq( 0 ) .button({ - text: false, - icons: { - primary: "ui-icon-help" - } + showLabel: false, + icon: "ui-icon-help" }) .end() .eq( 1 ) .button({ - icons: { - primary: "ui-icon-help" - }, + icon: "ui-icon-help", disabled: true }) .end() @@ -61,24 +57,6 @@
-
- - - - - - -
- -
- - - - - - -
-
anchor anchor diff --git a/themes/base/accordion.css b/themes/base/accordion.css index edf368eca..baffce488 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 17dea198f..fcbcda7bb 100644 --- a/themes/base/button.css +++ b/themes/base/button.css @@ -9,16 +9,23 @@ * 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; 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; + + /* Support: IE <= 11 */ + overflow: visible; } + .ui-button, .ui-button:link, .ui-button:visited, @@ -26,87 +33,31 @@ .ui-button:active { text-decoration: none; } + /* to make room for the icon, a width needs to be set here */ .ui-button-icon-only { - width: 2.2em; -} -/* 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; + width: 2em; + box-sizing: border-box; + text-indent: -9999px; + white-space: nowrap; } -/* button text element */ -.ui-button .ui-button-text { - display: block; - line-height: normal; -} -.ui-button-text-only .ui-button-text { - padding: .4em 1em; -} -.ui-button-icon-only .ui-button-text, -.ui-button-icons-only .ui-button-text { - padding: 0; - text-indent: -9999999px; -} -.ui-button-text-icon-primary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 1em .4em 2.1em; -} -.ui-button-text-icon-secondary .ui-button-text, -.ui-button-text-icons .ui-button-text { - padding: .4em 2.1em .4em 1em; -} -.ui-button-text-icons .ui-button-text { - padding-left: 2.1em; - padding-right: 2.1em; -} -/* no icon support for input elements, provide padding by default */ -input.ui-button { - padding: .4em 1em; +/* no icon support for input elements */ +input.ui-button.ui-button-icon-only { + text-indent: 0; } /* 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 { position: absolute; top: 50%; - margin-top: -8px; -} -.ui-button-icon-only .ui-icon { left: 50%; + margin-top: -8px; margin-left: -8px; } -.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-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; -} - -/* button sets */ -.ui-buttonset { - margin-right: 7px; -} -.ui-buttonset .ui-button { - margin-left: 0; - margin-right: -.3em; -} /* workarounds */ -/* reset extra padding in Firefox, see h5bp.com/l */ +/* Support: FireFox >= 4 */ input.ui-button::-moz-focus-inner, button.ui-button::-moz-focus-inner { border: 0; diff --git a/themes/base/core.css b/themes/base/core.css index 4a39cd395..2f7521282 100644 --- a/themes/base/core.css +++ b/themes/base/core.css @@ -68,15 +68,18 @@ /* Icons ----------------------------------*/ - -/* states and images */ .ui-icon { - display: block; - text-indent: -99999px; - overflow: hidden; - background-repeat: no-repeat; + display: inline-block; + vertical-align: middle; + margin-top: -.25em; + position: relative; } +.ui-widget-icon-block { + left: 50%; + margin-left: -8px; + display: block; +} /* Misc visuals ----------------------------------*/ diff --git a/themes/base/datepicker.css b/themes/base/datepicker.css index a77eab7b2..ddb8c17dd 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/themes/base/theme.css b/themes/base/theme.css index 0e0561dc1..eddbc8a0b 100644 --- a/themes/base/theme.css +++ b/themes/base/theme.css @@ -53,7 +53,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}*/; @@ -61,7 +64,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; } @@ -70,7 +77,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}*/; @@ -83,13 +92,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}*/; @@ -171,14 +184,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/widgets/button.js b/ui/widgets/button.js index 94fc75331..34a2afa40 100644 --- a/ui/widgets/button.js +++ b/ui/widgets/button.js @@ -22,10 +22,13 @@ // AMD. Register as an anonymous module. define( [ "jquery", - "../data", + + // These are only for backcompat + // TODO: Remove after 1.12 + "./controlgroup", + "./checkboxradio", + "../keycode", - "../labels", - "../version", "../widget" ], factory ); } else { @@ -35,391 +38,347 @@ } }( 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", - 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; - }; - $.widget( "ui.button", { version: "@VERSION", defaultElement: " +
+ +
+
+ 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 000000000..58e2f7eda --- /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 000000000..5d4c7b3ce --- /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 000000000..f90fb3040 --- /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/demos/index.html b/demos/index.html index f37874a44..4b4d04e06 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 new file mode 100644 index 000000000..92db788c5 --- /dev/null +++ b/tests/unit/checkboxradio/checkboxradio.html @@ -0,0 +1,69 @@ + + + + + jQuery UI Checkboxradio Test Suite + + + + + + + +
    +
    + +
    + + + +
    +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + + diff --git a/tests/unit/checkboxradio/common.js b/tests/unit/checkboxradio/common.js new file mode 100644 index 000000000..6a739435f --- /dev/null +++ b/tests/unit/checkboxradio/common.js @@ -0,0 +1,22 @@ +define( [ + "lib/common", + "ui/checkboxradio" +], function( common ) { + +common.testWidget( "checkboxradio", { + noDefaultElement: true, + defaults: { + disabled: null, + label: null, + icon: true, + classes: { + "ui-checkboxradio-label": "ui-corner-all", + "ui-checkboxradio-icon": "ui-corner-all" + }, + + // Callbacks + create: null + } +}); + +} ); diff --git a/tests/unit/checkboxradio/core.js b/tests/unit/checkboxradio/core.js new file mode 100644 index 000000000..e70ca58c1 --- /dev/null +++ b/tests/unit/checkboxradio/core.js @@ -0,0 +1,102 @@ +define( [ + "jquery", + "ui/checkboxradio" +], function( $ ) { + +module( "Checkboxradio: core" ); +test( "Checkbox - Initial class structure", function( assert ) { + expect( 2 ); + var input = $("#check"), + label = $("label[for=check]"); + + input.checkboxradio(); + assert.hasClasses( input, "ui-helper-hidden-accessible ui-checkboxradio" ); + assert.hasClasses( label, "ui-button ui-widget ui-checkboxradio-label ui-corner-all" ); +}); + +test( "Radios - Initial class structure", function( assert ) { + expect( 6 ); + var inputs = $( "#radio0 input" ), + labels = $( "#radio0 label" ); + + inputs.checkboxradio(); + inputs.each( function() { + assert.hasClasses( this, "ui-helper-hidden-accessible" ); + }); + labels.each( function() { + assert.hasClasses( this, "ui-button" ); + }); +}); + +asyncTest( "Ensure checked after single click on checkbox label button", function( assert ) { + expect( 2 ); + + $( "#check2" ).checkboxradio().change( function() { + var label = $( this ).checkboxradio( "widget" ); + ok( this.checked, "checked ok" ); + + assert.hasClasses( label, "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" ).checkboxradio( "widget" ).simulate( "click" ); + start(); + }); +}); + +test( "Checkbox creation requires a label, and finds it in all cases", function( assert ) { + expect( 7 ); + var groups = [ + "", + "", + "", + "", + "", + "", + "" + ]; + + $.each( groups, function( index, markup ) { + var group = $( markup ); + + group.find( "input[type=checkbox]" ).checkboxradio(); + assert.hasClasses( group.find( "label" ), "ui-button" ); + } ); +}); + +test( "Calling checkboxradio on an unsupported element throws an error", function( assert ) { + expect( 2 ); + var error = new Error( "Can't create checkboxradio on element.nodeName=div and element.type=undefined" ); + assert.raises( + function() { + $( "
    " ).checkboxradio(); + }, + error, + "Proper error thrown" + ); + error = new Error( "Can't create checkboxradio on element.nodeName=input and element.type=button" ); + assert.raises( + function() { + $( "" ).checkboxradio(); + }, + error, + "Proper error thrown" + ); +}); +test( "Calling checkboxradio on an input with no label throws an error", function( assert ) { + expect( 1 ); + var error = new Error( "No label found for checkboxradio widget" ); + assert.raises( + function() { + $( "" ).checkboxradio(); + }, + error, + "Proper error thrown" + ); +}); + +} ); diff --git a/tests/unit/checkboxradio/events.js b/tests/unit/checkboxradio/events.js new file mode 100644 index 000000000..e5909a386 --- /dev/null +++ b/tests/unit/checkboxradio/events.js @@ -0,0 +1,113 @@ +define( [ + "jquery", + "ui/checkboxradio" +], function( $ ) { + +module( "Checkboxradio: events" ); + +asyncTest( "form reset / click", function( assert ) { + expect( 35 ); + + var radios = [ + $( "#radio11" ).checkboxradio(), + $( "#radio12" ).checkboxradio(), + $( "#radio13" ).checkboxradio() + ], + widgets = [ + radios[ 0 ].checkboxradio( "widget" ), + radios[ 1 ].checkboxradio( "widget" ), + radios[ 2 ].checkboxradio( "widget" ) + ], + form1 = $( "#form1" ), + form2 = $( "#form2" ); + + // Checkes that only the specified radio is checked in the group + function assertChecked( checked ) { + $.each( widgets, function( index ) { + var method = index === checked ? "hasClasses" : "lacksClasses"; + + assert[ method ]( widgets[ index ], "ui-checkboxradio-checked ui-state-active" ); + } ); + } + + // Checks the form count on each form + function assertFormCount( count ) { + equal( form1.data( "uiCheckboxradioCount" ), count, "Form1 has a count of " + count ); + equal( form2.data( "uiCheckboxradioCount" ), 3, "Form2 has a count of 3" ); + } + + // Run the tests + function testForms( current, start ) { + assertChecked( 2 ); + + if ( !start && current !== 0 ) { + radios[ current - 1 ].checkboxradio( "destroy" ); + } + + assertFormCount( 3 - current ); + + radios[ current ].prop( "checked", true ); + radios[ current ].trigger( "change" ); + assertChecked( current ); + + form1.trigger( "reset" ); + } + + // Recoursivly run the tests in a setTimeout with call back for the resets + function iterate( i ) { + setTimeout( function() { + if ( i < 3 ) { + testForms( i ); + iterate( i + 1 ); + return; + } + radios[ 2 ].checkboxradio( "destroy" ); + assertChecked( false ); + start(); + } ); + } + + $( "#form2 input" ).checkboxradio(); + + // Check the starting state then kick everything off + testForms( 0, true ); + iterate( 0 ); + +} ); + +asyncTest( + "Resetting a checkbox's form should refresh the visual state of the checkbox", + function( assert ) { + expect( 2 ); + var form = $( "
    " + + "" + + "
    " ), + checkbox = form.find( "input[type=checkbox]" ).checkboxradio(), + widget = checkbox.checkboxradio( "widget" ); + + checkbox.prop( "checked", false ).checkboxradio( "refresh" ); + assert.lacksClasses( widget, "ui-state-active" ); + + form.get( 0 ).reset(); + + setTimeout(function() { + assert.hasClasses( widget, "ui-state-active" ); + start(); + }, 1 ); + } +); + +asyncTest( "Checkbox shows focus when using keyboard navigation", function( assert ) { + expect( 2 ); + var check = $( "#check" ).checkboxradio(), + label = $( "label[for='check']" ); + assert.lacksClasses( label, "ui-state-focus" ); + check.focus(); + setTimeout(function() { + assert.hasClasses( label, "ui-state-focus" ); + start(); + } ); + } +); + +} ); diff --git a/tests/unit/checkboxradio/methods.js b/tests/unit/checkboxradio/methods.js new file mode 100644 index 000000000..f189c9eea --- /dev/null +++ b/tests/unit/checkboxradio/methods.js @@ -0,0 +1,97 @@ +define( [ + "jquery", + "ui/checkboxradio" +], function( $ ) { + +module( "Checkboxradio: methods" ); + +$.each( [ "checkbox", "radio" ], function( index, value ) { + test( value + ": refresh", function( assert ) { + var widget, icon, + checkbox = value === "checkbox", + input = $( "#" + value + "-method-refresh" ); + + expect( checkbox ? 11 : 8 ); + + input.checkboxradio(); + + widget = input.checkboxradio( "widget" ); + icon = widget.find( ".ui-icon" ); + strictEqual( icon.length, 1, + "There is initally one icon" ); + + icon.remove(); + input.checkboxradio( "refresh" ); + icon = widget.find( ".ui-icon" ); + strictEqual( icon.length, 1, + "Icon is recreated on refresh if absent" ); + assert.hasClasses( icon, "ui-icon-blank" ); + if ( checkbox ) { + assert.lacksClasses( icon, "ui-icon-check" ); + } + assert.lacksClasses( widget, "ui-checkboxradio-checked" ); + + input.prop( "checked", true ); + input.checkboxradio( "refresh" ); + if ( checkbox ) { + assert.hasClasses( icon, "ui-icon-check" ); + } + assert[ !checkbox ? "hasClasses" : "lacksClasses" ]( icon, "ui-icon-blank" ); + assert.hasClasses( widget, "ui-checkboxradio-checked" ); + + input.prop( "checked", false ); + input.checkboxradio( "refresh" ); + assert.hasClasses( icon, "ui-icon-blank" ); + if ( checkbox ) { + assert.lacksClasses( icon, "ui-icon-check" ); + } + assert.lacksClasses( widget, "ui-checkboxradio-checked" ); + }); + + test( value + ": destroy", function( assert ){ + expect( 1 ); + assert.domEqual( "#" + value + "-method-destroy", function() { + $( "#" + value + "-method-destroy" ).checkboxradio().checkboxradio( "destroy" ); + }); + }); + + test( value + ": disable / enable", function( assert ) { + expect( 4 ); + var input = $( "#" + value + "-method-disable" ), + widget = input.checkboxradio().checkboxradio( "widget" ); + + input.checkboxradio( "disable" ); + assert.hasClasses( widget, "ui-state-disabled" ); + strictEqual( input.is( ":disabled" ), true, + value + " is disabled when disable is called" ); + + input.checkboxradio( "enable" ); + assert.lacksClasses( widget, "ui-state-disabled" ); + strictEqual( input.is( ":disabled" ), false, + value + " has disabled prop removed when enable is called" ); + }); + + test( value + ": widget returns the label", function(){ + var input = $( "#" + value + "-method-refresh" ), + label = $( "#" + value + "-method-refresh-label" ); + + expect( 1 ); + + input.checkboxradio(); + strictEqual( input.checkboxradio( "widget" )[ 0 ], label[ 0 ], + "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()[ 0 ], element[ 0 ], "Input preserved" ); +}); + +} ); diff --git a/tests/unit/checkboxradio/options.js b/tests/unit/checkboxradio/options.js new file mode 100644 index 000000000..11bd072ca --- /dev/null +++ b/tests/unit/checkboxradio/options.js @@ -0,0 +1,189 @@ +define( [ + "jquery", + "ui/checkboxradio" +], function( $ ) { + +module( "Checkboxradio: options" ); + +function assertDisabled( checkbox, assert ) { + assert.hasClasses( checkbox.checkboxradio( "widget" ), "ui-state-disabled", + "label gets ui-state-disabled" ); + strictEqual( checkbox.is( ":disabled" ), true, + "checkbox is disabled" ); +} + +function assertEnabled( checkbox, assert ) { + assert.lacksClasses( checkbox.checkboxradio( "widget" ), "ui-state-disabled", + "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" ); +} + +test( "disabled", function( assert ) { + var checkbox = $( "#checkbox-option-disabled" ); + expect( 6 ); + checkbox.checkboxradio({ + disabled: true + }); + + assertDisabled( checkbox, assert ); + + checkbox.checkboxradio( "option", "disabled", false ); + assertEnabled( checkbox, assert ); + + checkbox.checkboxradio( "option", "disabled", true ); + assertDisabled( checkbox, assert ); +}); +test( "disabled - prop true on init", function( assert ) { + expect( 2 ); + var checkbox = $( "#checkbox-option-disabled" ); + + checkbox.prop( "disabled", true ); + checkbox.checkboxradio(); + + assertDisabled( checkbox, assert ); +}); +test( "disabled - explicit null value, checks the DOM", function( assert ) { + expect( 2 ); + var checkbox = $( "#checkbox-option-disabled" ); + + checkbox.prop( "disabled", true ); + checkbox.checkboxradio({ + disabled: null + }); + assertDisabled( checkbox, assert ); +}); + +function assertNoIcon( checkbox ) { + strictEqual( checkbox.checkboxradio( "widget" ).find( "span.ui-icon" ).length, 0, + "Label does not contain an icon" ); +} +function assertIcon( checkbox, icon, assert ) { + var iconElement = checkbox.checkboxradio( "widget" ).find( ".ui-icon" ); + + icon = icon || "blank"; + strictEqual( iconElement.length, 1, + "Label contains icon" ); + assert.hasClasses( iconElement, "ui-checkboxradio-icon ui-corner-all ui-icon " + + "ui-icon-background ui-icon-" + icon, + "Icon has proper classes" ); +} +test( "icon - false on init", function() { + var checkbox = $( "#checkbox-option-icon" ); + + expect( 1 ); + + checkbox.checkboxradio({ icon: false }); + assertNoIcon( checkbox ); +}); + +test( "icon - default unchecked", function( assert ) { + var checkbox = $( "#checkbox-option-icon" ); + + expect( 2 ); + + checkbox.checkboxradio(); + assertIcon( checkbox, false, assert ); +}); +test( "icon", function( assert ){ + var checkbox = $( "#checkbox-option-icon" ); + + expect( 8 ); + + checkbox.prop( "checked", true ); + + checkbox.checkboxradio(); + assertIcon( checkbox, "check", assert ); + + checkbox.checkboxradio( "option", "icon", false ); + assertNoIcon( checkbox ); + + checkbox.checkboxradio( "option", "icon", true ); + assertIcon( checkbox, "check", assert ); + + checkbox.checkboxradio( "option", "icon", false ); + assertNoIcon( checkbox ); + + checkbox.prop( "checked", false ).checkboxradio( "refresh" ); + checkbox.checkboxradio( "option", "icon", true ); + assertIcon( checkbox, false, assert ); + +}); + +test( "label - default", function() { + var checkbox = $( "#checkbox-option-label" ), + widget; + + expect( 2 ); + + 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" ); +}); +test( "label - explicit value", function() { + expect( 5 ); + var checkbox = $( "#checkbox-option-label" ).checkboxradio({ + label: "foo" + }), + widget = checkbox.checkboxradio( "widget" ), + icon = widget.find( ".ui-icon" ), + iconSpace = widget.find( ".ui-checkboxradio-icon-space" ); + + 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" ); + strictEqual( icon.length, 1, + "Icon is preserved when label is set on init when wrapped in label" ); + strictEqual( iconSpace.length, 1, + "Icon space is preserved when label is set on init when wrapped in label" ); + strictEqual( $( "#checkbox-option-label" ).length, 1, + "Element is preserved when label is set on init when wrapped in label" ); +}); + +test( "label - explicit null value", function() { + var checkbox = $( "#checkbox-option-label" ), + widget; + + expect( 2 ); + + // We are testing the default here because the default null is a special value which means to check + // the DOM, so we need to make sure this happens correctly checking the options should never return + // null. It should always be true or false + checkbox.checkboxradio({ + label: null + }); + widget = checkbox.checkboxradio( "widget" ); + strictEqual( checkbox.checkboxradio( "option", "label" ), + "checkbox label", "When null is passed on create text from dom is used for option" ); + strictEqual( widget.text(), + " checkbox label", "When null is passed on create text from dom is used in dom" ); + +}); + +test( "label", function() { + var checkbox = $( "#checkbox-option-label" ), + widget; + + expect( 4 ); + + checkbox.checkboxradio(); + widget = checkbox.checkboxradio( "widget" ); + 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" ); + +}); + +} ); diff --git a/tests/unit/controlgroup/controlgroup_core.js b/tests/unit/controlgroup/controlgroup_core.js new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unit/index.html b/tests/unit/index.html index 418cfd34c..fe358cb6c 100644 --- a/tests/unit/index.html +++ b/tests/unit/index.html @@ -40,6 +40,7 @@
  • Accordion
  • Autocomplete
  • Button
  • +
  • Checkboxradio
  • Datepicker
  • Dialog
  • Menu
  • diff --git a/tests/visual/checkboxradio/checkboxradio.html b/tests/visual/checkboxradio/checkboxradio.html new file mode 100644 index 000000000..634e8df81 --- /dev/null +++ b/tests/visual/checkboxradio/checkboxradio.html @@ -0,0 +1,65 @@ + + + + + jQuery UI - Checkboxes + + + + + + + + + + +

    + Easy way to toggle through various combinations of options and states to make sure non lead to + a broken appearence. +

    +
    + + + + + + + + +
    +
    + + + + + + + +
    + + diff --git a/tests/visual/index.html b/tests/visual/index.html index 98753c827..39168c9f4 100644 --- a/tests/visual/index.html +++ b/tests/visual/index.html @@ -31,6 +31,11 @@
  • Performance
  • +

    Checkboxradio

    + +

    Dialog

    • Animations
    • diff --git a/themes/base/base.css b/themes/base/base.css index 3ed02661f..7194eba27 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 000000000..063ed5b5c --- /dev/null +++ b/themes/base/checkboxradio.css @@ -0,0 +1,33 @@ +/*! + * 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-checkboxradio-label .ui-icon-background { + border-radius: .12em; + border: none; +} +.ui-checkboxradio-radio-label .ui-icon-background { + width: 16px; + height: 16px; + border-radius: 1em; + overflow: visible; + border: none; +} +.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon, +.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon { + background-image: none; + width: 8px; + height: 8px; + border-width: 4px; + border-style: solid; +} +.ui-checkboxradio-disabled { + pointer-events: none; +} diff --git a/themes/base/theme.css b/themes/base/theme.css index eddbc8a0b..7553d4c58 100644 --- a/themes/base/theme.css +++ b/themes/base/theme.css @@ -102,12 +102,18 @@ 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, +.ui-state-active .ui-icon-background { + border: #003eff/*{borderColorActive}*/; + background-color: #ffffff/*{bgColorActive}*/; +} .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { @@ -184,7 +190,6 @@ a.ui-button:active, .ui-widget-header .ui-icon { background-image: url("images/ui-icons_444444_256x240.png")/*{iconsHeader}*/; } -.ui-state-default .ui-icon, .ui-button .ui-icon { background-image: url("images/ui-icons_777777_256x240.png")/*{iconsDefault}*/; } @@ -198,7 +203,8 @@ a.ui-button:active, .ui-button:active .ui-icon { background-image: url("images/ui-icons_ffffff_256x240.png")/*{iconsActive}*/; } -.ui-state-highlight .ui-icon { +.ui-state-highlight .ui-icon, +.ui-button .ui-state-highlight.ui-icon { background-image: url("images/ui-icons_777620_256x240.png")/*{iconsHighlight}*/; } .ui-state-error .ui-icon, diff --git a/ui/checkboxradio.js b/ui/checkboxradio.js new file mode 100644 index 000000000..84f69afaa --- /dev/null +++ b/ui/checkboxradio.js @@ -0,0 +1,289 @@ +/*! + * 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( $ ) { + +// Remove and replace with reset handler extension +var formResetHandler = function() { + var form = $( this ); + + // Wait for the form reset to actually happen before refreshing + setTimeout( function() { + + // We dont filter for css only versions since css only is not supported + form.find( ".ui-checkboxradio" ).checkboxradio( "refresh" ); + } ); + }; + +$.widget( "ui.checkboxradio", { + version: "@VERSION", + options: { + disabled: null, + label: null, + icon: true, + classes: { + "ui-checkboxradio-label": "ui-corner-all", + "ui-checkboxradio-icon": "ui-corner-all" + } + }, + + _getCreateOptions: function() { + var disabled, labels, + that = this, + options = this._super() || {}; + + // We read the type here, because it makes more sense to throw a element type error first, + // rather then the error for lack of a label. Often if its the wrong type, it + // won't have a label (e.g. calling on a div, btn, etc) + this._readType(); + + labels = this.element.labels(); + + // Todo: For now we will use the last label we need to check about the best + // way to handle multiple labels with some accessability experts + this.label = $( labels[ labels.length - 1 ] ); + if ( !this.label.length ) { + $.error( "No label found for checkboxradio widget" ); + } + + this.originalLabel = ""; + + // We need to get the label text but this may also need to make sure it does not contain the + // input itself. + this.label.contents().not( this.element ).each( function() { + + // The label contents could be text html or a mix we concat each element to get a string + // representation of the label without the input as part of it. + that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML; + } ); + + // Set the label option if we found label text + if ( this.originalLabel ) { + options.label = this.originalLabel; + } + + disabled = this.element[ 0 ].disabled; + if ( disabled != null ) { + options.disabled = disabled; + } + return options; + }, + + _create: function() { + var formCount, + checked = this.element[ 0 ].checked, + form = this.element.form(); + this.formParent = !!form.length ? form : $( "body" ); + + formCount = this.formParent.data( "uiCheckboxradioCount" ) || 0; + + // 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 + if ( formCount === 0 ) { + this.formParent.on( "reset." + this.widgetFullName, formResetHandler ); + } + + this.formParent.data( "uiCheckboxradioCount", formCount + 1 ); + + if ( this.options.disabled == null ) { + this.options.disabled = this.element[ 0 ].disabled || false; + } + + this._setOption( "disabled", this.options.disabled ); + this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" ); + this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); + + if ( this.type === "radio" ) { + this._addClass( this.label, "ui-checkboxradio-radio-label" ); + } + + if ( this.options.label && this.options.label !== this.originalLabel ) { + this._updateLabel(); + } else if ( this.originalLabel ) { + this.options.label = this.originalLabel; + } + + this._enhance(); + + if ( checked ) { + this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" ); + this._addClass( this.icon, null, "ui-state-hover" ); + } + + this._on( { + "change": "_toggleClasses", + "focus": function() { + this._addClass( this.label, null, "ui-state-focus ui-visual-focus" ); + }, + "blur": function() { + this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" ); + } + } ); + }, + + _readType: function() { + var nodeName = this.element[ 0 ].nodeName.toLowerCase(); + this.type = this.element[ 0 ].type; + if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) { + $.error( "Can't create checkboxradio on element.nodeName=" + nodeName + + " and element.type=" + this.type ); + } + }, + + // Support jQuery Mobile enhanced option + _enhance: function() { + this._updateIcon( this.element[ 0 ].checked ); + }, + + widget: function() { + return this.label; + }, + + _getRadioGroup: function() { + var name = this.element[ 0 ].name, + that = this, + radios = $( [] ); + + if ( name ) { + name = $.ui.escapeSelector( name ); + radios = this.formParent.find( "[name='" + $.ui.escapeSelector( name ) + "']" ).filter( function() { + var form = $( this ).form(); + return ( form.length ? form : $( "body" ) )[ 0 ] === that.formParent[ 0 ]; + } ); + } + return radios.not( this.element ); + }, + + _toggleClasses: function() { + var checked = this.element[ 0 ].checked; + this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); + + if ( this.options.icon && this.type === "checkbox" ) { + + // We add ui-state-highlight to change the icon color + this._toggleClass( this.icon, null, "ui-icon-check ui-state-highlight", checked ) + ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); + } + if ( this.type === "radio" ) { + this._getRadioGroup() + .each( function() { + var instance = $( this ).checkboxradio( "instance" ); + + if ( instance ) { + instance._removeClass( instance.label, + "ui-checkboxradio-checked", "ui-state-active" ); + } + } ); + } + }, + + _destroy: function() { + var formCount = this.formParent.data( "uiCheckboxradioCount" ) - 1; + + this.formParent.data( "uiCheckboxradioCount", formCount ); + + if ( formCount === 0 ) { + this.formParent.off( "reset." + this.widgetFullName, formResetHandler ); + } + + if ( this.icon ) { + this.icon.remove(); + this.iconSpace.remove(); + } + }, + + _setOption: function( key, value ) { + + // We don't alow the value to be set to nothing + if ( key === "label" && !value ) { + return; + } + + this._super( key, value ); + + if ( key === "disabled" ) { + this._toggleClass( this.label, null, "ui-state-disabled", value ); + this.element[ 0 ].disabled = value; + + // Don't refresh if disabled + return; + } + this.refresh(); + }, + + _updateIcon: function( checked ) { + var toAdd = "ui-icon ui-icon-background "; + + if ( this.options.icon ) { + if ( !this.icon ) { + this.icon = $( "" ); + this.iconSpace = $( " " ); + this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" ); + } + + if ( this.type === "checkbox" ) { + toAdd += checked ? "ui-icon-check" : "ui-icon-blank"; + this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" ); + } else { + toAdd += "ui-icon-blank"; + } + this._addClass( this.icon, "ui-checkboxradio-icon", toAdd ); + if ( !checked ) { + this._removeClass( this.icon, null, "ui-icon-check" ); + } + this.icon.prependTo( this.label ).after( this.iconSpace ); + } else if ( this.icon !== undefined ) { + this.icon.remove(); + this.iconSpace.remove(); + delete this.icon; + } + }, + + _updateLabel: function() { + + // Remove the contents of the label ( minus the icon, icon space, and input ) + this.label.contents().not( this.element.add( this.icon ).add( this.iconSpace ) ).remove(); + this.label.append( this.options.label ); + }, + + refresh: function() { + var checked = this.element[ 0 ].checked, + isDisabled = this.element[ 0 ].disabled; + + this._updateIcon( checked ); + this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); + if ( this.options.label !== null ) { + this._updateLabel(); + } + + if ( isDisabled !== this.options.disabled ) { + this._setOptions( { "disabled": isDisabled } ); + } + } + +} ); + +return $.ui.checkboxradio; + +} ) ); -- cgit v1.2.3 From 6e2bbcaa5e19bb933d8024ff5d6fcff34f91e034 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Wed, 23 Jul 2014 22:11:03 -0400 Subject: Theme: Add visual focus outline for checkbox and radio buttons This adds a focus outline matching that roughly from chrome osx --- themes/base/theme.css | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/themes/base/theme.css b/themes/base/theme.css index 7553d4c58..0722cf754 100644 --- a/themes/base/theme.css +++ b/themes/base/theme.css @@ -55,6 +55,9 @@ .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, + +/* We use html here because we need a greater specificity to make sure disabled +works properly when clicked or hovered */ html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active { border: 1px solid #c5c5c5/*{borderColorDefault}*/; @@ -98,6 +101,11 @@ a.ui-button:focus { color: #2b2b2b/*{fcHover}*/; text-decoration: none; } + +/* This cant be configured with themeroller because its new may end up added later */ +.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, @@ -196,7 +204,8 @@ a.ui-button:active, .ui-state-hover .ui-icon, .ui-state-focus .ui-icon, .ui-button:hover .ui-icon, -.ui-button:focus .ui-icon { +.ui-button:focus .ui-icon, +.ui-state-default .ui-icon { background-image: url("images/ui-icons_555555_256x240.png")/*{iconsHover}*/; } .ui-state-active .ui-icon, -- cgit v1.2.3 From 40a9d1dfdb6a341904ae7bcd4600b0ef201d14df Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Fri, 22 Aug 2014 23:39:35 -0400 Subject: Controlgroup: Inital commit of new widget This widget replaces the buttonset widget --- demos/button/icons.html | 1 + demos/controlgroup/default.html | 23 ++- demos/controlgroup/index.html | 2 +- demos/controlgroup/splitbutton.html | 23 ++- demos/controlgroup/toolbar.html | 140 +++++++++--------- demos/index.html | 1 + demos/tooltip/video-player.html | 8 +- tests/unit/controlgroup/common.js | 26 ++++ tests/unit/controlgroup/controlgroup.html | 39 +++++ tests/unit/controlgroup/controlgroup_core.js | 77 ++++++++++ tests/unit/controlgroup/core.js | 69 +++++++++ tests/unit/controlgroup/methods.js | 150 ++++++++++++++++++++ tests/unit/controlgroup/options.js | 108 ++++++++++++++ tests/unit/index.html | 1 + themes/base/base.css | 1 + themes/base/button.css | 17 +++ themes/base/controlgroup.css | 30 ++++ ui/.DS_Store | Bin 0 -> 10244 bytes ui/controlgroup.js | 205 +++++++++++++++++++++++++++ 19 files changed, 820 insertions(+), 101 deletions(-) create mode 100644 tests/unit/controlgroup/common.js create mode 100644 tests/unit/controlgroup/controlgroup.html create mode 100644 tests/unit/controlgroup/core.js create mode 100644 tests/unit/controlgroup/methods.js create mode 100644 tests/unit/controlgroup/options.js create mode 100644 themes/base/controlgroup.css create mode 100644 ui/.DS_Store create mode 100644 ui/controlgroup.js diff --git a/demos/button/icons.html b/demos/button/icons.html index f0b0f90fb..a8deca9cd 100644 --- a/demos/button/icons.html +++ b/demos/button/icons.html @@ -41,6 +41,7 @@ +

    CSS

    diff --git a/demos/controlgroup/default.html b/demos/controlgroup/default.html index 9e4bcdd80..0fc963537 100644 --- a/demos/controlgroup/default.html +++ b/demos/controlgroup/default.html @@ -16,18 +16,15 @@ -
    -

    A Controlgroup featuring various form controls

    -

    Controlgroup

    @@ -64,7 +58,7 @@
    Rental Car -
    +
    +
    +

    Output:

    +
      -

      A Controlgroup creating a split button

      +

      A controlgroup creating a split button, by combining a button and a selectmenu. We adjust the classes option on the selectmenu to show only the icon

      diff --git a/demos/controlgroup/toolbar.html b/demos/controlgroup/toolbar.html index f90fb3040..fb3172418 100644 --- a/demos/controlgroup/toolbar.html +++ b/demos/controlgroup/toolbar.html @@ -19,10 +19,11 @@ var iframe = $( "