resources/lib/blueimp-file-upload/js/vendor/jquery.ui.widget.js   F
last analyzed

Complexity

Total Complexity 147
Complexity/F 2.67

Size

Lines of Code 743
Function Count 55

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
nc 0
dl 0
loc 743
rs 2.1818
c 0
b 0
f 0
wmc 147
mnd 5
bc 125
fnc 55
bpm 2.2727
cpm 2.6727
noi 5

1 Function

Rating   Name   Duplication   Size   Complexity  
B jquery.ui.widget.js ➔ ?!? 0 733 1

How to fix   Complexity   

Complexity

Complex classes like resources/lib/blueimp-file-upload/js/vendor/jquery.ui.widget.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*! jQuery UI - v1.12.1 - 2018-02-10
2
 * http://jqueryui.com
3
 * Includes: widget.js
4
 * Copyright jQuery Foundation and other contributors; Licensed MIT */
5
6
(function( factory ) {
7
  if ( typeof define === "function" && define.amd ) {
8
9
    // AMD. Register as an anonymous module.
10
    define([ "jquery" ], factory );
11
  } else {
12
13
    // Browser globals
14
    factory( jQuery );
15
  }
16
}(function( $ ) {
17
18
  $.ui = $.ui || {};
19
20
  var version = $.ui.version = "1.12.1";
21
22
23
  /*!
24
   * jQuery UI Widget 1.12.1
25
   * http://jqueryui.com
26
   *
27
   * Copyright jQuery Foundation and other contributors
28
   * Released under the MIT license.
29
   * http://jquery.org/license
30
   */
31
32
  //>>label: Widget
33
  //>>group: Core
34
  //>>description: Provides a factory for creating stateful widgets with a common API.
35
  //>>docs: http://api.jqueryui.com/jQuery.widget/
36
  //>>demos: http://jqueryui.com/widget/
37
38
39
40
  var widgetUuid = 0;
41
  var widgetSlice = Array.prototype.slice;
42
43
  $.cleanData = ( function( orig ) {
44
    return function( elems ) {
45
      var events, elem, i;
46
      for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
47
        try {
48
49
          // Only trigger remove when necessary to save time
50
          events = $._data( elem, "events" );
51
          if ( events && events.remove ) {
52
            $( elem ).triggerHandler( "remove" );
53
          }
54
55
          // Http://bugs.jquery.com/ticket/8235
56
        } catch ( e ) {}
57
      }
58
      orig( elems );
59
    };
60
  } )( $.cleanData );
61
62
  $.widget = function( name, base, prototype ) {
63
    var existingConstructor, constructor, basePrototype;
64
65
    // ProxiedPrototype allows the provided prototype to remain unmodified
66
    // so that it can be used as a mixin for multiple widgets (#8876)
67
    var proxiedPrototype = {};
68
69
    var namespace = name.split( "." )[ 0 ];
70
    name = name.split( "." )[ 1 ];
71
    var fullName = namespace + "-" + name;
72
73
    if ( !prototype ) {
74
      prototype = base;
75
      base = $.Widget;
76
    }
77
78
    if ( $.isArray( prototype ) ) {
79
      prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
80
    }
81
82
    // Create selector for plugin
83
    $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
84
      return !!$.data( elem, fullName );
85
    };
86
87
    $[ namespace ] = $[ namespace ] || {};
88
    existingConstructor = $[ namespace ][ name ];
89
    constructor = $[ namespace ][ name ] = function( options, element ) {
90
91
      // Allow instantiation without "new" keyword
92
      if ( !this._createWidget ) {
93
        return new constructor( options, element );
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like constructor should be capitalized.
Loading history...
94
      }
95
96
      // Allow instantiation without initializing for simple inheritance
97
      // must use "new" keyword (the code above always passes args)
98
      if ( arguments.length ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if arguments.length is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
99
        this._createWidget( options, element );
100
      }
101
    };
102
103
    // Extend with the existing constructor to carry over any static properties
104
    $.extend( constructor, existingConstructor, {
105
      version: prototype.version,
106
107
      // Copy the object used to create the prototype in case we need to
108
      // redefine the widget later
109
      _proto: $.extend( {}, prototype ),
110
111
      // Track widgets that inherit from this widget in case this widget is
112
      // redefined after a widget inherits from it
113
      _childConstructors: []
114
    } );
115
116
    basePrototype = new base();
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like base should be capitalized.
Loading history...
117
118
    // We need to make the options hash a property directly on the new instance
119
    // otherwise we'll modify the options hash on the prototype that we're
120
    // inheriting from
121
    basePrototype.options = $.widget.extend( {}, basePrototype.options );
122
    $.each( prototype, function( prop, value ) {
123
      if ( !$.isFunction( value ) ) {
124
        proxiedPrototype[ prop ] = value;
125
        return;
126
      }
127
      proxiedPrototype[ prop ] = ( function() {
128
        function _super() {
129
          return base.prototype[ prop ].apply( this, arguments );
130
        }
131
132
        function _superApply( args ) {
133
          return base.prototype[ prop ].apply( this, args );
134
        }
135
136
        return function() {
137
          var __super = this._super;
138
          var __superApply = this._superApply;
139
          var returnValue;
140
141
          this._super = _super;
142
          this._superApply = _superApply;
143
144
          returnValue = value.apply( this, arguments );
145
146
          this._super = __super;
147
          this._superApply = __superApply;
148
149
          return returnValue;
150
        };
151
      } )();
152
    } );
153
    constructor.prototype = $.widget.extend( basePrototype, {
154
155
      // TODO: remove support for widgetEventPrefix
156
      // always use the name + a colon as the prefix, e.g., draggable:start
157
      // don't prefix for widgets that aren't DOM-based
158
      widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
159
    }, proxiedPrototype, {
160
      constructor: constructor,
161
      namespace: namespace,
162
      widgetName: name,
163
      widgetFullName: fullName
164
    } );
165
166
    // If this widget is being redefined then we need to find all widgets that
167
    // are inheriting from it and redefine all of them so that they inherit from
168
    // the new version of this widget. We're essentially trying to replace one
169
    // level in the prototype chain.
170
    if ( existingConstructor ) {
171
      $.each( existingConstructor._childConstructors, function( i, child ) {
172
        var childPrototype = child.prototype;
173
174
        // Redefine the child widget using the same prototype that was
175
        // originally used, but inherit from the new version of the base
176
        $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
177
          child._proto );
178
      } );
179
180
      // Remove the list of existing child constructors from the old constructor
181
      // so the old child constructors can be garbage collected
182
      delete existingConstructor._childConstructors;
183
    } else {
184
      base._childConstructors.push( constructor );
185
    }
186
187
    $.widget.bridge( name, constructor );
188
189
    return constructor;
190
  };
