UPDATE 4.4.0.0
[phpmyadmin.git] / js / jquery / src / jquery-ui / widget.js
blobc2fb788b4725c86cd51d125d27ca91ed87e298c8
1 /*!
2  * jQuery UI Widget 1.11.2
3  * http://jqueryui.com
4  *
5  * Copyright 2014 jQuery Foundation and other contributors
6  * Released under the MIT license.
7  * http://jquery.org/license
8  *
9  * http://api.jqueryui.com/jQuery.widget/
10  */
11 (function( factory ) {
12         if ( typeof define === "function" && define.amd ) {
14                 // AMD. Register as an anonymous module.
15                 define( [ "jquery" ], factory );
16         } else {
18                 // Browser globals
19                 factory( jQuery );
20         }
21 }(function( $ ) {
23 var widget_uuid = 0,
24         widget_slice = Array.prototype.slice;
26 $.cleanData = (function( orig ) {
27         return function( elems ) {
28                 var events, elem, i;
29                 for ( i = 0; (elem = elems[i]) != null; i++ ) {
30                         try {
32                                 // Only trigger remove when necessary to save time
33                                 events = $._data( elem, "events" );
34                                 if ( events && events.remove ) {
35                                         $( elem ).triggerHandler( "remove" );
36                                 }
38                         // http://bugs.jquery.com/ticket/8235
39                         } catch ( e ) {}
40                 }
41                 orig( elems );
42         };
43 })( $.cleanData );
45 $.widget = function( name, base, prototype ) {
46         var fullName, existingConstructor, constructor, basePrototype,
47                 // proxiedPrototype allows the provided prototype to remain unmodified
48                 // so that it can be used as a mixin for multiple widgets (#8876)
49                 proxiedPrototype = {},
50                 namespace = name.split( "." )[ 0 ];
52         name = name.split( "." )[ 1 ];
53         fullName = namespace + "-" + name;
55         if ( !prototype ) {
56                 prototype = base;
57                 base = $.Widget;
58         }
60         // create selector for plugin
61         $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
62                 return !!$.data( elem, fullName );
63         };
65         $[ namespace ] = $[ namespace ] || {};
66         existingConstructor = $[ namespace ][ name ];
67         constructor = $[ namespace ][ name ] = function( options, element ) {
68                 // allow instantiation without "new" keyword
69                 if ( !this._createWidget ) {
70                         return new constructor( options, element );
71                 }
73                 // allow instantiation without initializing for simple inheritance
74                 // must use "new" keyword (the code above always passes args)
75                 if ( arguments.length ) {
76                         this._createWidget( options, element );
77                 }
78         };
79         // extend with the existing constructor to carry over any static properties
80         $.extend( constructor, existingConstructor, {
81                 version: prototype.version,
82                 // copy the object used to create the prototype in case we need to
83                 // redefine the widget later
84                 _proto: $.extend( {}, prototype ),
85                 // track widgets that inherit from this widget in case this widget is
86                 // redefined after a widget inherits from it
87                 _childConstructors: []
88         });
90         basePrototype = new base();
91         // we need to make the options hash a property directly on the new instance
92         // otherwise we'll modify the options hash on the prototype that we're
93         // inheriting from
94         basePrototype.options = $.widget.extend( {}, basePrototype.options );
95         $.each( prototype, function( prop, value ) {
96                 if ( !$.isFunction( value ) ) {
97                         proxiedPrototype[ prop ] = value;
98                         return;
99                 }
100                 proxiedPrototype[ prop ] = (function() {
101                         var _super = function() {
102                                         return base.prototype[ prop ].apply( this, arguments );
103                                 },
104                                 _superApply = function( args ) {
105                                         return base.prototype[ prop ].apply( this, args );
106                                 };
107                         return function() {
108                                 var __super = this._super,
109                                         __superApply = this._superApply,
110                                         returnValue;
112                                 this._super = _super;
113                                 this._superApply = _superApply;
115                                 returnValue = value.apply( this, arguments );
117                                 this._super = __super;
118                                 this._superApply = __superApply;
120                                 return returnValue;
121                         };
122                 })();
123         });
124         constructor.prototype = $.widget.extend( basePrototype, {
125                 // TODO: remove support for widgetEventPrefix
126                 // always use the name + a colon as the prefix, e.g., draggable:start
127                 // don't prefix for widgets that aren't DOM-based
128                 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
129         }, proxiedPrototype, {
130                 constructor: constructor,
131                 namespace: namespace,
132                 widgetName: name,
133                 widgetFullName: fullName
134         });
136         // If this widget is being redefined then we need to find all widgets that
137         // are inheriting from it and redefine all of them so that they inherit from
138         // the new version of this widget. We're essentially trying to replace one
139         // level in the prototype chain.
140         if ( existingConstructor ) {
141                 $.each( existingConstructor._childConstructors, function( i, child ) {
142                         var childPrototype = child.prototype;
144                         // redefine the child widget using the same prototype that was
145                         // originally used, but inherit from the new version of the base
146                         $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
147                 });
148                 // remove the list of existing child constructors from the old constructor
149                 // so the old child constructors can be garbage collected
150                 delete existingConstructor._childConstructors;
151         } else {
152                 base._childConstructors.push( constructor );
153         }
155         $.widget.bridge( name, constructor );
157         return constructor;
160 $.widget.extend = function( target ) {
161         var input = widget_slice.call( arguments, 1 ),
162                 inputIndex = 0,
163                 inputLength = input.length,
164                 key,
165                 value;
166         for ( ; inputIndex < inputLength; inputIndex++ ) {
167                 for ( key in input[ inputIndex ] ) {
168                         value = input[ inputIndex ][ key ];
169                         if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
170                                 // Clone objects
171                                 if ( $.isPlainObject( value ) ) {
172                                         target[ key ] = $.isPlainObject( target[ key ] ) ?
173                                                 $.widget.extend( {}, target[ key ], value ) :
174                                                 // Don't extend strings, arrays, etc. with objects
175                                                 $.widget.extend( {}, value );
176                                 // Copy everything else by reference
177                                 } else {
178                                         target[ key ] = value;
179                                 }
180                         }
181                 }
182         }
183         return target;
186 $.widget.bridge = function( name, object ) {
187         var fullName = object.prototype.widgetFullName || name;
188         $.fn[ name ] = function( options ) {
189                 var isMethodCall = typeof options === "string",
190                         args = widget_slice.call( arguments, 1 ),
191                         returnValue = this;
193                 // allow multiple hashes to be passed on init
194                 options = !isMethodCall && args.length ?
195                         $.widget.extend.apply( null, [ options ].concat(args) ) :
196                         options;
198                 if ( isMethodCall ) {
199                         this.each(function() {
200                                 var methodValue,
201                                         instance = $.data( this, fullName );
202                                 if ( options === "instance" ) {
203                                         returnValue = instance;
204                                         return false;
205                                 }
206                                 if ( !instance ) {
207                                         return $.error( "cannot call methods on " + name + " prior to initialization; " +
208                                                 "attempted to call method '" + options + "'" );
209                                 }
210                                 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
211                                         return $.error( "no such method '" + options + "' for " + name + " widget instance" );
212                                 }
213                                 methodValue = instance[ options ].apply( instance, args );
214                                 if ( methodValue !== instance && methodValue !== undefined ) {
215                                         returnValue = methodValue && methodValue.jquery ?
216                                                 returnValue.pushStack( methodValue.get() ) :
217                                                 methodValue;
218                                         return false;
219                                 }
220                         });
221                 } else {
222                         this.each(function() {
223                                 var instance = $.data( this, fullName );
224                                 if ( instance ) {
225                                         instance.option( options || {} );
226                                         if ( instance._init ) {
227                                                 instance._init();
228                                         }
229                                 } else {
230                                         $.data( this, fullName, new object( options, this ) );
231                                 }
232                         });
233                 }
235                 return returnValue;
236         };
239 $.Widget = function( /* options, element */ ) {};
240 $.Widget._childConstructors = [];
242 $.Widget.prototype = {
243         widgetName: "widget",
244         widgetEventPrefix: "",
245         defaultElement: "<div>",
246         options: {
247                 disabled: false,
249                 // callbacks
250                 create: null
251         },
252         _createWidget: function( options, element ) {
253                 element = $( element || this.defaultElement || this )[ 0 ];
254                 this.element = $( element );
255                 this.uuid = widget_uuid++;
256                 this.eventNamespace = "." + this.widgetName + this.uuid;
258                 this.bindings = $();
259                 this.hoverable = $();
260                 this.focusable = $();
262                 if ( element !== this ) {
263                         $.data( element, this.widgetFullName, this );
264                         this._on( true, this.element, {
265                                 remove: function( event ) {
266                                         if ( event.target === element ) {
267                                                 this.destroy();
268                                         }
269                                 }
270                         });
271                         this.document = $( element.style ?
272                                 // element within the document
273                                 element.ownerDocument :
274                                 // element is window or document
275                                 element.document || element );
276                         this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
277                 }
279                 this.options = $.widget.extend( {},
280                         this.options,
281                         this._getCreateOptions(),
282                         options );
284                 this._create();
285                 this._trigger( "create", null, this._getCreateEventData() );
286                 this._init();
287         },
288         _getCreateOptions: $.noop,
289         _getCreateEventData: $.noop,
290         _create: $.noop,
291         _init: $.noop,
293         destroy: function() {
294                 this._destroy();
295                 // we can probably remove the unbind calls in 2.0
296                 // all event bindings should go through this._on()
297                 this.element
298                         .unbind( this.eventNamespace )
299                         .removeData( this.widgetFullName )
300                         // support: jquery <1.6.3
301                         // http://bugs.jquery.com/ticket/9413
302                         .removeData( $.camelCase( this.widgetFullName ) );
303                 this.widget()
304                         .unbind( this.eventNamespace )
305                         .removeAttr( "aria-disabled" )
306                         .removeClass(
307                                 this.widgetFullName + "-disabled " +
308                                 "ui-state-disabled" );
310                 // clean up events and states
311                 this.bindings.unbind( this.eventNamespace );
312                 this.hoverable.removeClass( "ui-state-hover" );
313                 this.focusable.removeClass( "ui-state-focus" );
314         },
315         _destroy: $.noop,
317         widget: function() {
318                 return this.element;
319         },
321         option: function( key, value ) {
322                 var options = key,
323                         parts,
324                         curOption,
325                         i;
327                 if ( arguments.length === 0 ) {
328                         // don't return a reference to the internal hash
329                         return $.widget.extend( {}, this.options );
330                 }
332                 if ( typeof key === "string" ) {
333                         // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
334                         options = {};
335                         parts = key.split( "." );
336                         key = parts.shift();
337                         if ( parts.length ) {
338                                 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
339                                 for ( i = 0; i < parts.length - 1; i++ ) {
340                                         curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
341                                         curOption = curOption[ parts[ i ] ];
342                                 }
343                                 key = parts.pop();
344                                 if ( arguments.length === 1 ) {
345                                         return curOption[ key ] === undefined ? null : curOption[ key ];
346                                 }
347                                 curOption[ key ] = value;
348                         } else {
349                                 if ( arguments.length === 1 ) {
350                                         return this.options[ key ] === undefined ? null : this.options[ key ];
351                                 }
352                                 options[ key ] = value;
353                         }
354                 }
356                 this._setOptions( options );
358                 return this;
359         },
360         _setOptions: function( options ) {
361                 var key;
363                 for ( key in options ) {
364                         this._setOption( key, options[ key ] );
365                 }
367                 return this;
368         },
369         _setOption: function( key, value ) {
370                 this.options[ key ] = value;
372                 if ( key === "disabled" ) {
373                         this.widget()
374                                 .toggleClass( this.widgetFullName + "-disabled", !!value );
376                         // If the widget is becoming disabled, then nothing is interactive
377                         if ( value ) {
378                                 this.hoverable.removeClass( "ui-state-hover" );
379                                 this.focusable.removeClass( "ui-state-focus" );
380                         }
381                 }
383                 return this;
384         },
386         enable: function() {
387                 return this._setOptions({ disabled: false });
388         },
389         disable: function() {
390                 return this._setOptions({ disabled: true });
391         },
393         _on: function( suppressDisabledCheck, element, handlers ) {
394                 var delegateElement,
395                         instance = this;
397                 // no suppressDisabledCheck flag, shuffle arguments
398                 if ( typeof suppressDisabledCheck !== "boolean" ) {
399                         handlers = element;
400                         element = suppressDisabledCheck;
401                         suppressDisabledCheck = false;
402                 }
404                 // no element argument, shuffle and use this.element
405                 if ( !handlers ) {
406                         handlers = element;
407                         element = this.element;
408                         delegateElement = this.widget();
409                 } else {
410                         element = delegateElement = $( element );
411                         this.bindings = this.bindings.add( element );
412                 }
414                 $.each( handlers, function( event, handler ) {
415                         function handlerProxy() {
416                                 // allow widgets to customize the disabled handling
417                                 // - disabled as an array instead of boolean
418                                 // - disabled class as method for disabling individual parts
419                                 if ( !suppressDisabledCheck &&
420                                                 ( instance.options.disabled === true ||
421                                                         $( this ).hasClass( "ui-state-disabled" ) ) ) {
422                                         return;
423                                 }
424                                 return ( typeof handler === "string" ? instance[ handler ] : handler )
425                                         .apply( instance, arguments );
426                         }
428                         // copy the guid so direct unbinding works
429                         if ( typeof handler !== "string" ) {
430                                 handlerProxy.guid = handler.guid =
431                                         handler.guid || handlerProxy.guid || $.guid++;
432                         }
434                         var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
435                                 eventName = match[1] + instance.eventNamespace,
436                                 selector = match[2];
437                         if ( selector ) {
438                                 delegateElement.delegate( selector, eventName, handlerProxy );
439                         } else {
440                                 element.bind( eventName, handlerProxy );
441                         }
442                 });
443         },
445         _off: function( element, eventName ) {
446                 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
447                         this.eventNamespace;
448                 element.unbind( eventName ).undelegate( eventName );
450                 // Clear the stack to avoid memory leaks (#10056)
451                 this.bindings = $( this.bindings.not( element ).get() );
452                 this.focusable = $( this.focusable.not( element ).get() );
453                 this.hoverable = $( this.hoverable.not( element ).get() );
454         },
456         _delay: function( handler, delay ) {
457                 function handlerProxy() {
458                         return ( typeof handler === "string" ? instance[ handler ] : handler )
459                                 .apply( instance, arguments );
460                 }
461                 var instance = this;
462                 return setTimeout( handlerProxy, delay || 0 );
463         },
465         _hoverable: function( element ) {
466                 this.hoverable = this.hoverable.add( element );
467                 this._on( element, {
468                         mouseenter: function( event ) {
469                                 $( event.currentTarget ).addClass( "ui-state-hover" );
470                         },
471                         mouseleave: function( event ) {
472                                 $( event.currentTarget ).removeClass( "ui-state-hover" );
473                         }
474                 });
475         },
477         _focusable: function( element ) {
478                 this.focusable = this.focusable.add( element );
479                 this._on( element, {
480                         focusin: function( event ) {
481                                 $( event.currentTarget ).addClass( "ui-state-focus" );
482                         },
483                         focusout: function( event ) {
484                                 $( event.currentTarget ).removeClass( "ui-state-focus" );
485                         }
486                 });
487         },
489         _trigger: function( type, event, data ) {
490                 var prop, orig,
491                         callback = this.options[ type ];
493                 data = data || {};
494                 event = $.Event( event );
495                 event.type = ( type === this.widgetEventPrefix ?
496                         type :
497                         this.widgetEventPrefix + type ).toLowerCase();
498                 // the original event may come from any element
499                 // so we need to reset the target on the new event
500                 event.target = this.element[ 0 ];
502                 // copy original event properties over to the new event
503                 orig = event.originalEvent;
504                 if ( orig ) {
505                         for ( prop in orig ) {
506                                 if ( !( prop in event ) ) {
507                                         event[ prop ] = orig[ prop ];
508                                 }
509                         }
510                 }
512                 this.element.trigger( event, data );
513                 return !( $.isFunction( callback ) &&
514                         callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
515                         event.isDefaultPrevented() );
516         }
519 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
520         $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
521                 if ( typeof options === "string" ) {
522                         options = { effect: options };
523                 }
524                 var hasOptions,
525                         effectName = !options ?
526                                 method :
527                                 options === true || typeof options === "number" ?
528                                         defaultEffect :
529                                         options.effect || defaultEffect;
530                 options = options || {};
531                 if ( typeof options === "number" ) {
532                         options = { duration: options };
533                 }
534                 hasOptions = !$.isEmptyObject( options );
535                 options.complete = callback;
536                 if ( options.delay ) {
537                         element.delay( options.delay );
538                 }
539                 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
540                         element[ method ]( options );
541                 } else if ( effectName !== method && element[ effectName ] ) {
542                         element[ effectName ]( options.duration, options.easing, callback );
543                 } else {
544                         element.queue(function( next ) {
545                                 $( this )[ method ]();
546                                 if ( callback ) {
547                                         callback.call( element[ 0 ] );
548                                 }
549                                 next();
550                         });
551                 }
552         };
555 return $.widget;
557 }));