/*! * jQuery UI Widget @VERSION * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Widget */ (function( $, undefined ) { var slice = Array.prototype.slice; var _cleanData = $.cleanData; $.cleanData = function( elems ) { for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { $( elem ).triggerHandler( "remove" ); } _cleanData( elems ); }; $.widget = function( name, base, prototype ) { var namespace = name.split( "." )[ 0 ], fullName; name = name.split( "." )[ 1 ]; fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } // create selector for plugin $.expr[ ":" ][ fullName ] = function( elem ) { return !!$.data( elem, name ); }; $[ namespace ] = $[ namespace ] || {}; // create the constructor using $.extend() so we can carry over any // static properties stored on the existing constructor (if there is one) $[ namespace ][ name ] = $.extend( function( options, element ) { // allow instantiation without "new" keyword if ( !this._createWidget ) { return new $[ namespace ][ name ]( options, element ); } // allow instantiation without initializing for simple inheritance // must use "new" keyword (the code above always passes args) if ( arguments.length ) { this._createWidget( options, element ); } }, $[ namespace ][ name ] ); var basePrototype = new base(); // we need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from basePrototype.options = $.extend( true, {}, basePrototype.options ); $.each( prototype, function( prop, value ) { if ( $.isFunction( value ) ) { prototype[ prop ] = (function() { var _super = function( method ) { return base.prototype[ method ].apply( this, slice.call( arguments, 1 ) ); }; var _superApply = function( method, args ) { return base.prototype[ method ].apply( this, args ); }; return function() { var __super = this._super, __superApply = this._superApply, returnValue; this._super = _super; this._superApply = _superApply; returnValue = value.apply( this, arguments ); this._super = __super; this._superApply = __superApply; return returnValue; }; }()); } }); $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { namespace: namespace, widgetName: name, widgetEventPrefix: name, widgetBaseClass: fullName }, prototype ); $.widget.bridge( name, $[ namespace ][ name ] ); }; $.widget.bridge = function( name, object ) { $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string", args = slice.call( arguments, 1 ), returnValue = this; // allow multiple hashes to be passed on init options = !isMethodCall && args.length ? $.extend.apply( null, [ true, options ].concat(args) ) : options; if ( isMethodCall ) { this.each(function() { var instance = $.data( this, name ); if ( !instance ) { return $.error( "cannot call methods on " + name + " prior to initialization; " + "attempted to call method '" + options + "'" ); } if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { return $.error( "no such method '" + options + "' for " + name + " widget instance" ); } var methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue.jquery ? returnValue.pushStack( methodValue.get() ) : methodValue; return false; } }); } else { this.each(function() { var instance = $.data( this, name ); if ( instance ) { instance.option( options || {} )._init(); } else { object( options, this ); } }); } return returnValue; }; }; $.Widget = function( options, element ) { // allow instantiation without "new" keyword if ( !this._createWidget ) { return new $[ namespace ][ name ]( options, element ); } // allow instantiation without initializing for simple inheritance // must use "new" keyword (the code above always passes args) if ( arguments.length ) { this._createWidget( options, element ); } }; $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", defaultElement: "
", options: { disabled: false, // callbacks create: null }, _createWidget: function( options, element ) { element = $( element || this.defaultElement || this )[ 0 ]; this.element = $( element ); this.options = $.extend( true, {}, this.options, this._getCreateOptions(), options ); this.bindings = $(); this.hoverable = $(); this.focusable = $(); if ( element !== this ) { $.data( element, this.widgetName, this ); this._bind({ remove: "destroy" }); } this._create(); this._trigger( "create" ); this._init(); }, _getCreateOptions: $.noop, _create: $.noop, _init: $.noop, destroy: function() { this._destroy(); // we can probably remove the unbind calls in 2.0 // all event bindings should go through this._bind() this.element .unbind( "." + this.widgetName ) .removeData( this.widgetName ); this.widget() .unbind( "." + this.widgetName ) .removeAttr( "aria-disabled" ) .removeClass( this.widgetBaseClass + "-disabled " + "ui-state-disabled" ); // clean up events and states this.bindings.unbind( "." + this.widgetName ); this.hoverable.removeClass( "ui-state-hover" ); this.focusable.removeClass( "ui-state-focus" ); }, _destroy: $.noop, widget: function() { return this.element; }, option: function( key, value ) { var options = key, parts, curOption, i; if ( arguments.length === 0 ) { // don't return a reference to the internal hash return $.extend( {}, this.options ); } if ( typeof key === "string" ) { if ( value === undefined ) { return this.options[ key ]; } // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } options = {}; parts = key.split( "." ); key = parts.shift(); if ( parts.length ) { curOption = options[ key ] = $.extend( true, {}, this.options[ key ] ); for ( i = 0; i < parts.length - 1; i++ ) { curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; curOption = curOption[ parts[ i ] ]; } curOption[ parts.pop() ] = value; } else { options[ key ] = value; } } this._setOptions( options ); return this; }, _setOptions: function( options ) { var self = this; $.each( options, function( key, value ) { self._setOption( key, value ); }); return this; }, _setOption: function( key, value ) { this.options[ key ] = value; if ( key === "disabled" ) { this.widget() .toggleClass( this.widgetBaseClass + "-disabled ui-state-disabled", !!value ) .attr( "aria-disabled", value ); this.hoverable.removeClass( "ui-state-hover" ); this.focusable.removeClass( "ui-state-focus" ); } return this; }, enable: function() { return this._setOption( "disabled", false ); }, disable: function() { return this._setOption( "disabled", true ); }, _bind: function( element, handlers ) { // no element argument, shuffle and use this.element if ( !handlers ) { handlers = element; element = this.element; } else { // accept selectors, DOM elements element = $( element ); this.bindings = this.bindings.add( element ); } var instance = this; $.each( handlers, function( event, handler ) { element.bind( event + "." + instance.widgetName, function() { // allow widgets to customize the disabled handling // - disabled as an array instead of boolean // - disabled class as method for disabling individual parts if ( instance.options.disabled === true || $( this ).hasClass( "ui-state-disabled" ) ) { return; } return ( typeof handler === "string" ? instance[ handler ] : handler ) .apply( instance, arguments ); }); }); }, _hoverable: function( element ) { this.hoverable = this.hoverable.add( element ); this._bind( element, { mouseenter: function( event ) { $( event.currentTarget ).addClass( "ui-state-hover" ); }, mouseleave: function( event ) { $( event.currentTarget ).removeClass( "ui-state-hover" ); } }); }, _focusable: function( element ) { this.focusable = this.focusable.add( element ); this._bind( element, { focusin: function( event ) { $( event.currentTarget ).addClass( "ui-state-focus" ); }, focusout: function( event ) { $( event.currentTarget ).removeClass( "ui-state-focus" ); } }); }, _trigger: function( type, event, data ) { var callback = this.options[ type ], args; event = $.Event( event ); event.type = ( type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type ).toLowerCase(); data = data || {}; // copy original event properties over to the new event // this would happen if we could call $.event.fix instead of $.Event // but we don't have a way to force an event to be fixed multiple times if ( event.originalEvent ) { for ( var i = $.event.props.length, prop; i; ) { prop = $.event.props[ --i ]; event[ prop ] = event.originalEvent[ prop ]; } } this.element.trigger( event, data ); args = $.isArray( data ) ? [ event ].concat( data ) : [ event, data ]; return !( $.isFunction( callback ) && callback.apply( this.element[0], args ) === false || event.isDefaultPrevented() ); } }; // DEPRECATED if ( $.uiBackCompat !== false ) { $.Widget.prototype._getCreateOptions = function() { return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ]; } } })( jQuery );