From e07784ec89d3581890e613a3a97b031454fe2876 Mon Sep 17 00:00:00 2001
From: Alexander Schmitz
Date: Mon, 2 Feb 2015 19:21:44 -0500
Subject: [PATCH 01/36] 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 3e66e2e37d3..d91dedb9bc4 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -229,6 +229,9 @@ grunt.initConfig({
"qunit/qunit.css": "qunit/qunit/qunit.css",
"qunit/LICENSE.txt": "qunit/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 38a9f77ee54..9b6b71b6f36 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 fb4c29a546917c2ef1c8375762f21434a6319a90 Mon Sep 17 00:00:00 2001
From: Alexander Schmitz
Date: Wed, 3 Dec 2014 11:20:20 -0500
Subject: [PATCH 02/36] Widget: Add classes option and
_add/_remove/_toggleClass methods
---
tests/unit/accordion/accordion_common.js | 1 +
.../unit/autocomplete/autocomplete_common.js | 1 +
tests/unit/button/button_common.js | 1 +
tests/unit/dialog/dialog_common.js | 1 +
tests/unit/draggable/draggable_common.js | 1 +
tests/unit/droppable/droppable_common.js | 1 +
tests/unit/menu/menu_common.js | 1 +
tests/unit/progressbar/progressbar_common.js | 1 +
tests/unit/resizable/resizable_common.js | 1 +
tests/unit/selectable/selectable_common.js | 1 +
tests/unit/selectmenu/selectmenu_common.js | 1 +
tests/unit/slider/slider_common.js | 1 +
tests/unit/sortable/sortable_common.js | 1 +
tests/unit/spinner/spinner_common.js | 1 +
tests/unit/tabs/tabs_common.js | 1 +
tests/unit/tooltip/tooltip_common.js | 1 +
tests/unit/widget/widget.html | 2 +
tests/unit/widget/widget_classes.js | 143 ++++++++++++++++++
tests/unit/widget/widget_core.js | 5 +-
ui/widget.js | 121 +++++++++++++--
20 files changed, 272 insertions(+), 15 deletions(-)
create mode 100644 tests/unit/widget/widget_classes.js
diff --git a/tests/unit/accordion/accordion_common.js b/tests/unit/accordion/accordion_common.js
index ef24cf25ec5..70e04e8475b 100644
--- a/tests/unit/accordion/accordion_common.js
+++ b/tests/unit/accordion/accordion_common.js
@@ -2,6 +2,7 @@ TestHelpers.commonWidgetTests( "accordion", {
defaults: {
active: 0,
animate: {},
+ classes: {},
collapsible: false,
disabled: false,
event: "click",
diff --git a/tests/unit/autocomplete/autocomplete_common.js b/tests/unit/autocomplete/autocomplete_common.js
index 63b24d384b9..b82ec1d1c50 100644
--- a/tests/unit/autocomplete/autocomplete_common.js
+++ b/tests/unit/autocomplete/autocomplete_common.js
@@ -2,6 +2,7 @@ TestHelpers.commonWidgetTests( "autocomplete", {
defaults: {
appendTo: null,
autoFocus: false,
+ classes: {},
delay: 300,
disabled: false,
messages: {
diff --git a/tests/unit/button/button_common.js b/tests/unit/button/button_common.js
index ef22d30114f..1564a1beeee 100644
--- a/tests/unit/button/button_common.js
+++ b/tests/unit/button/button_common.js
@@ -1,5 +1,6 @@
TestHelpers.commonWidgetTests( "button", {
defaults: {
+ classes: {},
disabled: null,
icons: {
primary: null,
diff --git a/tests/unit/dialog/dialog_common.js b/tests/unit/dialog/dialog_common.js
index fc10fabaab6..87f7f7d1578 100644
--- a/tests/unit/dialog/dialog_common.js
+++ b/tests/unit/dialog/dialog_common.js
@@ -3,6 +3,7 @@ TestHelpers.commonWidgetTests( "dialog", {
appendTo: "body",
autoOpen: true,
buttons: [],
+ classes: {},
closeOnEscape: true,
closeText: "Close",
disabled: false,
diff --git a/tests/unit/draggable/draggable_common.js b/tests/unit/draggable/draggable_common.js
index 5abd09e4935..00193bdaf4f 100644
--- a/tests/unit/draggable/draggable_common.js
+++ b/tests/unit/draggable/draggable_common.js
@@ -3,6 +3,7 @@ TestHelpers.commonWidgetTests( "draggable", {
appendTo: "parent",
axis: false,
cancel: "input,textarea,button,select,option",
+ classes: {},
connectToSortable: false,
containment: false,
cursor: "auto",
diff --git a/tests/unit/droppable/droppable_common.js b/tests/unit/droppable/droppable_common.js
index c112def3cf4..bd56aa35f9b 100644
--- a/tests/unit/droppable/droppable_common.js
+++ b/tests/unit/droppable/droppable_common.js
@@ -3,6 +3,7 @@ TestHelpers.commonWidgetTests( "droppable", {
accept: "*",
activeClass: false,
addClasses: true,
+ classes: {},
disabled: false,
greedy: false,
hoverClass: false,
diff --git a/tests/unit/menu/menu_common.js b/tests/unit/menu/menu_common.js
index ae0ab988785..942e9e9f954 100644
--- a/tests/unit/menu/menu_common.js
+++ b/tests/unit/menu/menu_common.js
@@ -1,5 +1,6 @@
TestHelpers.commonWidgetTests( "menu", {
defaults: {
+ classes: {},
disabled: false,
icons: {
submenu: "ui-icon-caret-1-e"
diff --git a/tests/unit/progressbar/progressbar_common.js b/tests/unit/progressbar/progressbar_common.js
index 0768576f568..c603b4efd2b 100644
--- a/tests/unit/progressbar/progressbar_common.js
+++ b/tests/unit/progressbar/progressbar_common.js
@@ -1,5 +1,6 @@
TestHelpers.commonWidgetTests( "progressbar", {
defaults: {
+ classes: {},
disabled: false,
max: 100,
value: 0,
diff --git a/tests/unit/resizable/resizable_common.js b/tests/unit/resizable/resizable_common.js
index c261ac5b9c8..a68103101bc 100644
--- a/tests/unit/resizable/resizable_common.js
+++ b/tests/unit/resizable/resizable_common.js
@@ -7,6 +7,7 @@ TestHelpers.commonWidgetTests( "resizable", {
aspectRatio: false,
autoHide: false,
cancel: "input,textarea,button,select,option",
+ classes: {},
containment: false,
delay: 0,
disabled: false,
diff --git a/tests/unit/selectable/selectable_common.js b/tests/unit/selectable/selectable_common.js
index d00a47be593..0f9adf54018 100644
--- a/tests/unit/selectable/selectable_common.js
+++ b/tests/unit/selectable/selectable_common.js
@@ -3,6 +3,7 @@ TestHelpers.commonWidgetTests("selectable", {
appendTo: "body",
autoRefresh: true,
cancel: "input,textarea,button,select,option",
+ classes: {},
delay: 0,
disabled: false,
distance: 0,
diff --git a/tests/unit/selectmenu/selectmenu_common.js b/tests/unit/selectmenu/selectmenu_common.js
index bc245f96266..cb8712e7b5a 100644
--- a/tests/unit/selectmenu/selectmenu_common.js
+++ b/tests/unit/selectmenu/selectmenu_common.js
@@ -1,6 +1,7 @@
TestHelpers.commonWidgetTests( "selectmenu", {
defaults: {
appendTo: null,
+ classes: {},
disabled: null,
icons: {
button: "ui-icon-triangle-1-s"
diff --git a/tests/unit/slider/slider_common.js b/tests/unit/slider/slider_common.js
index 6d7278de6a2..a72071f793d 100644
--- a/tests/unit/slider/slider_common.js
+++ b/tests/unit/slider/slider_common.js
@@ -2,6 +2,7 @@ TestHelpers.commonWidgetTests( "slider", {
defaults: {
animate: false,
cancel: "input,textarea,button,select,option",
+ classes: {},
delay: 0,
disabled: false,
distance: 0,
diff --git a/tests/unit/sortable/sortable_common.js b/tests/unit/sortable/sortable_common.js
index 86850a658c3..6733714a755 100644
--- a/tests/unit/sortable/sortable_common.js
+++ b/tests/unit/sortable/sortable_common.js
@@ -3,6 +3,7 @@ TestHelpers.commonWidgetTests( "sortable", {
appendTo: "parent",
axis: false,
cancel: "input,textarea,button,select,option",
+ classes: {},
connectWith: false,
containment: false,
cursor: "auto",
diff --git a/tests/unit/spinner/spinner_common.js b/tests/unit/spinner/spinner_common.js
index b494e3ca34d..871af7db447 100644
--- a/tests/unit/spinner/spinner_common.js
+++ b/tests/unit/spinner/spinner_common.js
@@ -1,5 +1,6 @@
TestHelpers.commonWidgetTests( "spinner", {
defaults: {
+ classes: {},
culture: null,
disabled: false,
icons: {
diff --git a/tests/unit/tabs/tabs_common.js b/tests/unit/tabs/tabs_common.js
index a589515f806..8f6bbc67bc9 100644
--- a/tests/unit/tabs/tabs_common.js
+++ b/tests/unit/tabs/tabs_common.js
@@ -1,6 +1,7 @@
TestHelpers.commonWidgetTests( "tabs", {
defaults: {
active: null,
+ classes: {},
collapsible: false,
disabled: false,
event: "click",
diff --git a/tests/unit/tooltip/tooltip_common.js b/tests/unit/tooltip/tooltip_common.js
index 2d6ea91eccd..0611d724cec 100644
--- a/tests/unit/tooltip/tooltip_common.js
+++ b/tests/unit/tooltip/tooltip_common.js
@@ -1,5 +1,6 @@
TestHelpers.commonWidgetTests( "tooltip", {
defaults: {
+ classes: {},
content: function() {},
disabled: false,
hide: true,
diff --git a/tests/unit/widget/widget.html b/tests/unit/widget/widget.html
index 2b764abab9e..ac106ea3294 100644
--- a/tests/unit/widget/widget.html
+++ b/tests/unit/widget/widget.html
@@ -9,6 +9,7 @@
+
+
diff --git a/tests/unit/widget/widget_classes.js b/tests/unit/widget/widget_classes.js
new file mode 100644
index 00000000000..0202d26831c
--- /dev/null
+++ b/tests/unit/widget/widget_classes.js
@@ -0,0 +1,143 @@
+(function( $ ) {
+
+module( "widget factory classes", {
+ setup: function() {
+ $.widget( "ui.classesWidget", {
+ options: {
+ classes: {
+ "ui-classes-widget": "ui-theme-widget",
+ "ui-classes-element": "ui-theme-element ui-theme-element-2"
+ }
+ },
+ _create: function() {
+ this.span = $( "" )
+ .appendTo( this.element );
+
+ this.element.wrap( "" );
+
+ this.wrapper = this.element.parent();
+
+ this._addClass( "ui-classes-element", "ui-core-element" )
+ ._addClass( "ui-classes-element-2" )
+ ._addClass( null, "ui-core-element-null" )
+ ._addClass( this.span, null, "ui-core-span-null" )
+ ._addClass( this.span, "ui-classes-span", "ui-core-span" )
+ ._addClass( this.wrapper, "ui-classes-widget" );
+
+ },
+ toggleClasses: function( bool ) {
+ this._toggleClass( "ui-classes-element", "ui-core-element", bool )
+ ._toggleClass( "ui-classes-element-2", null, bool )
+ ._toggleClass( null, "ui-core-element-null", bool )
+ ._toggleClass( this.span, null, "ui-core-span-null", bool )
+ ._toggleClass( this.span, "ui-classes-span", "ui-core-span", bool )
+ ._toggleClass( this.wrapper, "ui-classes-widget", null, bool );
+ },
+ removeClasses: function() {
+ this._removeClass( "ui-classes-element", "ui-core-element" )
+ ._removeClass( "ui-classes-element-2" )
+ ._removeClass( null, "ui-core-element-null" )
+ ._removeClass( this.span, null, "ui-core-span-null" )
+ ._removeClass( this.span, "ui-classes-span", "ui-core-span" )
+ ._removeClass( this.wrapper, "ui-classes-widget" );
+ },
+ _destroy: function() {
+ this.span.remove();
+ this.element.unwrap();
+ }
+ });
+ },
+ teardown: function() {
+ delete $.ui.classesWidget;
+ delete $.fn.classesWidget;
+ }
+});
+
+function elementHasClasses( widget, method, assert ) {
+ var toggle = method === "toggle" ? ( ", true" ) : "";
+
+ assert.hasClasses( widget, "ui-classes-element ui-theme-element ui-theme-element-2",
+ "_" + method + "Class works with ( keys, extra" + toggle + " )" );
+ assert.hasClasses( widget, "ui-classes-element-2",
+ "_" + method + "Class works with ( keys, null" + toggle + " )" );
+ assert.hasClasses( widget, "ui-core-element-null",
+ "_" + method + "Class works with ( null, extra" + toggle + " )" );
+ assert.hasClasses( widget.parent(), "ui-classes-widget ui-theme-widget",
+ "_" + method + "Class works with ( element, null, extra" + toggle + " )" );
+ assert.hasClasses( widget.find( "span" ), "ui-classes-span ui-core-span",
+ "_" + method + "Class works with ( element, keys, extra" + toggle + " )" );
+ assert.hasClasses( widget.find( "span" ), "ui-core-span-null",
+ "_" + method + "Class works with ( element, keys, null" + toggle + " )" );
+}
+function elementLacksClasses( widget, method, assert ) {
+ var toggle = method === "toggle" ? ( ", false" ) : "";
+
+ assert.lacksClasses( widget, "ui-classes-element ui-theme-element ui-theme-element-2",
+ "_" + method + "Class works with ( keys, extra" + toggle + " )" );
+ assert.lacksClasses( widget, "ui-classes-element-2",
+ "_" + method + "Class works with ( keys, null" + toggle + " )" );
+ assert.lacksClasses( widget, "ui-core-element-null",
+ "_" + method + "Class works with ( null, extra" + toggle + " )" );
+ assert.lacksClasses( widget.parent(), "ui-classes-widget ui-theme-widget",
+ "_" + method + "Class works with ( element, null, extra" + toggle + " )" );
+ assert.lacksClasses( widget.find( "span" ), "ui-classes-span ui-core-span",
+ "_" + method + "Class works with ( element, keys, extra" + toggle + " )" );
+ assert.lacksClasses( widget.find( "span" ), "ui-core-span-null",
+ "_" + method + "Class works with ( element, keys, null" + toggle + " )" );
+}
+
+test( ".option() - classes setter", function( assert ) {
+ expect( 11 );
+
+ var testWidget = $.ui.classesWidget();
+
+ elementHasClasses( testWidget.element, "add", assert );
+
+ testWidget.option({
+ classes: {
+ "ui-classes-span": "custom-theme-span",
+ "ui-classes-widget": "ui-theme-widget custom-theme-widget",
+ "ui-classes-element": "ui-theme-element-2"
+ }
+ });
+
+ assert.lacksClasses( testWidget.element, "ui-theme-element",
+ "Removing a class from the value removes the class" );
+
+ testWidget.option( "classes.ui-classes-element", "" );
+ assert.hasClasses( testWidget.element, "ui-classes-element",
+ "Setting to empty value leaves structure class" );
+ assert.lacksClasses( testWidget.element, "ui-theme-element-2",
+ "Setting empty value removes previous value classes" );
+ assert.hasClasses( testWidget.span, "ui-classes-span custom-theme-span",
+ "Adding a class to an empty value works as expected" );
+ assert.hasClasses( testWidget.wrapper, "ui-classes-widget custom-theme-widget",
+ "Appending a class to the current value works as expected" );
+});
+
+test( ".destroy() - class removal", function() {
+ expect( 1 );
+
+ domEqual( "#widget", function() {
+ $( "#widget" ).classesWidget().classesWidget( "destroy" );
+ });
+});
+
+test( "._add/_remove/_toggleClass()", function( assert ) {
+ expect( 24 );
+
+ var widget = $( "#widget" ).classesWidget();
+
+ elementHasClasses( widget, "add", assert );
+
+ widget.classesWidget( "toggleClasses", false );
+ elementLacksClasses( widget, "toggle", assert );
+
+ widget.classesWidget( "toggleClasses", true );
+ elementHasClasses( widget, "toggle", assert );
+
+ widget.classesWidget( "removeClasses" );
+ elementLacksClasses( widget, "remove", assert );
+});
+
+}( jQuery ) );
diff --git a/tests/unit/widget/widget_core.js b/tests/unit/widget/widget_core.js
index 2b88e39ef22..4e5b023490a 100644
--- a/tests/unit/widget/widget_core.js
+++ b/tests/unit/widget/widget_core.js
@@ -227,6 +227,7 @@ test( "merge multiple option arguments", function() {
$.widget( "ui.testWidget", {
_create: function() {
deepEqual( this.options, {
+ classes: {},
create: null,
disabled: false,
option1: "value1",
@@ -281,6 +282,7 @@ test( "._getCreateOptions()", function() {
},
_create: function() {
deepEqual( this.options, {
+ classes: {},
create: null,
disabled: false,
option1: "override1",
@@ -485,10 +487,11 @@ test( ".option() - getter", function() {
options = div.testWidget( "option" );
deepEqual( options, {
+ baz: 5,
+ classes: {},
create: null,
disabled: false,
foo: "bar",
- baz: 5,
qux: [ "quux", "quuux" ]
}, "full options hash returned" );
options.foo = "notbar";
diff --git a/ui/widget.js b/ui/widget.js
index 33e0d156e4d..4999048f6f0 100644
--- a/ui/widget.js
+++ b/ui/widget.js
@@ -250,6 +250,7 @@ $.Widget.prototype = {
widgetEventPrefix: "",
defaultElement: "
",
options: {
+ classes: {},
disabled: false,
// callbacks
@@ -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,13 @@ $.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 +313,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,
@@ -370,21 +373,54 @@ $.Widget.prototype = {
return this;
},
_setOption: function( key, value ) {
+ if ( key === "classes" ) {
+ this._setOptionClasses( 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" );
}
}
return this;
},
+ _setOptionClasses: 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;
+ }
+
+ // We are doing this to create a new jQuery object because the _removeClass() call
+ // on the next line is going to destroy the reference to the current elements being
+ // tracked. We need to save a copy of this collection so that we can add the new classes
+ // below.
+ 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 the value passed in from
+ // _setOption(), this is the new value of the classes option which was passed to
+ // _setOption(). We pass this value directly to _classes().
+ elements.addClass( this._classes({
+ element: elements,
+ keys: classKey,
+ classes: value,
+ add: true
+ }));
+ }
+ },
enable: function() {
return this._setOptions({ disabled: false });
@@ -393,6 +429,63 @@ $.Widget.prototype = {
return this._setOptions({ disabled: true });
},
+ _classes: function( options ) {
+ var full = [],
+ that = this;
+
+ options = $.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 ( options.add ) {
+ current = $( $.unique( current.get().concat( options.element.get() ) ) );
+ } else {
+ current = $( current.not( options.element ).get() );
+ }
+ that.classesElementLookup[ classes[ i ] ] = current;
+ full.push( classes[ i ] );
+ if ( checkOption && options.classes[ classes[ i ] ] ) {
+ full.push( options.classes[ classes[ i ] ] );
+ }
+ }
+ }
+
+ if ( options.keys ) {
+ processClassString( options.keys.match( /\S+/g ) || [], true );
+ }
+ if ( options.extra ) {
+ processClassString( options.extra.match( /\S+/g ) || [] );
+ }
+
+ 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;
@@ -469,10 +562,10 @@ $.Widget.prototype = {
this.hoverable = this.hoverable.add( element );
this._on( element, {
mouseenter: function( event ) {
- $( event.currentTarget ).addClass( "ui-state-hover" );
+ this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
},
mouseleave: function( event ) {
- $( event.currentTarget ).removeClass( "ui-state-hover" );
+ this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
}
});
},
@@ -481,10 +574,10 @@ $.Widget.prototype = {
this.focusable = this.focusable.add( element );
this._on( element, {
focusin: function( event ) {
- $( event.currentTarget ).addClass( "ui-state-focus" );
+ this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
},
focusout: function( event ) {
- $( event.currentTarget ).removeClass( "ui-state-focus" );
+ this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
}
});
},
From a8cfc3050b62c32b26b5fd74609a83d39f681cba Mon Sep 17 00:00:00 2001
From: Alexander Schmitz
Date: Wed, 3 Dec 2014 11:23:19 -0500
Subject: [PATCH 03/36] Accordion: Add classes option
---
tests/unit/accordion/accordion.html | 1 +
tests/unit/accordion/accordion_common.js | 6 +-
tests/unit/accordion/accordion_core.js | 28 ++++--
ui/accordion.js | 115 +++++++++++------------
4 files changed, 81 insertions(+), 69 deletions(-)
diff --git a/tests/unit/accordion/accordion.html b/tests/unit/accordion/accordion.html
index 0a8755fd34b..9ea2d364539 100644
--- a/tests/unit/accordion/accordion.html
+++ b/tests/unit/accordion/accordion.html
@@ -9,6 +9,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+