191
192
  $.widget.extend = function( target ) {
193
    var input = widgetSlice.call( arguments, 1 );
194
    var inputIndex = 0;
195
    var inputLength = input.length;
196
    var key;
197
    var value;
198
199
    for ( ; inputIndex < inputLength; inputIndex++ ) {
200
      for ( key in input[ inputIndex ] ) {
201
        value = input[ inputIndex ][ key ];
202
        if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
203
204
          // Clone objects
205
          if ( $.isPlainObject( value ) ) {
206
            target[ key ] = $.isPlainObject( target[ key ] ) ?
207
              $.widget.extend( {}, target[ key ], value ) :
208
209
              // Don't extend strings, arrays, etc. with objects
210
              $.widget.extend( {}, value );
211
212
            // Copy everything else by reference
213
          } else {
214
            target[ key ] = value;
215
          }
216
        }
217
      }
218
    }
219
    return target;
220
  };
221
222
  $.widget.bridge = function( name, object ) {
223
    var fullName = object.prototype.widgetFullName || name;
224
    $.fn[ name ] = function( options ) {
225
      var isMethodCall = typeof options === "string";
226
      var args = widgetSlice.call( arguments, 1 );
227
      var returnValue = this;
228
229
      if ( isMethodCall ) {
230
231
        // If this is an empty collection, we need to have the instance method
232
        // return undefined instead of the jQuery instance
233
        if ( !this.length && options === "instance" ) {
234
          returnValue = undefined;
235
        } else {
236
          this.each( function() {
237
            var methodValue;
238
            var instance = $.data( this, fullName );
239
240
            if ( options === "instance" ) {
241
              returnValue = instance;
242
              return false;
243
            }
244
245
            if ( !instance ) {
246
              return $.error( "cannot call methods on " + name +
247
                " prior to initialization; " +
248
                "attempted to call method '" + options + "'" );
249
            }
250
251
            if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
252
              return $.error( "no such method '" + options + "' for " + name +
253
                " widget instance" );
254
            }
255
256
            methodValue = instance[ options ].apply( instance, args );
257
258
            if ( methodValue !== instance && methodValue !== undefined ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if methodValue !== instance...thodValue !== undefined is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
259
              returnValue = methodValue && methodValue.jquery ?
260
                returnValue.pushStack( methodValue.get() ) :
261
                methodValue;
262
              return false;
263
            }
264
          } );
265
        }
266
      } else {
267
268
        // Allow multiple hashes to be passed on init
269
        if ( args.length ) {
270
          options = $.widget.extend.apply( null, [ options ].concat( args ) );
271
        }
272
273
        this.each( function() {
274
          var instance = $.data( this, fullName );
275
          if ( instance ) {
276
            instance.option( options || {} );
277
            if ( instance._init ) {
278
              instance._init();
279
            }
280
          } else {
281
            $.data( this, fullName, new object( options, this ) );
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like object should be capitalized.
Loading history...
282
          }
283
        } );
284
      }
285
286
      return returnValue;
287
    };
