diff options
author | Alexander Schmitz <arschmitz@gmail.com> | 2014-12-03 11:20:20 -0500 |
---|---|---|
committer | Alexander Schmitz <arschmitz@gmail.com> | 2015-03-11 16:00:04 -0400 |
commit | c192d4086d9bbaf09d5f870857af30c60a427e22 (patch) | |
tree | 0f302a92a94ddadf79e9fd0fd028b557d0f96b02 /ui | |
parent | 4959c81d80943d097ab29f829488f0551186c1fd (diff) | |
download | jquery-ui-c192d4086d9bbaf09d5f870857af30c60a427e22.tar.gz jquery-ui-c192d4086d9bbaf09d5f870857af30c60a427e22.zip |
Widget: Add classes option and _add/_remove/_toggleClass methods
Fixes #7053
Closes gh-1411
Diffstat (limited to 'ui')
-rw-r--r-- | ui/widget.js | 121 |
1 files changed, 107 insertions, 14 deletions
diff --git a/ui/widget.js b/ui/widget.js index 33e0d156e..4999048f6 100644 --- a/ui/widget.js +++ b/ui/widget.js @@ -250,6 +250,7 @@ $.Widget.prototype = { widgetEventPrefix: "", defaultElement: "<div>", 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" ); } }); }, |