288
  };
289
290
  $.Widget = function( /* options, element */ ) {};
291
  $.Widget._childConstructors = [];
292
293
  $.Widget.prototype = {
294
    widgetName: "widget",
295
    widgetEventPrefix: "",
296
    defaultElement: "<div>",
297
298
    options: {
299
      classes: {},
300
      disabled: false,
301
302
      // Callbacks
303
      create: null
304
    },
305
306
    _createWidget: function( options, element ) {
307
      element = $( element || this.defaultElement || this )[ 0 ];
308
      this.element = $( element );
309
      this.uuid = widgetUuid++;
310
      this.eventNamespace = "." + this.widgetName + this.uuid;
311
312
      this.bindings = $();
313
      this.hoverable = $();
314
      this.focusable = $();
315
      this.classesElementLookup = {};
316
317
      if ( element !== this ) {
318
        $.data( element, this.widgetFullName, this );
319
        this._on( true, this.element, {
320
          remove: function( event ) {
321
            if ( event.target === element ) {
322
              this.destroy();
323
            }
324
          }
325
        } );
326
        this.document = $( element.style ?
327
328
          // Element within the document
329
          element.ownerDocument :
330
331
          // Element is window or document
332
          element.document || element );
333
        this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
334
      }
335
336
      this.options = $.widget.extend( {},
337
        this.options,
338
        this._getCreateOptions(),
339
        options );
340
341
      this._create();
342
343
      if ( this.options.disabled ) {
344
        this._setOptionDisabled( this.options.disabled );
345
      }
346
347
      this._trigger( "create", null, this._getCreateEventData() );
348
      this._init();
349
    },
350
351
    _getCreateOptions: function() {
352
      return {};
353
    },
354
355
    _getCreateEventData: $.noop,
356
357
    _create: $.noop,
358
359
    _init: $.noop,
360
361
    destroy: function() {
362
      var that = this;
363
364
      this._destroy();
365
      $.each( this.classesElementLookup, function( key, value ) {
366
        that._removeClass( value, key );
367
      } );
368
369
      // We can probably remove the unbind calls in 2.0
370
      // all event bindings should go through this._on()
371
      this.element
372
        .off( this.eventNamespace )
373
        .removeData( this.widgetFullName );
374
      this.widget()
375
        .off( this.eventNamespace )
376
        .removeAttr( "aria-disabled" );
377
378
      // Clean up events and states
379
      this.bindings.off( this.eventNamespace );
380
    },
381
382
    _destroy: $.noop,
383
384
    widget: function() {
385
      return this.element;
386
    },
387
388
    option: function( key, value ) {
389
      var options = key;
390
      var parts;
391
      var curOption;
392
      var i;
393
394
      if ( arguments.length === 0 ) {
395
396
        // Don't return a reference to the internal hash
397
        return $.widget.extend( {}, this.options );
398
      }
399
400
      if ( typeof key === "string" ) {
401
402
        // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
403
        options = {};
404
        parts = key.split( "." );
405
        key = parts.shift();
406
        if ( parts.length ) {
407
          curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
408
          for ( i = 0; i < parts.length - 1; i++ ) {
409
            curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
410
            curOption = curOption[ parts[ i ] ];
411
          }
412
          key = parts.pop();
413
          if ( arguments.length === 1 ) {
414
            return curOption[ key ] === undefined ? null : curOption[ key ];
415
          }
416
          curOption[ key ] = value;
417
        } else {
418
          if ( arguments.length === 1 ) {
419
            return this.options[ key ] === undefined ? null : this.options[ key ];
420
          }
421
          options[ key ] = value;
422
        }
423
      }
424
425
      this._setOptions( options );
426
427
      return this;
428
    },
429
430
    _setOptions: function( options ) {
431
      var key;
432
433
      for ( key in options ) {
434
        this._setOption( key, options[ key ] );
435
      }
436
437
      return this;
438
    },
439
440
    _setOption: function( key, value ) {
441
      if ( key === "classes" ) {
442
        this._setOptionClasses( value );
443
      }
444
445
      this.options[ key ] = value;
446
447
      if ( key === "disabled" ) {
448
        this._setOptionDisabled( value );
449
      }
450
451
      return this;
452
    },
453
454
    _setOptionClasses: function( value ) {
455
      var classKey, elements, currentElements;
456
457
      for ( classKey in value ) {
458
        currentElements = this.classesElementLookup[ classKey ];
459
        if ( value[ classKey ] === this.options.classes[ classKey ] ||
460
          !currentElements ||
461
          !currentElements.length ) {
462
          continue;
463
        }
464
465
        // We are doing this to create a new jQuery object because the _removeClass() call
466
        // on the next line is going to destroy the reference to the current elements being
467
        // tracked. We need to save a copy of this collection so that we can add the new classes
468
        // below.
469
        elements = $( currentElements.get() );
470
        this._removeClass( currentElements, classKey );
471
472
        // We don't use _addClass() here, because that uses this.options.classes
473
        // for generating the string of classes. We want to use the value passed in from
474
        // _setOption(), this is the new value of the classes option which was passed to
475
        // _setOption(). We pass this value directly to _classes().
476
        elements.addClass( this._classes( {
477
          element: elements,
478
          keys: classKey,
479
          classes: value,
480
          add: true
481
        } ) );
482
      }
483
    },
484
485
    _setOptionDisabled: function( value ) {
486
      this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
487
488
      // If the widget is becoming disabled, then nothing is interactive
489
      if ( value ) {
490
        this._removeClass( this.hoverable, null, "ui-state-hover" );
491
        this._removeClass( this.focusable, null, "ui-state-focus" );
492
      }
493
    },
494
495
    enable: function() {
496
      return this._setOptions( { disabled: false } );
497
    },
498
499
    disable: function() {
500
      return this._setOptions( { disabled: true } );
501
    },
502
503
    _classes: function( options ) {
504
      var full = [];
505
      var that = this;
506
507
      options = $.extend( {
508
        element: this.element,
509
        classes: this.options.classes || {}
510
      }, options );
511
512
      function processClassString( classes, checkOption ) {
513
        var current, i;
514
        for ( i = 0; i < classes.length; i++ ) {
515
          current = that.classesElementLookup[ classes[ i ] ] || $();
516
          if ( options.add ) {
517
            current = $( $.unique( current.get().concat( options.element.get() ) ) );
518
          } else {
519
            current = $( current.not( options.element ).get() );
520
          }
521
          that.classesElementLookup[ classes[ i ] ] = current;
522
          full.push( classes[ i ] );
523
          if ( checkOption && options.classes[ classes[ i ] ] ) {
524
            full.push( options.classes[ classes[ i ] ] );
525
          }
526
        }
527
      }
528
529
      this._on( options.element, {
530
        "remove": "_untrackClassesElement"
531
      } );
532
533
      if ( options.keys ) {
534
        processClassString( options.keys.match( /\S+/g ) || [], true );
535
      }
536
      if ( options.extra ) {
537
        processClassString( options.extra.match( /\S+/g ) || [] );
538
      }
539
540
      return full.join( " " );
541
    },
542
543
    _untrackClassesElement: function( event ) {
544
      var that = this;
545
      $.each( that.classesElementLookup, function( key, value ) {
546
        if ( $.inArray( event.target, value ) !== -1 ) {
547
          that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
548
        }
549
      } );
550
    },
551
552
    _removeClass: function( element, keys, extra ) {
553
      return this._toggleClass( element, keys, extra, false );
554
    },
555
556
    _addClass: function( element, keys, extra ) {
557
      return this._toggleClass( element, keys, extra, true );
558
    },
559
560
    _toggleClass: function( element, keys, extra, add ) {
561
      add = ( typeof add === "boolean" ) ? add : extra;
562
      var shift = ( typeof element === "string" || element === null ),
563
        options = {
564
          extra: shift ? keys : extra,
565
          keys: shift ? element : keys,
566
          element: shift ? this.element : element,
567
          add: add
568
        };
569
      options.element.toggleClass( this._classes( options ), add );
570
      return this;
571
    },
572
573
    _on: function( suppressDisabledCheck, element, handlers ) {
574
      var delegateElement;
575
      var instance = this;
576
577
      // No suppressDisabledCheck flag, shuffle arguments
578
      if ( typeof suppressDisabledCheck !== "boolean" ) {
579
        handlers = element;
580
        element = suppressDisabledCheck;
581
        suppressDisabledCheck = false;
582
      }
583
584
      // No element argument, shuffle and use this.element
585
      if ( !handlers ) {
586
        handlers = element;
587
        element = this.element;
588
        delegateElement = this.widget();
589
      } else {
590
        element = delegateElement = $( element );
591
        this.bindings = this.bindings.add( element );
592
      }
593
594
      $.each( handlers, function( event, handler ) {
595
        function handlerProxy() {
596
597
          // Allow widgets to customize the disabled handling
598
          // - disabled as an array instead of boolean
599
          // - disabled class as method for disabling individual parts
600
          if ( !suppressDisabledCheck &&
601
            ( instance.options.disabled === true ||
602
              $( this ).hasClass( "ui-state-disabled" ) ) ) {
603
            return;
604
          }
605
          return ( typeof handler === "string" ? instance[ handler ] : handler )
606
            .apply( instance, arguments );
607
        }
608
609
        // Copy the guid so direct unbinding works
610
        if ( typeof handler !== "string" ) {
611
          handlerProxy.guid = handler.guid =
612
            handler.guid || handlerProxy.guid || $.guid++;
613
        }
614
615
        var match = event.match( /^([\w:-]*)\s*(.*)$/ );
616
        var eventName = match[ 1 ] + instance.eventNamespace;
617
        var selector = match[ 2 ];
618
619
        if ( selector ) {
620
          delegateElement.on( eventName, selector, handlerProxy );
621
        } else {
622
          element.on( eventName, handlerProxy );
623
        }
624
      } );
625
    },
626
627
    _off: function( element, eventName ) {
628
      eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
629
        this.eventNamespace;
630
      element.off( eventName ).off( eventName );
631
632
      // Clear the stack to avoid memory leaks (#10056)
633
      this.bindings = $( this.bindings.not( element ).get() );
634
      this.focusable = $( this.focusable.not( element ).get() );
635
      this.hoverable = $( this.hoverable.not( element ).get() );
636
    },
637
638
    _delay: function( handler, delay ) {
639
      function handlerProxy() {
640
        return ( typeof handler === "string" ? instance[ handler ] : handler )
641
          .apply( instance, arguments );
642
      }
643
      var instance = this;
644
      return setTimeout( handlerProxy, delay || 0 );
645
    },
646
647
    _hoverable: function( element ) {
648
      this.hoverable = this.hoverable.add( element );
649
      this._on( element, {
650
        mouseenter: function( event ) {
651
          this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
652
        },
653
        mouseleave: function( event ) {
654
          this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
655
        }
656
      } );
657
    },
658
659
    _focusable: function( element ) {
660
      this.focusable = this.focusable.add( element );
661
      this._on( element, {
662
        focusin: function( event ) {
663
          this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
664
        },
665
        focusout: function( event ) {
666
          this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
667
        }
668
      } );
669
    },
670
671
    _trigger: function( type, event, data ) {
672
      var prop, orig;
673
      var callback = this.options[ type ];
674
675
      data = data || {};
676
      event = $.Event( event );
677
      event.type = ( type === this.widgetEventPrefix ?
678
        type :
679
        this.widgetEventPrefix + type ).toLowerCase();
680
681
      // The original event may come from any element
682
      // so we need to reset the target on the new event
683
      event.target = this.element[ 0 ];
684
685
      // Copy original event properties over to the new event
686
      orig = event.originalEvent;
687
      if ( orig ) {
688
        for ( prop in orig ) {
689
          if ( !( prop in event ) ) {
690
            event[ prop ] = orig[ prop ];
691
          }
692
        }
693
      }
694
695
      this.element.trigger( event, data );
696
      return !( $.isFunction( callback ) &&
697
        callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
698
        event.isDefaultPrevented() );
699
    }
700
  };
701
702
  $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
703
    $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
704
      if ( typeof options === "string" ) {
705
        options = { effect: options };
706
      }
707
708
      var hasOptions;
709
      var effectName = !options ?
710
        method :
711
        options === true || typeof options === "number" ?
712
        defaultEffect :
713
        options.effect || defaultEffect;
714
715
      options = options || {};
716
      if ( typeof options === "number" ) {
717
        options = { duration: options };
718
      }
719
720
      hasOptions = !$.isEmptyObject( options );
721
      options.complete = callback;
722
723
      if ( options.delay ) {
724
        element.delay( options.delay );
725
      }
726
727
      if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
728
        element[ method ]( options );
729
      } else if ( effectName !== method && element[ effectName ] ) {
730
        element[ effectName ]( options.duration, options.easing, callback );
731
      } else {
732
        element.queue( function( next ) {
733
          $( this )[ method ]();
734
          if ( callback ) {
735
            callback.call( element[ 0 ] );
736
          }
737
          next();
738
        } );
739
      }
740
    };
741
  } );
742
743
  var widget = $.widget;
744
745
746
747
748
}));
749