Passed
Pull Request — master (#133)
by
unknown
14:52 queued 04:47
created

Resources/Public/JavaScript/jquery-ui.js   F

Complexity

Total Complexity 3073
Complexity/F 2.88

Size

Lines of Code 18701
Function Count 1067

Duplication

Duplicated Lines 273
Ratio 1.46 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10692
c 1
b 0
f 0
dl 273
loc 18701
rs 0.8
wmc 3073
mnd 2006
bc 2006
fnc 1067
bpm 1.88
cpm 2.88
noi 151

35 Functions

Rating   Name   Duplication   Size   Complexity  
B jquery-ui.js ➔ Datepicker 0 89 1
F jquery-ui.js ➔ processClassString 0 16 61
B jquery-ui.js ➔ handlerProxy 0 13 6
F jquery-ui.js ➔ reduce 0 12 19
F jquery-ui.js ➔ isOverAxis 0 3 102
F jquery-ui.js ➔ _normalizeArguments 0 51 90
F jquery-ui.js ➔ spinnerModifer 0 10 19
F jquery-ui.js ➔ datepicker_getZindex 0 24 487
B jquery-ui.js ➔ filteredUi 0 6 8
F jquery-ui.js ➔ getOffsets 0 6 26
F jquery-ui.js ➔ addItems 0 3 429
A jquery-ui.js ➔ show 0 10 2
F jquery-ui.js ➔ position 0 7 88
F jquery-ui.js ➔ constrain 0 9 110
A jquery-ui.js ➔ standardAnimationOption 0 25 5
F jquery-ui.js ➔ datepicker_bindHover 0 13 427
A jquery-ui.js ➔ getDimensions 0 29 4
F jquery-ui.js ➔ getElementStyles 0 27 56
C jquery-ui.js ➔ animComplete 0 7 9
A jquery-ui.js ➔ _superApply 0 3 1
B jquery-ui.js ➔ stringParse 0 39 5
F jquery-ui.js ➔ hue2rgb 0 13 57
A jquery-ui.js ➔ styleDifference 0 17 5
F jquery-ui.js ➔ run 0 49 19
A jquery-ui.js ➔ datepicker_handleMouseover 0 12 5
F jquery-ui.js ➔ clamp 0 26 105
F jquery-ui.js ➔ visible 0 8 63
A jquery-ui.js ➔ parseCss 0 3 1
F jquery-ui.js ➔ parseClip 0 13 24
F jquery-ui.js ➔ checkFocus 0 8 23
F jquery-ui.js ➔ _super 0 3 19
F jquery-ui.js ➔ childComplete 0 6 50
F jquery-ui.js ➔ delayEvent 0 5 140
A jquery-ui.js ➔ datepicker_extendRemove 0 9 3
F jquery-ui.js ➔ complete 0 4 62

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Resources/Public/JavaScript/jquery-ui.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 - 2016-09-14
2
* http://jqueryui.com
3
* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
4
* Copyright jQuery Foundation and other contributors; Licensed MIT */
5
6
(function( factory ) {
7
	if ( typeof define === "function" && define.amd ) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
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++ ) {
0 ignored issues
show
Best Practice introduced by
Comparing elem = elems.i to null using the != operator is not safe. Consider using !== instead.
Loading history...
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 ) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
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 );
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
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;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
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
 * jQuery UI Position 1.12.1
748
 * http://jqueryui.com
749
 *
750
 * Copyright jQuery Foundation and other contributors
751
 * Released under the MIT license.
752
 * http://jquery.org/license
753
 *
754
 * http://api.jqueryui.com/position/
755
 */
756
757
//>>label: Position
758
//>>group: Core
759
//>>description: Positions elements relative to other elements.
760
//>>docs: http://api.jqueryui.com/position/
761
//>>demos: http://jqueryui.com/position/
762
763
764
( function() {
765
var cachedScrollbarWidth,
766
	max = Math.max,
767
	abs = Math.abs,
768
	rhorizontal = /left|center|right/,
769
	rvertical = /top|center|bottom/,
770
	roffset = /[\+\-]\d+(\.[\d]+)?%?/,
771
	rposition = /^\w+/,
772
	rpercent = /%$/,
773
	_position = $.fn.position;
774
775
function getOffsets( offsets, width, height ) {
776
	return [
777
		parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
778
		parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
779
	];
780
}
781
782
function parseCss( element, property ) {
783
	return parseInt( $.css( element, property ), 10 ) || 0;
784
}
785
786
function getDimensions( elem ) {
787
	var raw = elem[ 0 ];
788
	if ( raw.nodeType === 9 ) {
789
		return {
790
			width: elem.width(),
791
			height: elem.height(),
792
			offset: { top: 0, left: 0 }
793
		};
794
	}
795
	if ( $.isWindow( raw ) ) {
796
		return {
797
			width: elem.width(),
798
			height: elem.height(),
799
			offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
800
		};
801
	}
802
	if ( raw.preventDefault ) {
803
		return {
804
			width: 0,
805
			height: 0,
806
			offset: { top: raw.pageY, left: raw.pageX }
807
		};
808
	}
809
	return {
810
		width: elem.outerWidth(),
811
		height: elem.outerHeight(),
812
		offset: elem.offset()
813
	};
814
}
815
816
$.position = {
817
	scrollbarWidth: function() {
818
		if ( cachedScrollbarWidth !== undefined ) {
819
			return cachedScrollbarWidth;
820
		}
821
		var w1, w2,
822
			div = $( "<div " +
823
				"style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
824
				"<div style='height:100px;width:auto;'></div></div>" ),
825
			innerDiv = div.children()[ 0 ];
826
827
		$( "body" ).append( div );
828
		w1 = innerDiv.offsetWidth;
829
		div.css( "overflow", "scroll" );
830
831
		w2 = innerDiv.offsetWidth;
832
833
		if ( w1 === w2 ) {
834
			w2 = div[ 0 ].clientWidth;
835
		}
836
837
		div.remove();
838
839
		return ( cachedScrollbarWidth = w1 - w2 );
840
	},
841
	getScrollInfo: function( within ) {
842
		var overflowX = within.isWindow || within.isDocument ? "" :
843
				within.element.css( "overflow-x" ),
844
			overflowY = within.isWindow || within.isDocument ? "" :
845
				within.element.css( "overflow-y" ),
846
			hasOverflowX = overflowX === "scroll" ||
847
				( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
848
			hasOverflowY = overflowY === "scroll" ||
849
				( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
850
		return {
851
			width: hasOverflowY ? $.position.scrollbarWidth() : 0,
852
			height: hasOverflowX ? $.position.scrollbarWidth() : 0
853
		};
854
	},
855
	getWithinInfo: function( element ) {
856
		var withinElement = $( element || window ),
857
			isWindow = $.isWindow( withinElement[ 0 ] ),
858
			isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
859
			hasOffset = !isWindow && !isDocument;
860
		return {
861
			element: withinElement,
862
			isWindow: isWindow,
863
			isDocument: isDocument,
864
			offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
865
			scrollLeft: withinElement.scrollLeft(),
866
			scrollTop: withinElement.scrollTop(),
867
			width: withinElement.outerWidth(),
868
			height: withinElement.outerHeight()
869
		};
870
	}
871
};
872
873
$.fn.position = function( options ) {
874
	if ( !options || !options.of ) {
875
		return _position.apply( this, arguments );
876
	}
877
878
	// Make a copy, we don't want to modify arguments
879
	options = $.extend( {}, options );
880
881
	var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
882
		target = $( options.of ),
883
		within = $.position.getWithinInfo( options.within ),
884
		scrollInfo = $.position.getScrollInfo( within ),
885
		collision = ( options.collision || "flip" ).split( " " ),
886
		offsets = {};
887
888
	dimensions = getDimensions( target );
889
	if ( target[ 0 ].preventDefault ) {
890
891
		// Force left top to allow flipping
892
		options.at = "left top";
893
	}
894
	targetWidth = dimensions.width;
895
	targetHeight = dimensions.height;
896
	targetOffset = dimensions.offset;
897
898
	// Clone to reuse original targetOffset later
899
	basePosition = $.extend( {}, targetOffset );
900
901
	// Force my and at to have valid horizontal and vertical positions
902
	// if a value is missing or invalid, it will be converted to center
903
	$.each( [ "my", "at" ], function() {
904
		var pos = ( options[ this ] || "" ).split( " " ),
905
			horizontalOffset,
906
			verticalOffset;
907
908
		if ( pos.length === 1 ) {
909
			pos = rhorizontal.test( pos[ 0 ] ) ?
910
				pos.concat( [ "center" ] ) :
911
				rvertical.test( pos[ 0 ] ) ?
912
					[ "center" ].concat( pos ) :
913
					[ "center", "center" ];
914
		}
915
		pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
916
		pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
917
918
		// Calculate offsets
919
		horizontalOffset = roffset.exec( pos[ 0 ] );
920
		verticalOffset = roffset.exec( pos[ 1 ] );
921
		offsets[ this ] = [
922
			horizontalOffset ? horizontalOffset[ 0 ] : 0,
923
			verticalOffset ? verticalOffset[ 0 ] : 0
924
		];
925
926
		// Reduce to just the positions without the offsets
927
		options[ this ] = [
928
			rposition.exec( pos[ 0 ] )[ 0 ],
929
			rposition.exec( pos[ 1 ] )[ 0 ]
930
		];
931
	} );
932
933
	// Normalize collision option
934
	if ( collision.length === 1 ) {
935
		collision[ 1 ] = collision[ 0 ];
936
	}
937
938
	if ( options.at[ 0 ] === "right" ) {
939
		basePosition.left += targetWidth;
940
	} else if ( options.at[ 0 ] === "center" ) {
941
		basePosition.left += targetWidth / 2;
942
	}
943
944
	if ( options.at[ 1 ] === "bottom" ) {
945
		basePosition.top += targetHeight;
946
	} else if ( options.at[ 1 ] === "center" ) {
947
		basePosition.top += targetHeight / 2;
948
	}
949
950
	atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
951
	basePosition.left += atOffset[ 0 ];
952
	basePosition.top += atOffset[ 1 ];
953
954
	return this.each( function() {
955
		var collisionPosition, using,
956
			elem = $( this ),
957
			elemWidth = elem.outerWidth(),
958
			elemHeight = elem.outerHeight(),
959
			marginLeft = parseCss( this, "marginLeft" ),
960
			marginTop = parseCss( this, "marginTop" ),
961
			collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
962
				scrollInfo.width,
963
			collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
964
				scrollInfo.height,
965
			position = $.extend( {}, basePosition ),
966
			myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
967
968
		if ( options.my[ 0 ] === "right" ) {
969
			position.left -= elemWidth;
970
		} else if ( options.my[ 0 ] === "center" ) {
971
			position.left -= elemWidth / 2;
972
		}
973
974
		if ( options.my[ 1 ] === "bottom" ) {
975
			position.top -= elemHeight;
976
		} else if ( options.my[ 1 ] === "center" ) {
977
			position.top -= elemHeight / 2;
978
		}
979
980
		position.left += myOffset[ 0 ];
981
		position.top += myOffset[ 1 ];
982
983
		collisionPosition = {
984
			marginLeft: marginLeft,
985
			marginTop: marginTop
986
		};
987
988
		$.each( [ "left", "top" ], function( i, dir ) {
989
			if ( $.ui.position[ collision[ i ] ] ) {
990
				$.ui.position[ collision[ i ] ][ dir ]( position, {
991
					targetWidth: targetWidth,
992
					targetHeight: targetHeight,
993
					elemWidth: elemWidth,
994
					elemHeight: elemHeight,
995
					collisionPosition: collisionPosition,
996
					collisionWidth: collisionWidth,
997
					collisionHeight: collisionHeight,
998
					offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
999
					my: options.my,
1000
					at: options.at,
1001
					within: within,
1002
					elem: elem
1003
				} );
1004
			}
1005
		} );
1006
1007
		if ( options.using ) {
1008
1009
			// Adds feedback as second argument to using callback, if present
1010
			using = function( props ) {
1011
				var left = targetOffset.left - position.left,
1012
					right = left + targetWidth - elemWidth,
1013
					top = targetOffset.top - position.top,
1014
					bottom = top + targetHeight - elemHeight,
1015
					feedback = {
1016
						target: {
1017
							element: target,
1018
							left: targetOffset.left,
1019
							top: targetOffset.top,
1020
							width: targetWidth,
1021
							height: targetHeight
1022
						},
1023
						element: {
1024
							element: elem,
1025
							left: position.left,
1026
							top: position.top,
1027
							width: elemWidth,
1028
							height: elemHeight
1029
						},
1030
						horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1031
						vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1032
					};
1033
				if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1034
					feedback.horizontal = "center";
1035
				}
1036
				if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1037
					feedback.vertical = "middle";
1038
				}
1039
				if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1040
					feedback.important = "horizontal";
1041
				} else {
1042
					feedback.important = "vertical";
1043
				}
1044
				options.using.call( this, props, feedback );
1045
			};
1046
		}
1047
1048
		elem.offset( $.extend( position, { using: using } ) );
0 ignored issues
show
Bug introduced by
The variable using does not seem to be initialized in case options.using on line 1007 is false. Are you sure this can never be the case?
Loading history...
1049
	} );
1050
};
1051
1052
$.ui.position = {
1053
	fit: {
1054
		left: function( position, data ) {
1055
			var within = data.within,
1056
				withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1057
				outerWidth = within.width,
1058
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1059
				overLeft = withinOffset - collisionPosLeft,
1060
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1061
				newOverRight;
1062
1063
			// Element is wider than within
1064
			if ( data.collisionWidth > outerWidth ) {
1065
1066
				// Element is initially over the left side of within
1067
				if ( overLeft > 0 && overRight <= 0 ) {
1068
					newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
1069
						withinOffset;
1070
					position.left += overLeft - newOverRight;
1071
1072
				// Element is initially over right side of within
1073
				} else if ( overRight > 0 && overLeft <= 0 ) {
1074
					position.left = withinOffset;
1075
1076
				// Element is initially over both left and right sides of within
1077
				} else {
1078
					if ( overLeft > overRight ) {
1079
						position.left = withinOffset + outerWidth - data.collisionWidth;
1080
					} else {
1081
						position.left = withinOffset;
1082
					}
1083
				}
1084
1085
			// Too far left -> align with left edge
1086
			} else if ( overLeft > 0 ) {
1087
				position.left += overLeft;
1088
1089
			// Too far right -> align with right edge
1090
			} else if ( overRight > 0 ) {
1091
				position.left -= overRight;
1092
1093
			// Adjust based on position and margin
1094
			} else {
1095
				position.left = max( position.left - collisionPosLeft, position.left );
1096
			}
1097
		},
1098
		top: function( position, data ) {
1099
			var within = data.within,
1100
				withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1101
				outerHeight = data.within.height,
1102
				collisionPosTop = position.top - data.collisionPosition.marginTop,
1103
				overTop = withinOffset - collisionPosTop,
1104
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1105
				newOverBottom;
1106
1107
			// Element is taller than within
1108
			if ( data.collisionHeight > outerHeight ) {
1109
1110
				// Element is initially over the top of within
1111
				if ( overTop > 0 && overBottom <= 0 ) {
1112
					newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
1113
						withinOffset;
1114
					position.top += overTop - newOverBottom;
1115
1116
				// Element is initially over bottom of within
1117
				} else if ( overBottom > 0 && overTop <= 0 ) {
1118
					position.top = withinOffset;
1119
1120
				// Element is initially over both top and bottom of within
1121
				} else {
1122
					if ( overTop > overBottom ) {
1123
						position.top = withinOffset + outerHeight - data.collisionHeight;
1124
					} else {
1125
						position.top = withinOffset;
1126
					}
1127
				}
1128
1129
			// Too far up -> align with top
1130
			} else if ( overTop > 0 ) {
1131
				position.top += overTop;
1132
1133
			// Too far down -> align with bottom edge
1134
			} else if ( overBottom > 0 ) {
1135
				position.top -= overBottom;
1136
1137
			// Adjust based on position and margin
1138
			} else {
1139
				position.top = max( position.top - collisionPosTop, position.top );
1140
			}
1141
		}
1142
	},
1143
	flip: {
1144
		left: function( position, data ) {
1145
			var within = data.within,
1146
				withinOffset = within.offset.left + within.scrollLeft,
1147
				outerWidth = within.width,
1148
				offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1149
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1150
				overLeft = collisionPosLeft - offsetLeft,
1151
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1152
				myOffset = data.my[ 0 ] === "left" ?
1153
					-data.elemWidth :
1154
					data.my[ 0 ] === "right" ?
1155
						data.elemWidth :
1156
						0,
1157
				atOffset = data.at[ 0 ] === "left" ?
1158
					data.targetWidth :
1159
					data.at[ 0 ] === "right" ?
1160
						-data.targetWidth :
1161
						0,
1162
				offset = -2 * data.offset[ 0 ],
1163
				newOverRight,
1164
				newOverLeft;
1165
1166
			if ( overLeft < 0 ) {
1167
				newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
1168
					outerWidth - withinOffset;
1169
				if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1170
					position.left += myOffset + atOffset + offset;
1171
				}
1172
			} else if ( overRight > 0 ) {
1173
				newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
1174
					atOffset + offset - offsetLeft;
1175
				if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1176
					position.left += myOffset + atOffset + offset;
1177
				}
1178
			}
1179
		},
1180
		top: function( position, data ) {
1181
			var within = data.within,
1182
				withinOffset = within.offset.top + within.scrollTop,
1183
				outerHeight = within.height,
1184
				offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1185
				collisionPosTop = position.top - data.collisionPosition.marginTop,
1186
				overTop = collisionPosTop - offsetTop,
1187
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1188
				top = data.my[ 1 ] === "top",
1189
				myOffset = top ?
1190
					-data.elemHeight :
1191
					data.my[ 1 ] === "bottom" ?
1192
						data.elemHeight :
1193
						0,
1194
				atOffset = data.at[ 1 ] === "top" ?
1195
					data.targetHeight :
1196
					data.at[ 1 ] === "bottom" ?
1197
						-data.targetHeight :
1198
						0,
1199
				offset = -2 * data.offset[ 1 ],
1200
				newOverTop,
1201
				newOverBottom;
1202
			if ( overTop < 0 ) {
1203
				newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
1204
					outerHeight - withinOffset;
1205
				if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
1206
					position.top += myOffset + atOffset + offset;
1207
				}
1208
			} else if ( overBottom > 0 ) {
1209
				newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
1210
					offset - offsetTop;
1211
				if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
1212
					position.top += myOffset + atOffset + offset;
1213
				}
1214
			}
1215
		}
1216
	},
1217
	flipfit: {
1218
		left: function() {
1219
			$.ui.position.flip.left.apply( this, arguments );
1220
			$.ui.position.fit.left.apply( this, arguments );
1221
		},
1222
		top: function() {
1223
			$.ui.position.flip.top.apply( this, arguments );
1224
			$.ui.position.fit.top.apply( this, arguments );
1225
		}
1226
	}
1227
};
1228
1229
} )();
1230
1231
var position = $.ui.position;
1232
1233
1234
/*!
1235
 * jQuery UI :data 1.12.1
1236
 * http://jqueryui.com
1237
 *
1238
 * Copyright jQuery Foundation and other contributors
1239
 * Released under the MIT license.
1240
 * http://jquery.org/license
1241
 */
1242
1243
//>>label: :data Selector
1244
//>>group: Core
1245
//>>description: Selects elements which have data stored under the specified key.
1246
//>>docs: http://api.jqueryui.com/data-selector/
1247
1248
1249
var data = $.extend( $.expr[ ":" ], {
1250
	data: $.expr.createPseudo ?
1251
		$.expr.createPseudo( function( dataName ) {
1252
			return function( elem ) {
1253
				return !!$.data( elem, dataName );
1254
			};
1255
		} ) :
1256
1257
		// Support: jQuery <1.8
1258
		function( elem, i, match ) {
1259
			return !!$.data( elem, match[ 3 ] );
1260
		}
1261
} );
1262
1263
/*!
1264
 * jQuery UI Disable Selection 1.12.1
1265
 * http://jqueryui.com
1266
 *
1267
 * Copyright jQuery Foundation and other contributors
1268
 * Released under the MIT license.
1269
 * http://jquery.org/license
1270
 */
1271
1272
//>>label: disableSelection
1273
//>>group: Core
1274
//>>description: Disable selection of text content within the set of matched elements.
1275
//>>docs: http://api.jqueryui.com/disableSelection/
1276
1277
// This file is deprecated
1278
1279
1280
var disableSelection = $.fn.extend( {
1281
	disableSelection: ( function() {
1282
		var eventType = "onselectstart" in document.createElement( "div" ) ?
1283
			"selectstart" :
1284
			"mousedown";
1285
1286
		return function() {
1287
			return this.on( eventType + ".ui-disableSelection", function( event ) {
1288
				event.preventDefault();
1289
			} );
1290
		};
1291
	} )(),
1292
1293
	enableSelection: function() {
1294
		return this.off( ".ui-disableSelection" );
1295
	}
1296
} );
1297
1298
1299
/*!
1300
 * jQuery UI Effects 1.12.1
1301
 * http://jqueryui.com
1302
 *
1303
 * Copyright jQuery Foundation and other contributors
1304
 * Released under the MIT license.
1305
 * http://jquery.org/license
1306
 */
1307
1308
//>>label: Effects Core
1309
//>>group: Effects
1310
// jscs:disable maximumLineLength
1311
//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
1312
// jscs:enable maximumLineLength
1313
//>>docs: http://api.jqueryui.com/category/effects-core/
1314
//>>demos: http://jqueryui.com/effect/
1315
1316
1317
1318
var dataSpace = "ui-effects-",
1319
	dataSpaceStyle = "ui-effects-style",
1320
	dataSpaceAnimated = "ui-effects-animated",
1321
1322
	// Create a local jQuery because jQuery Color relies on it and the
1323
	// global may not exist with AMD and a custom build (#10199)
1324
	jQuery = $;
1325
1326
$.effects = {
1327
	effect: {}
1328
};
1329
1330
/*!
1331
 * jQuery Color Animations v2.1.2
1332
 * https://github.com/jquery/jquery-color
1333
 *
1334
 * Copyright 2014 jQuery Foundation and other contributors
1335
 * Released under the MIT license.
1336
 * http://jquery.org/license
1337
 *
1338
 * Date: Wed Jan 16 08:47:09 2013 -0600
1339
 */
1340
( function( jQuery, undefined ) {
1341
1342
	var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
1343
		"borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
1344
1345
	// Plusequals test for += 100 -= 100
1346
	rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
1347
1348
	// A set of RE's that can match strings and generate color tuples.
1349
	stringParsers = [ {
1350
			re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1351
			parse: function( execResult ) {
1352
				return [
1353
					execResult[ 1 ],
1354
					execResult[ 2 ],
1355
					execResult[ 3 ],
1356
					execResult[ 4 ]
1357
				];
1358
			}
1359
		}, {
1360
			re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1361
			parse: function( execResult ) {
1362
				return [
1363
					execResult[ 1 ] * 2.55,
1364
					execResult[ 2 ] * 2.55,
1365
					execResult[ 3 ] * 2.55,
1366
					execResult[ 4 ]
1367
				];
1368
			}
1369
		}, {
1370
1371
			// This regex ignores A-F because it's compared against an already lowercased string
1372
			re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
1373
			parse: function( execResult ) {
1374
				return [
1375
					parseInt( execResult[ 1 ], 16 ),
1376
					parseInt( execResult[ 2 ], 16 ),
1377
					parseInt( execResult[ 3 ], 16 )
1378
				];
1379
			}
1380
		}, {
1381
1382
			// This regex ignores A-F because it's compared against an already lowercased string
1383
			re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
1384
			parse: function( execResult ) {
1385
				return [
1386
					parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
1387
					parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
1388
					parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
1389
				];
1390
			}
1391
		}, {
1392
			re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1393
			space: "hsla",
1394
			parse: function( execResult ) {
1395
				return [
1396
					execResult[ 1 ],
1397
					execResult[ 2 ] / 100,
1398
					execResult[ 3 ] / 100,
1399
					execResult[ 4 ]
1400
				];
1401
			}
1402
		} ],
1403
1404
	// JQuery.Color( )
1405
	color = jQuery.Color = function( color, green, blue, alpha ) {
1406
		return new jQuery.Color.fn.parse( color, green, blue, alpha );
1407
	},
1408
	spaces = {
1409
		rgba: {
1410
			props: {
1411
				red: {
1412
					idx: 0,
1413
					type: "byte"
1414
				},
1415
				green: {
1416
					idx: 1,
1417
					type: "byte"
1418
				},
1419
				blue: {
1420
					idx: 2,
1421
					type: "byte"
1422
				}
1423
			}
1424
		},
1425
1426
		hsla: {
1427
			props: {
1428
				hue: {
1429
					idx: 0,
1430
					type: "degrees"
1431
				},
1432
				saturation: {
1433
					idx: 1,
1434
					type: "percent"
1435
				},
1436
				lightness: {
1437
					idx: 2,
1438
					type: "percent"
1439
				}
1440
			}
1441
		}
1442
	},
1443
	propTypes = {
1444
		"byte": {
1445
			floor: true,
1446
			max: 255
1447
		},
1448
		"percent": {
1449
			max: 1
1450
		},
1451
		"degrees": {
1452
			mod: 360,
1453
			floor: true
1454
		}
1455
	},
1456
	support = color.support = {},
1457
1458
	// Element for support tests
1459
	supportElem = jQuery( "<p>" )[ 0 ],
1460
1461
	// Colors = jQuery.Color.names
1462
	colors,
1463
1464
	// Local aliases of functions called often
1465
	each = jQuery.each;
1466
1467
// Determine rgba support immediately
1468
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
1469
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
1470
1471
// Define cache name and alpha properties
1472
// for rgba and hsla spaces
1473
each( spaces, function( spaceName, space ) {
1474
	space.cache = "_" + spaceName;
1475
	space.props.alpha = {
1476
		idx: 3,
1477
		type: "percent",
1478
		def: 1
1479
	};
1480
} );
1481
1482
function clamp( value, prop, allowEmpty ) {
1483
	var type = propTypes[ prop.type ] || {};
1484
1485
	if ( value == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing value to null using the == operator is not safe. Consider using === instead.
Loading history...
1486
		return ( allowEmpty || !prop.def ) ? null : prop.def;
1487
	}
1488
1489
	// ~~ is an short way of doing floor for positive numbers
1490
	value = type.floor ? ~~value : parseFloat( value );
1491
1492
	// IE will pass in empty strings as value for alpha,
1493
	// which will hit this case
1494
	if ( isNaN( value ) ) {
1495
		return prop.def;
1496
	}
1497
1498
	if ( type.mod ) {
1499
1500
		// We add mod before modding to make sure that negatives values
1501
		// get converted properly: -10 -> 350
1502
		return ( value + type.mod ) % type.mod;
1503
	}
1504
1505
	// For now all property types without mod have min and max
1506
	return 0 > value ? 0 : type.max < value ? type.max : value;
1507
}
1508
1509
function stringParse( string ) {
1510
	var inst = color(),
1511
		rgba = inst._rgba = [];
1512
1513
	string = string.toLowerCase();
1514
1515
	each( stringParsers, function( i, parser ) {
1516
		var parsed,
1517
			match = parser.re.exec( string ),
1518
			values = match && parser.parse( match ),
1519
			spaceName = parser.space || "rgba";
1520
1521
		if ( values ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if values 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...
1522
			parsed = inst[ spaceName ]( values );
1523
1524
			// If this was an rgba parse the assignment might happen twice
1525
			// oh well....
1526
			inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
1527
			rgba = inst._rgba = parsed._rgba;
1528
1529
			// Exit each( stringParsers ) here because we matched
1530
			return false;
1531
		}
1532
	} );
1533
1534
	// Found a stringParser that handled it
1535
	if ( rgba.length ) {
1536
1537
		// If this came from a parsed string, force "transparent" when alpha is 0
1538
		// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
1539
		if ( rgba.join() === "0,0,0,0" ) {
1540
			jQuery.extend( rgba, colors.transparent );
1541
		}
1542
		return inst;
1543
	}
1544
1545
	// Named colors
1546
	return colors[ string ];
1547
}
1548
1549
color.fn = jQuery.extend( color.prototype, {
1550
	parse: function( red, green, blue, alpha ) {
1551
		if ( red === undefined ) {
1552
			this._rgba = [ null, null, null, null ];
1553
			return this;
1554
		}
1555
		if ( red.jquery || red.nodeType ) {
1556
			red = jQuery( red ).css( green );
1557
			green = undefined;
1558
		}
1559
1560
		var inst = this,
1561
			type = jQuery.type( red ),
1562
			rgba = this._rgba = [];
1563
1564
		// More than 1 argument specified - assume ( red, green, blue, alpha )
1565
		if ( green !== undefined ) {
1566
			red = [ red, green, blue, alpha ];
1567
			type = "array";
1568
		}
1569
1570
		if ( type === "string" ) {
1571
			return this.parse( stringParse( red ) || colors._default );
1572
		}
1573
1574
		if ( type === "array" ) {
1575
			each( spaces.rgba.props, function( key, prop ) {
1576
				rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
1577
			} );
1578
			return this;
1579
		}
1580
1581
		if ( type === "object" ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if type === "object" 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...
1582
			if ( red instanceof color ) {
1583
				each( spaces, function( spaceName, space ) {
1584
					if ( red[ space.cache ] ) {
1585
						inst[ space.cache ] = red[ space.cache ].slice();
1586
					}
1587
				} );
1588
			} else {
1589
				each( spaces, function( spaceName, space ) {
1590
					var cache = space.cache;
1591
					each( space.props, function( key, prop ) {
1592
1593
						// If the cache doesn't exist, and we know how to convert
1594
						if ( !inst[ cache ] && space.to ) {
1595
1596
							// If the value was null, we don't need to copy it
1597
							// if the key was alpha, we don't need to copy it either
1598
							if ( key === "alpha" || red[ key ] == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing red.key to null using the == operator is not safe. Consider using === instead.
Loading history...
1599
								return;
1600
							}
1601
							inst[ cache ] = space.to( inst._rgba );
1602
						}
1603
1604
						// This is the only case where we allow nulls for ALL properties.
1605
						// call clamp with alwaysAllowEmpty
1606
						inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
1607
					} );
1608
1609
					// Everything defined but alpha?
1610
					if ( inst[ cache ] &&
1611
							jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
1612
1613
						// Use the default of 1
1614
						inst[ cache ][ 3 ] = 1;
1615
						if ( space.from ) {
1616
							inst._rgba = space.from( inst[ cache ] );
1617
						}
1618
					}
1619
				} );
1620
			}
1621
			return this;
1622
		}
1623
	},
1624
	is: function( compare ) {
1625
		var is = color( compare ),
1626
			same = true,
1627
			inst = this;
1628
1629
		each( spaces, function( _, space ) {
1630
			var localCache,
1631
				isCache = is[ space.cache ];
1632
			if ( isCache ) {
1633
				localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
1634
				each( space.props, function( _, prop ) {
1635
					if ( isCache[ prop.idx ] != null ) {
0 ignored issues
show
Best Practice introduced by
Comparing isCache.prop.idx to null using the != operator is not safe. Consider using !== instead.
Loading history...
Complexity Best Practice introduced by
There is no return statement if isCache.prop.idx != null 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...
1636
						same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
1637
						return same;
1638
					}
1639
				} );
1640
			}
1641
			return same;
1642
		} );
1643
		return same;
1644
	},
1645
	_space: function() {
1646
		var used = [],
1647
			inst = this;
1648
		each( spaces, function( spaceName, space ) {
1649
			if ( inst[ space.cache ] ) {
1650
				used.push( spaceName );
1651
			}
1652
		} );
1653
		return used.pop();
1654
	},
1655
	transition: function( other, distance ) {
1656
		var end = color( other ),
1657
			spaceName = end._space(),
1658
			space = spaces[ spaceName ],
1659
			startColor = this.alpha() === 0 ? color( "transparent" ) : this,
1660
			start = startColor[ space.cache ] || space.to( startColor._rgba ),
1661
			result = start.slice();
1662
1663
		end = end[ space.cache ];
1664
		each( space.props, function( key, prop ) {
1665
			var index = prop.idx,
1666
				startValue = start[ index ],
1667
				endValue = end[ index ],
1668
				type = propTypes[ prop.type ] || {};
1669
1670
			// If null, don't override start value
1671
			if ( endValue === null ) {
1672
				return;
1673
			}
1674
1675
			// If null - use end
1676
			if ( startValue === null ) {
1677
				result[ index ] = endValue;
1678
			} else {
1679
				if ( type.mod ) {
1680
					if ( endValue - startValue > type.mod / 2 ) {
1681
						startValue += type.mod;
1682
					} else if ( startValue - endValue > type.mod / 2 ) {
1683
						startValue -= type.mod;
1684
					}
1685
				}
1686
				result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
1687
			}
1688
		} );
1689
		return this[ spaceName ]( result );
1690
	},
1691
	blend: function( opaque ) {
1692
1693
		// If we are already opaque - return ourself
1694
		if ( this._rgba[ 3 ] === 1 ) {
1695
			return this;
1696
		}
1697
1698
		var rgb = this._rgba.slice(),
1699
			a = rgb.pop(),
1700
			blend = color( opaque )._rgba;
1701
1702
		return color( jQuery.map( rgb, function( v, i ) {
1703
			return ( 1 - a ) * blend[ i ] + a * v;
1704
		} ) );
1705
	},
1706
	toRgbaString: function() {
1707
		var prefix = "rgba(",
1708
			rgba = jQuery.map( this._rgba, function( v, i ) {
1709
				return v == null ? ( i > 2 ? 1 : 0 ) : v;
0 ignored issues
show
Best Practice introduced by
Comparing v to null using the == operator is not safe. Consider using === instead.
Loading history...
1710
			} );
1711
1712
		if ( rgba[ 3 ] === 1 ) {
1713
			rgba.pop();
1714
			prefix = "rgb(";
1715
		}
1716
1717
		return prefix + rgba.join() + ")";
1718
	},
1719
	toHslaString: function() {
1720
		var prefix = "hsla(",
1721
			hsla = jQuery.map( this.hsla(), function( v, i ) {
1722
				if ( v == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing v to null using the == operator is not safe. Consider using === instead.
Loading history...
1723
					v = i > 2 ? 1 : 0;
1724
				}
1725
1726
				// Catch 1 and 2
1727
				if ( i && i < 3 ) {
1728
					v = Math.round( v * 100 ) + "%";
1729
				}
1730
				return v;
1731
			} );
1732
1733
		if ( hsla[ 3 ] === 1 ) {
1734
			hsla.pop();
1735
			prefix = "hsl(";
1736
		}
1737
		return prefix + hsla.join() + ")";
1738
	},
1739
	toHexString: function( includeAlpha ) {
1740
		var rgba = this._rgba.slice(),
1741
			alpha = rgba.pop();
1742
1743
		if ( includeAlpha ) {
1744
			rgba.push( ~~( alpha * 255 ) );
1745
		}
1746
1747
		return "#" + jQuery.map( rgba, function( v ) {
1748
1749
			// Default to 0 when nulls exist
1750
			v = ( v || 0 ).toString( 16 );
1751
			return v.length === 1 ? "0" + v : v;
1752
		} ).join( "" );
1753
	},
1754
	toString: function() {
1755
		return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
1756
	}
1757
} );
1758
color.fn.parse.prototype = color.fn;
1759
1760
// Hsla conversions adapted from:
1761
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
1762
1763
function hue2rgb( p, q, h ) {
1764
	h = ( h + 1 ) % 1;
1765
	if ( h * 6 < 1 ) {
1766
		return p + ( q - p ) * h * 6;
1767
	}
1768
	if ( h * 2 < 1 ) {
1769
		return q;
1770
	}
1771
	if ( h * 3 < 2 ) {
1772
		return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
1773
	}
1774
	return p;
1775
}
1776
1777
spaces.hsla.to = function( rgba ) {
1778
	if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing rgba.0 to null using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing rgba.2 to null using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing rgba.1 to null using the == operator is not safe. Consider using === instead.
Loading history...
1779
		return [ null, null, null, rgba[ 3 ] ];
1780
	}
1781
	var r = rgba[ 0 ] / 255,
1782
		g = rgba[ 1 ] / 255,
1783
		b = rgba[ 2 ] / 255,
1784
		a = rgba[ 3 ],
1785
		max = Math.max( r, g, b ),
1786
		min = Math.min( r, g, b ),
1787
		diff = max - min,
1788
		add = max + min,
1789
		l = add * 0.5,
1790
		h, s;
1791
1792
	if ( min === max ) {
1793
		h = 0;
1794
	} else if ( r === max ) {
1795
		h = ( 60 * ( g - b ) / diff ) + 360;
1796
	} else if ( g === max ) {
1797
		h = ( 60 * ( b - r ) / diff ) + 120;
1798
	} else {
1799
		h = ( 60 * ( r - g ) / diff ) + 240;
1800
	}
1801
1802
	// Chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
1803
	// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
1804
	if ( diff === 0 ) {
1805
		s = 0;
1806
	} else if ( l <= 0.5 ) {
1807
		s = diff / add;
1808
	} else {
1809
		s = diff / ( 2 - add );
1810
	}
1811
	return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
0 ignored issues
show
Best Practice introduced by
Comparing a to null using the == operator is not safe. Consider using === instead.
Loading history...
1812
};
1813
1814
spaces.hsla.from = function( hsla ) {
1815
	if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing hsla.1 to null using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing hsla.0 to null using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing hsla.2 to null using the == operator is not safe. Consider using === instead.
Loading history...
1816
		return [ null, null, null, hsla[ 3 ] ];
1817
	}
1818
	var h = hsla[ 0 ] / 360,
1819
		s = hsla[ 1 ],
1820
		l = hsla[ 2 ],
1821
		a = hsla[ 3 ],
1822
		q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
1823
		p = 2 * l - q;
1824
1825
	return [
1826
		Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
1827
		Math.round( hue2rgb( p, q, h ) * 255 ),
1828
		Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
1829
		a
1830
	];
1831
};
1832
1833
each( spaces, function( spaceName, space ) {
1834
	var props = space.props,
1835
		cache = space.cache,
1836
		to = space.to,
1837
		from = space.from;
1838
1839
	// Makes rgba() and hsla()
1840
	color.fn[ spaceName ] = function( value ) {
1841
1842
		// Generate a cache for this space if it doesn't exist
1843
		if ( to && !this[ cache ] ) {
1844
			this[ cache ] = to( this._rgba );
1845
		}
1846
		if ( value === undefined ) {
1847
			return this[ cache ].slice();
1848
		}
1849
1850
		var ret,
1851
			type = jQuery.type( value ),
1852
			arr = ( type === "array" || type === "object" ) ? value : arguments,
1853
			local = this[ cache ].slice();
1854
1855
		each( props, function( key, prop ) {
1856
			var val = arr[ type === "object" ? key : prop.idx ];
1857
			if ( val == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing val to null using the == operator is not safe. Consider using === instead.
Loading history...
1858
				val = local[ prop.idx ];
1859
			}
1860
			local[ prop.idx ] = clamp( val, prop );
1861
		} );
1862
1863
		if ( from ) {
1864
			ret = color( from( local ) );
1865
			ret[ cache ] = local;
1866
			return ret;
1867
		} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
1868
			return color( local );
1869
		}
1870
	};
1871
1872
	// Makes red() green() blue() alpha() hue() saturation() lightness()
1873
	each( props, function( key, prop ) {
1874
1875
		// Alpha is included in more than one space
1876
		if ( color.fn[ key ] ) {
1877
			return;
1878
		}
1879
		color.fn[ key ] = function( value ) {
1880
			var vtype = jQuery.type( value ),
1881
				fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
1882
				local = this[ fn ](),
1883
				cur = local[ prop.idx ],
1884
				match;
1885
1886
			if ( vtype === "undefined" ) {
1887
				return cur;
1888
			}
1889
1890
			if ( vtype === "function" ) {
1891
				value = value.call( this, cur );
1892
				vtype = jQuery.type( value );
1893
			}
1894
			if ( value == null && prop.empty ) {
0 ignored issues
show
Best Practice introduced by
Comparing value to null using the == operator is not safe. Consider using === instead.
Loading history...
1895
				return this;
1896
			}
1897
			if ( vtype === "string" ) {
1898
				match = rplusequals.exec( value );
1899
				if ( match ) {
1900
					value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
1901
				}
1902
			}
1903
			local[ prop.idx ] = value;
1904
			return this[ fn ]( local );
1905
		};
1906
	} );
1907
} );
1908
1909
// Add cssHook and .fx.step function for each named hook.
1910
// accept a space separated string of properties
1911
color.hook = function( hook ) {
1912
	var hooks = hook.split( " " );
1913
	each( hooks, function( i, hook ) {
1914
		jQuery.cssHooks[ hook ] = {
1915
			set: function( elem, value ) {
1916
				var parsed, curElem,
1917
					backgroundColor = "";
1918
1919
				if ( value !== "transparent" && ( jQuery.type( value ) !== "string" ||
1920
						( parsed = stringParse( value ) ) ) ) {
1921
					value = color( parsed || value );
1922
					if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
1923
						curElem = hook === "backgroundColor" ? elem.parentNode : elem;
1924
						while (
1925
							( backgroundColor === "" || backgroundColor === "transparent" ) &&
1926
							curElem && curElem.style
1927
						) {
1928
							try {
1929
								backgroundColor = jQuery.css( curElem, "backgroundColor" );
1930
								curElem = curElem.parentNode;
1931
							} catch ( e ) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
1932
							}
1933
						}
1934
1935
						value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
1936
							backgroundColor :
1937
							"_default" );
1938
					}
1939
1940
					value = value.toRgbaString();
1941
				}
1942
				try {
1943
					elem.style[ hook ] = value;
1944
				} catch ( e ) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
1945
1946
					// Wrapped to prevent IE from throwing errors on "invalid" values like
1947
					// 'auto' or 'inherit'
1948
				}
1949
			}
1950
		};
1951
		jQuery.fx.step[ hook ] = function( fx ) {
1952
			if ( !fx.colorInit ) {
1953
				fx.start = color( fx.elem, hook );
1954
				fx.end = color( fx.end );
1955
				fx.colorInit = true;
1956
			}
1957
			jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
1958
		};
1959
	} );
1960
1961
};
1962
1963
color.hook( stepHooks );
1964
1965
jQuery.cssHooks.borderColor = {
1966
	expand: function( value ) {
1967
		var expanded = {};
1968
1969
		each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
1970
			expanded[ "border" + part + "Color" ] = value;
1971
		} );
1972
		return expanded;
1973
	}
1974
};
1975
1976
// Basic color names only.
1977
// Usage of any of the other color names requires adding yourself or including
1978
// jquery.color.svg-names.js.
1979
colors = jQuery.Color.names = {
1980
1981
	// 4.1. Basic color keywords
1982
	aqua: "#00ffff",
1983
	black: "#000000",
1984
	blue: "#0000ff",
1985
	fuchsia: "#ff00ff",
1986
	gray: "#808080",
1987
	green: "#008000",
1988
	lime: "#00ff00",
1989
	maroon: "#800000",
1990
	navy: "#000080",
1991
	olive: "#808000",
1992
	purple: "#800080",
1993
	red: "#ff0000",
1994
	silver: "#c0c0c0",
1995
	teal: "#008080",
1996
	white: "#ffffff",
1997
	yellow: "#ffff00",
1998
1999
	// 4.2.3. "transparent" color keyword
2000
	transparent: [ null, null, null, 0 ],
2001
2002
	_default: "#ffffff"
2003
};
2004
2005
} )( jQuery );
2006
2007
/******************************************************************************/
2008
/****************************** CLASS ANIMATIONS ******************************/
2009
/******************************************************************************/
2010
( function() {
2011
2012
var classAnimationActions = [ "add", "remove", "toggle" ],
2013
	shorthandStyles = {
2014
		border: 1,
2015
		borderBottom: 1,
2016
		borderColor: 1,
2017
		borderLeft: 1,
2018
		borderRight: 1,
2019
		borderTop: 1,
2020
		borderWidth: 1,
2021
		margin: 1,
2022
		padding: 1
2023
	};
2024
2025
$.each(
2026
	[ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
2027
	function( _, prop ) {
2028
		$.fx.step[ prop ] = function( fx ) {
2029
			if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
2030
				jQuery.style( fx.elem, prop, fx.end );
2031
				fx.setAttr = true;
2032
			}
2033
		};
2034
	}
2035
);
2036
2037
function getElementStyles( elem ) {
2038
	var key, len,
2039
		style = elem.ownerDocument.defaultView ?
2040
			elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
2041
			elem.currentStyle,
2042
		styles = {};
2043
2044
	if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
2045
		len = style.length;
2046
		while ( len-- ) {
2047
			key = style[ len ];
2048
			if ( typeof style[ key ] === "string" ) {
2049
				styles[ $.camelCase( key ) ] = style[ key ];
2050
			}
2051
		}
2052
2053
	// Support: Opera, IE <9
2054
	} else {
2055
		for ( key in style ) {
2056
			if ( typeof style[ key ] === "string" ) {
2057
				styles[ key ] = style[ key ];
2058
			}
2059
		}
2060
	}
2061
2062
	return styles;
2063
}
2064
2065
function styleDifference( oldStyle, newStyle ) {
2066
	var diff = {},
2067
		name, value;
2068
2069
	for ( name in newStyle ) {
2070
		value = newStyle[ name ];
2071
		if ( oldStyle[ name ] !== value ) {
2072
			if ( !shorthandStyles[ name ] ) {
2073
				if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
2074
					diff[ name ] = value;
2075
				}
2076
			}
2077
		}
2078
	}
2079
2080
	return diff;
2081
}
2082
2083
// Support: jQuery <1.8
2084
if ( !$.fn.addBack ) {
2085
	$.fn.addBack = function( selector ) {
2086
		return this.add( selector == null ?
0 ignored issues
show
Best Practice introduced by
Comparing selector to null using the == operator is not safe. Consider using === instead.
Loading history...
2087
			this.prevObject : this.prevObject.filter( selector )
2088
		);
2089
	};
2090
}
2091
2092
$.effects.animateClass = function( value, duration, easing, callback ) {
2093
	var o = $.speed( duration, easing, callback );
2094
2095
	return this.queue( function() {
2096
		var animated = $( this ),
2097
			baseClass = animated.attr( "class" ) || "",
2098
			applyClassChange,
2099
			allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
2100
2101
		// Map the animated objects to store the original styles.
2102
		allAnimations = allAnimations.map( function() {
2103
			var el = $( this );
2104
			return {
2105
				el: el,
2106
				start: getElementStyles( this )
2107
			};
2108
		} );
2109
2110
		// Apply class change
2111
		applyClassChange = function() {
2112
			$.each( classAnimationActions, function( i, action ) {
2113
				if ( value[ action ] ) {
2114
					animated[ action + "Class" ]( value[ action ] );
2115
				}
2116
			} );
2117
		};
2118
		applyClassChange();
2119
2120
		// Map all animated objects again - calculate new styles and diff
2121
		allAnimations = allAnimations.map( function() {
2122
			this.end = getElementStyles( this.el[ 0 ] );
2123
			this.diff = styleDifference( this.start, this.end );
2124
			return this;
2125
		} );
2126
2127
		// Apply original class
2128
		animated.attr( "class", baseClass );
2129
2130
		// Map all animated objects again - this time collecting a promise
2131
		allAnimations = allAnimations.map( function() {
2132
			var styleInfo = this,
2133
				dfd = $.Deferred(),
2134
				opts = $.extend( {}, o, {
2135
					queue: false,
2136
					complete: function() {
2137
						dfd.resolve( styleInfo );
2138
					}
2139
				} );
2140
2141
			this.el.animate( this.diff, opts );
2142
			return dfd.promise();
2143
		} );
2144
2145
		// Once all animations have completed:
2146
		$.when.apply( $, allAnimations.get() ).done( function() {
2147
2148
			// Set the final class
2149
			applyClassChange();
2150
2151
			// For each animated element,
2152
			// clear all css properties that were animated
2153
			$.each( arguments, function() {
2154
				var el = this.el;
2155
				$.each( this.diff, function( key ) {
2156
					el.css( key, "" );
2157
				} );
2158
			} );
2159
2160
			// This is guarnteed to be there if you use jQuery.speed()
2161
			// it also handles dequeuing the next anim...
2162
			o.complete.call( animated[ 0 ] );
2163
		} );
2164
	} );
2165
};
2166
2167
$.fn.extend( {
2168
	addClass: ( function( orig ) {
2169
		return function( classNames, speed, easing, callback ) {
2170
			return speed ?
2171
				$.effects.animateClass.call( this,
2172
					{ add: classNames }, speed, easing, callback ) :
2173
				orig.apply( this, arguments );
2174
		};
2175
	} )( $.fn.addClass ),
2176
2177
	removeClass: ( function( orig ) {
2178
		return function( classNames, speed, easing, callback ) {
2179
			return arguments.length > 1 ?
2180
				$.effects.animateClass.call( this,
2181
					{ remove: classNames }, speed, easing, callback ) :
2182
				orig.apply( this, arguments );
2183
		};
2184
	} )( $.fn.removeClass ),
2185
2186
	toggleClass: ( function( orig ) {
2187
		return function( classNames, force, speed, easing, callback ) {
2188
			if ( typeof force === "boolean" || force === undefined ) {
2189
				if ( !speed ) {
2190
2191
					// Without speed parameter
2192
					return orig.apply( this, arguments );
2193
				} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
2194
					return $.effects.animateClass.call( this,
2195
						( force ? { add: classNames } : { remove: classNames } ),
2196
						speed, easing, callback );
2197
				}
2198
			} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
2199
2200
				// Without force parameter
2201
				return $.effects.animateClass.call( this,
2202
					{ toggle: classNames }, force, speed, easing );
2203
			}
2204
		};
2205
	} )( $.fn.toggleClass ),
2206
2207
	switchClass: function( remove, add, speed, easing, callback ) {
2208
		return $.effects.animateClass.call( this, {
2209
			add: add,
2210
			remove: remove
2211
		}, speed, easing, callback );
2212
	}
2213
} );
2214
2215
} )();
2216
2217
/******************************************************************************/
2218
/*********************************** EFFECTS **********************************/
2219
/******************************************************************************/
2220
2221
( function() {
2222
2223
if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
2224
	$.expr.filters.animated = ( function( orig ) {
2225
		return function( elem ) {
2226
			return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
2227
		};
2228
	} )( $.expr.filters.animated );
2229
}
2230
2231
if ( $.uiBackCompat !== false ) {
2232
	$.extend( $.effects, {
2233
2234
		// Saves a set of properties in a data storage
2235
		save: function( element, set ) {
2236
			var i = 0, length = set.length;
2237
			for ( ; i < length; i++ ) {
2238
				if ( set[ i ] !== null ) {
2239
					element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
2240
				}
2241
			}
2242
		},
2243
2244
		// Restores a set of previously saved properties from a data storage
2245
		restore: function( element, set ) {
2246
			var val, i = 0, length = set.length;
2247
			for ( ; i < length; i++ ) {
2248
				if ( set[ i ] !== null ) {
2249
					val = element.data( dataSpace + set[ i ] );
2250
					element.css( set[ i ], val );
2251
				}
2252
			}
2253
		},
2254
2255
		setMode: function( el, mode ) {
2256
			if ( mode === "toggle" ) {
2257
				mode = el.is( ":hidden" ) ? "show" : "hide";
2258
			}
2259
			return mode;
2260
		},
2261
2262
		// Wraps the element around a wrapper that copies position properties
2263
		createWrapper: function( element ) {
2264
2265
			// If the element is already wrapped, return it
2266
			if ( element.parent().is( ".ui-effects-wrapper" ) ) {
2267
				return element.parent();
2268
			}
2269
2270
			// Wrap the element
2271
			var props = {
2272
					width: element.outerWidth( true ),
2273
					height: element.outerHeight( true ),
2274
					"float": element.css( "float" )
2275
				},
2276
				wrapper = $( "<div></div>" )
2277
					.addClass( "ui-effects-wrapper" )
2278
					.css( {
2279
						fontSize: "100%",
2280
						background: "transparent",
2281
						border: "none",
2282
						margin: 0,
2283
						padding: 0
2284
					} ),
2285
2286
				// Store the size in case width/height are defined in % - Fixes #5245
2287
				size = {
2288
					width: element.width(),
2289
					height: element.height()
2290
				},
2291
				active = document.activeElement;
2292
2293
			// Support: Firefox
2294
			// Firefox incorrectly exposes anonymous content
2295
			// https://bugzilla.mozilla.org/show_bug.cgi?id=561664
2296
			try {
2297
				active.id;
0 ignored issues
show
introduced by
The result of the property access to active.id is not used.
Loading history...
2298
			} catch ( e ) {
2299
				active = document.body;
2300
			}
2301
2302
			element.wrap( wrapper );
2303
2304
			// Fixes #7595 - Elements lose focus when wrapped.
2305
			if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
2306
				$( active ).trigger( "focus" );
2307
			}
2308
2309
			// Hotfix for jQuery 1.4 since some change in wrap() seems to actually
2310
			// lose the reference to the wrapped element
2311
			wrapper = element.parent();
2312
2313
			// Transfer positioning properties to the wrapper
2314
			if ( element.css( "position" ) === "static" ) {
2315
				wrapper.css( { position: "relative" } );
2316
				element.css( { position: "relative" } );
2317
			} else {
2318
				$.extend( props, {
2319
					position: element.css( "position" ),
2320
					zIndex: element.css( "z-index" )
2321
				} );
2322
				$.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
2323
					props[ pos ] = element.css( pos );
2324
					if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
2325
						props[ pos ] = "auto";
2326
					}
2327
				} );
2328
				element.css( {
2329
					position: "relative",
2330
					top: 0,
2331
					left: 0,
2332
					right: "auto",
2333
					bottom: "auto"
2334
				} );
2335
			}
2336
			element.css( size );
2337
2338
			return wrapper.css( props ).show();
2339
		},
2340
2341
		removeWrapper: function( element ) {
2342
			var active = document.activeElement;
2343
2344
			if ( element.parent().is( ".ui-effects-wrapper" ) ) {
2345
				element.parent().replaceWith( element );
2346
2347
				// Fixes #7595 - Elements lose focus when wrapped.
2348
				if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
2349
					$( active ).trigger( "focus" );
2350
				}
2351
			}
2352
2353
			return element;
2354
		}
2355
	} );
2356
}
2357
2358
$.extend( $.effects, {
2359
	version: "1.12.1",
2360
2361
	define: function( name, mode, effect ) {
2362
		if ( !effect ) {
2363
			effect = mode;
2364
			mode = "effect";
2365
		}
2366
2367
		$.effects.effect[ name ] = effect;
2368
		$.effects.effect[ name ].mode = mode;
2369
2370
		return effect;
2371
	},
2372
2373
	scaledDimensions: function( element, percent, direction ) {
2374
		if ( percent === 0 ) {
2375
			return {
2376
				height: 0,
2377
				width: 0,
2378
				outerHeight: 0,
2379
				outerWidth: 0
2380
			};
2381
		}
2382
2383
		var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
2384
			y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
2385
2386
		return {
2387
			height: element.height() * y,
2388
			width: element.width() * x,
2389
			outerHeight: element.outerHeight() * y,
2390
			outerWidth: element.outerWidth() * x
2391
		};
2392
2393
	},
2394
2395
	clipToBox: function( animation ) {
2396
		return {
2397
			width: animation.clip.right - animation.clip.left,
2398
			height: animation.clip.bottom - animation.clip.top,
2399
			left: animation.clip.left,
2400
			top: animation.clip.top
2401
		};
2402
	},
2403
2404
	// Injects recently queued functions to be first in line (after "inprogress")
2405
	unshift: function( element, queueLength, count ) {
2406
		var queue = element.queue();
2407
2408
		if ( queueLength > 1 ) {
2409
			queue.splice.apply( queue,
2410
				[ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
2411
		}
2412
		element.dequeue();
2413
	},
2414
2415
	saveStyle: function( element ) {
2416
		element.data( dataSpaceStyle, element[ 0 ].style.cssText );
2417
	},
2418
2419
	restoreStyle: function( element ) {
2420
		element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
2421
		element.removeData( dataSpaceStyle );
2422
	},
2423
2424
	mode: function( element, mode ) {
2425
		var hidden = element.is( ":hidden" );
2426
2427
		if ( mode === "toggle" ) {
2428
			mode = hidden ? "show" : "hide";
2429
		}
2430
		if ( hidden ? mode === "hide" : mode === "show" ) {
2431
			mode = "none";
2432
		}
2433
		return mode;
2434
	},
2435
2436
	// Translates a [top,left] array into a baseline value
2437
	getBaseline: function( origin, original ) {
2438
		var y, x;
2439
2440
		switch ( origin[ 0 ] ) {
2441
		case "top":
2442
			y = 0;
2443
			break;
2444
		case "middle":
2445
			y = 0.5;
2446
			break;
2447
		case "bottom":
2448
			y = 1;
2449
			break;
2450
		default:
2451
			y = origin[ 0 ] / original.height;
2452
		}
2453
2454
		switch ( origin[ 1 ] ) {
2455
		case "left":
2456
			x = 0;
2457
			break;
2458
		case "center":
2459
			x = 0.5;
2460
			break;
2461
		case "right":
2462
			x = 1;
2463
			break;
2464
		default:
2465
			x = origin[ 1 ] / original.width;
2466
		}
2467
2468
		return {
2469
			x: x,
2470
			y: y
2471
		};
2472
	},
2473
2474
	// Creates a placeholder element so that the original element can be made absolute
2475
	createPlaceholder: function( element ) {
2476
		var placeholder,
2477
			cssPosition = element.css( "position" ),
2478
			position = element.position();
2479
2480
		// Lock in margins first to account for form elements, which
2481
		// will change margin if you explicitly set height
2482
		// see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
2483
		// Support: Safari
2484
		element.css( {
2485
			marginTop: element.css( "marginTop" ),
2486
			marginBottom: element.css( "marginBottom" ),
2487
			marginLeft: element.css( "marginLeft" ),
2488
			marginRight: element.css( "marginRight" )
2489
		} )
2490
		.outerWidth( element.outerWidth() )
2491
		.outerHeight( element.outerHeight() );
2492
2493
		if ( /^(static|relative)/.test( cssPosition ) ) {
2494
			cssPosition = "absolute";
2495
2496
			placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
2497
2498
				// Convert inline to inline block to account for inline elements
2499
				// that turn to inline block based on content (like img)
2500
				display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
2501
					"inline-block" :
2502
					"block",
2503
				visibility: "hidden",
2504
2505
				// Margins need to be set to account for margin collapse
2506
				marginTop: element.css( "marginTop" ),
2507
				marginBottom: element.css( "marginBottom" ),
2508
				marginLeft: element.css( "marginLeft" ),
2509
				marginRight: element.css( "marginRight" ),
2510
				"float": element.css( "float" )
2511
			} )
2512
			.outerWidth( element.outerWidth() )
2513
			.outerHeight( element.outerHeight() )
2514
			.addClass( "ui-effects-placeholder" );
2515
2516
			element.data( dataSpace + "placeholder", placeholder );
2517
		}
2518
2519
		element.css( {
2520
			position: cssPosition,
2521
			left: position.left,
2522
			top: position.top
2523
		} );
2524
2525
		return placeholder;
0 ignored issues
show
Bug introduced by
The variable placeholder does not seem to be initialized in case ^(static|relative).test(cssPosition) on line 2493 is false. Are you sure this can never be the case?
Loading history...
2526
	},
2527
2528
	removePlaceholder: function( element ) {
2529
		var dataKey = dataSpace + "placeholder",
2530
				placeholder = element.data( dataKey );
2531
2532
		if ( placeholder ) {
2533
			placeholder.remove();
2534
			element.removeData( dataKey );
2535
		}
2536
	},
2537
2538
	// Removes a placeholder if it exists and restores
2539
	// properties that were modified during placeholder creation
2540
	cleanUp: function( element ) {
2541
		$.effects.restoreStyle( element );
2542
		$.effects.removePlaceholder( element );
2543
	},
2544
2545
	setTransition: function( element, list, factor, value ) {
2546
		value = value || {};
2547
		$.each( list, function( i, x ) {
2548
			var unit = element.cssUnit( x );
2549
			if ( unit[ 0 ] > 0 ) {
2550
				value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
2551
			}
2552
		} );
2553
		return value;
2554
	}
2555
} );
2556
2557
// Return an effect options object for the given parameters:
2558
function _normalizeArguments( effect, options, speed, callback ) {
2559
2560
	// Allow passing all options as the first parameter
2561
	if ( $.isPlainObject( effect ) ) {
2562
		options = effect;
2563
		effect = effect.effect;
2564
	}
2565
2566
	// Convert to an object
2567
	effect = { effect: effect };
2568
2569
	// Catch (effect, null, ...)
2570
	if ( options == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing options to null using the == operator is not safe. Consider using === instead.
Loading history...
2571
		options = {};
2572
	}
2573
2574
	// Catch (effect, callback)
2575
	if ( $.isFunction( options ) ) {
2576
		callback = options;
2577
		speed = null;
2578
		options = {};
2579
	}
2580
2581
	// Catch (effect, speed, ?)
2582
	if ( typeof options === "number" || $.fx.speeds[ options ] ) {
2583
		callback = speed;
2584
		speed = options;
2585
		options = {};
2586
	}
2587
2588
	// Catch (effect, options, callback)
2589
	if ( $.isFunction( speed ) ) {
2590
		callback = speed;
2591
		speed = null;
2592
	}
2593
2594
	// Add options to effect
2595
	if ( options ) {
2596
		$.extend( effect, options );
2597
	}
2598
2599
	speed = speed || options.duration;
2600
	effect.duration = $.fx.off ? 0 :
2601
		typeof speed === "number" ? speed :
2602
		speed in $.fx.speeds ? $.fx.speeds[ speed ] :
2603
		$.fx.speeds._default;
2604
2605
	effect.complete = callback || options.complete;
2606
2607
	return effect;
2608
}
2609
2610
function standardAnimationOption( option ) {
2611
2612
	// Valid standard speeds (nothing, number, named speed)
2613
	if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
2614
		return true;
2615
	}
2616
2617
	// Invalid strings - treat as "normal" speed
2618
	if ( typeof option === "string" && !$.effects.effect[ option ] ) {
2619
		return true;
2620
	}
2621
2622
	// Complete callback
2623
	if ( $.isFunction( option ) ) {
2624
		return true;
2625
	}
2626
2627
	// Options hash (but not naming an effect)
2628
	if ( typeof option === "object" && !option.effect ) {
2629
		return true;
2630
	}
2631
2632
	// Didn't match any standard API
2633
	return false;
2634
}
2635
2636
$.fn.extend( {
2637
	effect: function( /* effect, options, speed, callback */ ) {
2638
		var args = _normalizeArguments.apply( this, arguments ),
2639
			effectMethod = $.effects.effect[ args.effect ],
2640
			defaultMode = effectMethod.mode,
2641
			queue = args.queue,
2642
			queueName = queue || "fx",
2643
			complete = args.complete,
2644
			mode = args.mode,
2645
			modes = [],
2646
			prefilter = function( next ) {
2647
				var el = $( this ),
2648
					normalizedMode = $.effects.mode( el, mode ) || defaultMode;
2649
2650
				// Sentinel for duck-punching the :animated psuedo-selector
2651
				el.data( dataSpaceAnimated, true );
2652
2653
				// Save effect mode for later use,
2654
				// we can't just call $.effects.mode again later,
2655
				// as the .show() below destroys the initial state
2656
				modes.push( normalizedMode );
2657
2658
				// See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
2659
				if ( defaultMode && ( normalizedMode === "show" ||
2660
						( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
2661
					el.show();
2662
				}
2663
2664
				if ( !defaultMode || normalizedMode !== "none" ) {
2665
					$.effects.saveStyle( el );
2666
				}
2667
2668
				if ( $.isFunction( next ) ) {
2669
					next();
2670
				}
2671
			};
2672
2673
		if ( $.fx.off || !effectMethod ) {
2674
2675
			// Delegate to the original method (e.g., .show()) if possible
2676
			if ( mode ) {
2677
				return this[ mode ]( args.duration, complete );
2678
			} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
2679
				return this.each( function() {
2680
					if ( complete ) {
2681
						complete.call( this );
2682
					}
2683
				} );
2684
			}
2685
		}
2686
2687
		function run( next ) {
2688
			var elem = $( this );
2689
2690
			function cleanup() {
2691
				elem.removeData( dataSpaceAnimated );
2692
2693
				$.effects.cleanUp( elem );
2694
2695
				if ( args.mode === "hide" ) {
2696
					elem.hide();
2697
				}
2698
2699
				done();
2700
			}
2701
2702
			function done() {
2703
				if ( $.isFunction( complete ) ) {
2704
					complete.call( elem[ 0 ] );
2705
				}
2706
2707
				if ( $.isFunction( next ) ) {
2708
					next();
2709
				}
2710
			}
2711
2712
			// Override mode option on a per element basis,
2713
			// as toggle can be either show or hide depending on element state
2714
			args.mode = modes.shift();
2715
2716
			if ( $.uiBackCompat !== false && !defaultMode ) {
2717
				if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
2718
2719
					// Call the core method to track "olddisplay" properly
2720
					elem[ mode ]();
2721
					done();
2722
				} else {
2723
					effectMethod.call( elem[ 0 ], args, done );
2724
				}
2725
			} else {
2726
				if ( args.mode === "none" ) {
2727
2728
					// Call the core method to track "olddisplay" properly
2729
					elem[ mode ]();
2730
					done();
2731
				} else {
2732
					effectMethod.call( elem[ 0 ], args, cleanup );
2733
				}
2734
			}
2735
		}
2736
2737
		// Run prefilter on all elements first to ensure that
2738
		// any showing or hiding happens before placeholder creation,
2739
		// which ensures that any layout changes are correctly captured.
2740
		return queue === false ?
2741
			this.each( prefilter ).each( run ) :
2742
			this.queue( queueName, prefilter ).queue( queueName, run );
2743
	},
2744
2745
	show: ( function( orig ) {
2746
		return function( option ) {
2747
			if ( standardAnimationOption( option ) ) {
2748
				return orig.apply( this, arguments );
2749
			} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
2750
				var args = _normalizeArguments.apply( this, arguments );
2751
				args.mode = "show";
2752
				return this.effect.call( this, args );
2753
			}
2754
		};
2755
	} )( $.fn.show ),
2756
2757
	hide: ( function( orig ) {
2758
		return function( option ) {
2759
			if ( standardAnimationOption( option ) ) {
2760
				return orig.apply( this, arguments );
2761
			} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
2762
				var args = _normalizeArguments.apply( this, arguments );
2763
				args.mode = "hide";
2764
				return this.effect.call( this, args );
2765
			}
2766
		};
2767
	} )( $.fn.hide ),
2768
2769
	toggle: ( function( orig ) {
2770
		return function( option ) {
2771
			if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
2772
				return orig.apply( this, arguments );
2773
			} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
2774
				var args = _normalizeArguments.apply( this, arguments );
2775
				args.mode = "toggle";
2776
				return this.effect.call( this, args );
2777
			}
2778
		};
2779
	} )( $.fn.toggle ),
2780
2781
	cssUnit: function( key ) {
2782
		var style = this.css( key ),
2783
			val = [];
2784
2785
		$.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
2786
			if ( style.indexOf( unit ) > 0 ) {
2787
				val = [ parseFloat( style ), unit ];
2788
			}
2789
		} );
2790
		return val;
2791
	},
2792
2793
	cssClip: function( clipObj ) {
2794
		if ( clipObj ) {
2795
			return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
2796
				clipObj.bottom + "px " + clipObj.left + "px)" );
2797
		}
2798
		return parseClip( this.css( "clip" ), this );
2799
	},
2800
2801
	transfer: function( options, done ) {
2802
		var element = $( this ),
2803
			target = $( options.to ),
2804
			targetFixed = target.css( "position" ) === "fixed",
2805
			body = $( "body" ),
2806
			fixTop = targetFixed ? body.scrollTop() : 0,
2807
			fixLeft = targetFixed ? body.scrollLeft() : 0,
2808
			endPosition = target.offset(),
2809
			animation = {
2810
				top: endPosition.top - fixTop,
2811
				left: endPosition.left - fixLeft,
2812
				height: target.innerHeight(),
2813
				width: target.innerWidth()
2814
			},
2815
			startPosition = element.offset(),
2816
			transfer = $( "<div class='ui-effects-transfer'></div>" )
2817
				.appendTo( "body" )
2818
				.addClass( options.className )
2819
				.css( {
2820
					top: startPosition.top - fixTop,
2821
					left: startPosition.left - fixLeft,
2822
					height: element.innerHeight(),
2823
					width: element.innerWidth(),
2824
					position: targetFixed ? "fixed" : "absolute"
2825
				} )
2826
				.animate( animation, options.duration, options.easing, function() {
2827
					transfer.remove();
2828
					if ( $.isFunction( done ) ) {
2829
						done();
2830
					}
2831
				} );
2832
	}
2833
} );
2834
2835
function parseClip( str, element ) {
2836
		var outerWidth = element.outerWidth(),
2837
			outerHeight = element.outerHeight(),
2838
			clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
2839
			values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
2840
2841
		return {
2842
			top: parseFloat( values[ 1 ] ) || 0,
2843
			right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
2844
			bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
2845
			left: parseFloat( values[ 4 ] ) || 0
2846
		};
2847
}
2848
2849
$.fx.step.clip = function( fx ) {
2850
	if ( !fx.clipInit ) {
2851
		fx.start = $( fx.elem ).cssClip();
2852
		if ( typeof fx.end === "string" ) {
2853
			fx.end = parseClip( fx.end, fx.elem );
2854
		}
2855
		fx.clipInit = true;
2856
	}
2857
2858
	$( fx.elem ).cssClip( {
2859
		top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
2860
		right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
2861
		bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
2862
		left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
2863
	} );
2864
};
2865
2866
} )();
2867
2868
/******************************************************************************/
2869
/*********************************** EASING ***********************************/
2870
/******************************************************************************/
2871
2872
( function() {
2873
2874
// Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
2875
2876
var baseEasings = {};
2877
2878
$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
2879
	baseEasings[ name ] = function( p ) {
2880
		return Math.pow( p, i + 2 );
2881
	};
2882
} );
2883
2884
$.extend( baseEasings, {
2885
	Sine: function( p ) {
2886
		return 1 - Math.cos( p * Math.PI / 2 );
2887
	},
2888
	Circ: function( p ) {
2889
		return 1 - Math.sqrt( 1 - p * p );
2890
	},
2891
	Elastic: function( p ) {
2892
		return p === 0 || p === 1 ? p :
2893
			-Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
2894
	},
2895
	Back: function( p ) {
2896
		return p * p * ( 3 * p - 2 );
2897
	},
2898
	Bounce: function( p ) {
2899
		var pow2,
2900
			bounce = 4;
2901
2902
		while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
2903
		return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
2904
	}
2905
} );
2906
2907
$.each( baseEasings, function( name, easeIn ) {
2908
	$.easing[ "easeIn" + name ] = easeIn;
2909
	$.easing[ "easeOut" + name ] = function( p ) {
2910
		return 1 - easeIn( 1 - p );
2911
	};
2912
	$.easing[ "easeInOut" + name ] = function( p ) {
2913
		return p < 0.5 ?
2914
			easeIn( p * 2 ) / 2 :
2915
			1 - easeIn( p * -2 + 2 ) / 2;
2916
	};
2917
} );
2918
2919
} )();
2920
2921
var effect = $.effects;
2922
2923
2924
/*!
2925
 * jQuery UI Effects Blind 1.12.1
2926
 * http://jqueryui.com
2927
 *
2928
 * Copyright jQuery Foundation and other contributors
2929
 * Released under the MIT license.
2930
 * http://jquery.org/license
2931
 */
2932
2933
//>>label: Blind Effect
2934
//>>group: Effects
2935
//>>description: Blinds the element.
2936
//>>docs: http://api.jqueryui.com/blind-effect/
2937
//>>demos: http://jqueryui.com/effect/
2938
2939
2940
2941
var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectBlind seems to be never used. Consider removing it.
Loading history...
2942
	var map = {
2943
			up: [ "bottom", "top" ],
2944
			vertical: [ "bottom", "top" ],
2945
			down: [ "top", "bottom" ],
2946
			left: [ "right", "left" ],
2947
			horizontal: [ "right", "left" ],
2948
			right: [ "left", "right" ]
2949
		},
2950
		element = $( this ),
2951
		direction = options.direction || "up",
2952
		start = element.cssClip(),
2953
		animate = { clip: $.extend( {}, start ) },
2954
		placeholder = $.effects.createPlaceholder( element );
2955
2956
	animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
2957
2958
	if ( options.mode === "show" ) {
2959
		element.cssClip( animate.clip );
2960
		if ( placeholder ) {
2961
			placeholder.css( $.effects.clipToBox( animate ) );
2962
		}
2963
2964
		animate.clip = start;
2965
	}
2966
2967
	if ( placeholder ) {
2968
		placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
2969
	}
2970
2971
	element.animate( animate, {
2972
		queue: false,
2973
		duration: options.duration,
2974
		easing: options.easing,
2975
		complete: done
2976
	} );
2977
} );
2978
2979
2980
/*!
2981
 * jQuery UI Effects Bounce 1.12.1
2982
 * http://jqueryui.com
2983
 *
2984
 * Copyright jQuery Foundation and other contributors
2985
 * Released under the MIT license.
2986
 * http://jquery.org/license
2987
 */
2988
2989
//>>label: Bounce Effect
2990
//>>group: Effects
2991
//>>description: Bounces an element horizontally or vertically n times.
2992
//>>docs: http://api.jqueryui.com/bounce-effect/
2993
//>>demos: http://jqueryui.com/effect/
2994
2995
2996
2997
var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectBounce seems to be never used. Consider removing it.
Loading history...
2998
	var upAnim, downAnim, refValue,
2999
		element = $( this ),
3000
3001
		// Defaults:
3002
		mode = options.mode,
3003
		hide = mode === "hide",
3004
		show = mode === "show",
3005
		direction = options.direction || "up",
3006
		distance = options.distance,
3007
		times = options.times || 5,
3008
3009
		// Number of internal animations
3010
		anims = times * 2 + ( show || hide ? 1 : 0 ),
3011
		speed = options.duration / anims,
3012
		easing = options.easing,
3013
3014
		// Utility:
3015
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3016
		motion = ( direction === "up" || direction === "left" ),
3017
		i = 0,
3018
3019
		queuelen = element.queue().length;
3020
3021
	$.effects.createPlaceholder( element );
3022
3023
	refValue = element.css( ref );
3024
3025
	// Default distance for the BIGGEST bounce is the outer Distance / 3
3026
	if ( !distance ) {
3027
		distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
3028
	}
3029
3030
	if ( show ) {
3031
		downAnim = { opacity: 1 };
3032
		downAnim[ ref ] = refValue;
3033
3034
		// If we are showing, force opacity 0 and set the initial position
3035
		// then do the "first" animation
3036
		element
3037
			.css( "opacity", 0 )
3038
			.css( ref, motion ? -distance * 2 : distance * 2 )
3039
			.animate( downAnim, speed, easing );
3040
	}
3041
3042
	// Start at the smallest distance if we are hiding
3043
	if ( hide ) {
3044
		distance = distance / Math.pow( 2, times - 1 );
3045
	}
3046
3047
	downAnim = {};
3048
	downAnim[ ref ] = refValue;
3049
3050
	// Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
3051
	for ( ; i < times; i++ ) {
3052
		upAnim = {};
3053
		upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
3054
3055
		element
3056
			.animate( upAnim, speed, easing )
3057
			.animate( downAnim, speed, easing );
3058
3059
		distance = hide ? distance * 2 : distance / 2;
3060
	}
3061
3062
	// Last Bounce when Hiding
3063
	if ( hide ) {
3064
		upAnim = { opacity: 0 };
3065
		upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
3066
3067
		element.animate( upAnim, speed, easing );
3068
	}
3069
3070
	element.queue( done );
3071
3072
	$.effects.unshift( element, queuelen, anims + 1 );
3073
} );
3074
3075
3076
/*!
3077
 * jQuery UI Effects Clip 1.12.1
3078
 * http://jqueryui.com
3079
 *
3080
 * Copyright jQuery Foundation and other contributors
3081
 * Released under the MIT license.
3082
 * http://jquery.org/license
3083
 */
3084
3085
//>>label: Clip Effect
3086
//>>group: Effects
3087
//>>description: Clips the element on and off like an old TV.
3088
//>>docs: http://api.jqueryui.com/clip-effect/
3089
//>>demos: http://jqueryui.com/effect/
3090
3091
3092
3093
var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectClip seems to be never used. Consider removing it.
Loading history...
3094
	var start,
3095
		animate = {},
3096
		element = $( this ),
3097
		direction = options.direction || "vertical",
3098
		both = direction === "both",
3099
		horizontal = both || direction === "horizontal",
3100
		vertical = both || direction === "vertical";
3101
3102
	start = element.cssClip();
3103
	animate.clip = {
3104
		top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
3105
		right: horizontal ? ( start.right - start.left ) / 2 : start.right,
3106
		bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
3107
		left: horizontal ? ( start.right - start.left ) / 2 : start.left
3108
	};
3109
3110
	$.effects.createPlaceholder( element );
3111
3112
	if ( options.mode === "show" ) {
3113
		element.cssClip( animate.clip );
3114
		animate.clip = start;
3115
	}
3116
3117
	element.animate( animate, {
3118
		queue: false,
3119
		duration: options.duration,
3120
		easing: options.easing,
3121
		complete: done
3122
	} );
3123
3124
} );
3125
3126
3127
/*!
3128
 * jQuery UI Effects Drop 1.12.1
3129
 * http://jqueryui.com
3130
 *
3131
 * Copyright jQuery Foundation and other contributors
3132
 * Released under the MIT license.
3133
 * http://jquery.org/license
3134
 */
3135
3136
//>>label: Drop Effect
3137
//>>group: Effects
3138
//>>description: Moves an element in one direction and hides it at the same time.
3139
//>>docs: http://api.jqueryui.com/drop-effect/
3140
//>>demos: http://jqueryui.com/effect/
3141
3142
3143
3144
var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectDrop seems to be never used. Consider removing it.
Loading history...
3145
3146
	var distance,
3147
		element = $( this ),
3148
		mode = options.mode,
3149
		show = mode === "show",
3150
		direction = options.direction || "left",
3151
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3152
		motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
3153
		oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
3154
		animation = {
3155
			opacity: 0
3156
		};
3157
3158
	$.effects.createPlaceholder( element );
3159
3160
	distance = options.distance ||
3161
		element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
3162
3163
	animation[ ref ] = motion + distance;
3164
3165
	if ( show ) {
3166
		element.css( animation );
3167
3168
		animation[ ref ] = oppositeMotion + distance;
3169
		animation.opacity = 1;
3170
	}
3171
3172
	// Animate
3173
	element.animate( animation, {
3174
		queue: false,
3175
		duration: options.duration,
3176
		easing: options.easing,
3177
		complete: done
3178
	} );
3179
} );
3180
3181
3182
/*!
3183
 * jQuery UI Effects Explode 1.12.1
3184
 * http://jqueryui.com
3185
 *
3186
 * Copyright jQuery Foundation and other contributors
3187
 * Released under the MIT license.
3188
 * http://jquery.org/license
3189
 */
3190
3191
//>>label: Explode Effect
3192
//>>group: Effects
3193
// jscs:disable maximumLineLength
3194
//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
3195
// jscs:enable maximumLineLength
3196
//>>docs: http://api.jqueryui.com/explode-effect/
3197
//>>demos: http://jqueryui.com/effect/
3198
3199
3200
3201
var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectExplode seems to be never used. Consider removing it.
Loading history...
3202
3203
	var i, j, left, top, mx, my,
3204
		rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
3205
		cells = rows,
3206
		element = $( this ),
3207
		mode = options.mode,
3208
		show = mode === "show",
3209
3210
		// Show and then visibility:hidden the element before calculating offset
3211
		offset = element.show().css( "visibility", "hidden" ).offset(),
3212
3213
		// Width and height of a piece
3214
		width = Math.ceil( element.outerWidth() / cells ),
3215
		height = Math.ceil( element.outerHeight() / rows ),
3216
		pieces = [];
3217
3218
	// Children animate complete:
3219
	function childComplete() {
3220
		pieces.push( this );
3221
		if ( pieces.length === rows * cells ) {
3222
			animComplete();
3223
		}
3224
	}
3225
3226
	// Clone the element for each row and cell.
3227
	for ( i = 0; i < rows; i++ ) { // ===>
3228
		top = offset.top + i * height;
3229
		my = i - ( rows - 1 ) / 2;
3230
3231
		for ( j = 0; j < cells; j++ ) { // |||
3232
			left = offset.left + j * width;
3233
			mx = j - ( cells - 1 ) / 2;
3234
3235
			// Create a clone of the now hidden main element that will be absolute positioned
3236
			// within a wrapper div off the -left and -top equal to size of our pieces
3237
			element
3238
				.clone()
3239
				.appendTo( "body" )
3240
				.wrap( "<div></div>" )
3241
				.css( {
3242
					position: "absolute",
3243
					visibility: "visible",
3244
					left: -j * width,
3245
					top: -i * height
3246
				} )
3247
3248
				// Select the wrapper - make it overflow: hidden and absolute positioned based on
3249
				// where the original was located +left and +top equal to the size of pieces
3250
				.parent()
3251
					.addClass( "ui-effects-explode" )
3252
					.css( {
3253
						position: "absolute",
3254
						overflow: "hidden",
3255
						width: width,
3256
						height: height,
3257
						left: left + ( show ? mx * width : 0 ),
3258
						top: top + ( show ? my * height : 0 ),
3259
						opacity: show ? 0 : 1
3260
					} )
3261
					.animate( {
3262
						left: left + ( show ? 0 : mx * width ),
3263
						top: top + ( show ? 0 : my * height ),
3264
						opacity: show ? 1 : 0
3265
					}, options.duration || 500, options.easing, childComplete );
3266
		}
3267
	}
3268
3269
	function animComplete() {
3270
		element.css( {
3271
			visibility: "visible"
3272
		} );
3273
		$( pieces ).remove();
3274
		done();
3275
	}
3276
} );
3277
3278
3279
/*!
3280
 * jQuery UI Effects Fade 1.12.1
3281
 * http://jqueryui.com
3282
 *
3283
 * Copyright jQuery Foundation and other contributors
3284
 * Released under the MIT license.
3285
 * http://jquery.org/license
3286
 */
3287
3288
//>>label: Fade Effect
3289
//>>group: Effects
3290
//>>description: Fades the element.
3291
//>>docs: http://api.jqueryui.com/fade-effect/
3292
//>>demos: http://jqueryui.com/effect/
3293
3294
3295
3296
var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectFade seems to be never used. Consider removing it.
Loading history...
3297
	var show = options.mode === "show";
3298
3299
	$( this )
3300
		.css( "opacity", show ? 0 : 1 )
3301
		.animate( {
3302
			opacity: show ? 1 : 0
3303
		}, {
3304
			queue: false,
3305
			duration: options.duration,
3306
			easing: options.easing,
3307
			complete: done
3308
		} );
3309
} );
3310
3311
3312
/*!
3313
 * jQuery UI Effects Fold 1.12.1
3314
 * http://jqueryui.com
3315
 *
3316
 * Copyright jQuery Foundation and other contributors
3317
 * Released under the MIT license.
3318
 * http://jquery.org/license
3319
 */
3320
3321
//>>label: Fold Effect
3322
//>>group: Effects
3323
//>>description: Folds an element first horizontally and then vertically.
3324
//>>docs: http://api.jqueryui.com/fold-effect/
3325
//>>demos: http://jqueryui.com/effect/
3326
3327
3328
3329
var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectFold seems to be never used. Consider removing it.
Loading history...
3330
3331
	// Create element
3332
	var element = $( this ),
3333
		mode = options.mode,
3334
		show = mode === "show",
3335
		hide = mode === "hide",
3336
		size = options.size || 15,
3337
		percent = /([0-9]+)%/.exec( size ),
3338
		horizFirst = !!options.horizFirst,
3339
		ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
3340
		duration = options.duration / 2,
3341
3342
		placeholder = $.effects.createPlaceholder( element ),
3343
3344
		start = element.cssClip(),
3345
		animation1 = { clip: $.extend( {}, start ) },
3346
		animation2 = { clip: $.extend( {}, start ) },
3347
3348
		distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
3349
3350
		queuelen = element.queue().length;
3351
3352
	if ( percent ) {
3353
		size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
3354
	}
3355
	animation1.clip[ ref[ 0 ] ] = size;
3356
	animation2.clip[ ref[ 0 ] ] = size;
3357
	animation2.clip[ ref[ 1 ] ] = 0;
3358
3359
	if ( show ) {
3360
		element.cssClip( animation2.clip );
3361
		if ( placeholder ) {
3362
			placeholder.css( $.effects.clipToBox( animation2 ) );
3363
		}
3364
3365
		animation2.clip = start;
3366
	}
3367
3368
	// Animate
3369
	element
3370
		.queue( function( next ) {
3371
			if ( placeholder ) {
3372
				placeholder
3373
					.animate( $.effects.clipToBox( animation1 ), duration, options.easing )
3374
					.animate( $.effects.clipToBox( animation2 ), duration, options.easing );
3375
			}
3376
3377
			next();
3378
		} )
3379
		.animate( animation1, duration, options.easing )
3380
		.animate( animation2, duration, options.easing )
3381
		.queue( done );
3382
3383
	$.effects.unshift( element, queuelen, 4 );
3384
} );
3385
3386
3387
/*!
3388
 * jQuery UI Effects Highlight 1.12.1
3389
 * http://jqueryui.com
3390
 *
3391
 * Copyright jQuery Foundation and other contributors
3392
 * Released under the MIT license.
3393
 * http://jquery.org/license
3394
 */
3395
3396
//>>label: Highlight Effect
3397
//>>group: Effects
3398
//>>description: Highlights the background of an element in a defined color for a custom duration.
3399
//>>docs: http://api.jqueryui.com/highlight-effect/
3400
//>>demos: http://jqueryui.com/effect/
3401
3402
3403
3404
var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectHighlight seems to be never used. Consider removing it.
Loading history...
3405
	var element = $( this ),
3406
		animation = {
3407
			backgroundColor: element.css( "backgroundColor" )
3408
		};
3409
3410
	if ( options.mode === "hide" ) {
3411
		animation.opacity = 0;
3412
	}
3413
3414
	$.effects.saveStyle( element );
3415
3416
	element
3417
		.css( {
3418
			backgroundImage: "none",
3419
			backgroundColor: options.color || "#ffff99"
3420
		} )
3421
		.animate( animation, {
3422
			queue: false,
3423
			duration: options.duration,
3424
			easing: options.easing,
3425
			complete: done
3426
		} );
3427
} );
3428
3429
3430
/*!
3431
 * jQuery UI Effects Size 1.12.1
3432
 * http://jqueryui.com
3433
 *
3434
 * Copyright jQuery Foundation and other contributors
3435
 * Released under the MIT license.
3436
 * http://jquery.org/license
3437
 */
3438
3439
//>>label: Size Effect
3440
//>>group: Effects
3441
//>>description: Resize an element to a specified width and height.
3442
//>>docs: http://api.jqueryui.com/size-effect/
3443
//>>demos: http://jqueryui.com/effect/
3444
3445
3446
3447
var effectsEffectSize = $.effects.define( "size", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectSize seems to be never used. Consider removing it.
Loading history...
3448
3449
	// Create element
3450
	var baseline, factor, temp,
3451
		element = $( this ),
3452
3453
		// Copy for children
3454
		cProps = [ "fontSize" ],
3455
		vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
3456
		hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
3457
3458
		// Set options
3459
		mode = options.mode,
3460
		restore = mode !== "effect",
3461
		scale = options.scale || "both",
3462
		origin = options.origin || [ "middle", "center" ],
3463
		position = element.css( "position" ),
3464
		pos = element.position(),
3465
		original = $.effects.scaledDimensions( element ),
3466
		from = options.from || original,
3467
		to = options.to || $.effects.scaledDimensions( element, 0 );
3468
3469
	$.effects.createPlaceholder( element );
3470
3471
	if ( mode === "show" ) {
3472
		temp = from;
3473
		from = to;
3474
		to = temp;
3475
	}
3476
3477
	// Set scaling factor
3478
	factor = {
3479
		from: {
3480
			y: from.height / original.height,
3481
			x: from.width / original.width
3482
		},
3483
		to: {
3484
			y: to.height / original.height,
3485
			x: to.width / original.width
3486
		}
3487
	};
3488
3489
	// Scale the css box
3490
	if ( scale === "box" || scale === "both" ) {
3491
3492
		// Vertical props scaling
3493
		if ( factor.from.y !== factor.to.y ) {
3494
			from = $.effects.setTransition( element, vProps, factor.from.y, from );
3495
			to = $.effects.setTransition( element, vProps, factor.to.y, to );
3496
		}
3497
3498
		// Horizontal props scaling
3499
		if ( factor.from.x !== factor.to.x ) {
3500
			from = $.effects.setTransition( element, hProps, factor.from.x, from );
3501
			to = $.effects.setTransition( element, hProps, factor.to.x, to );
3502
		}
3503
	}
3504
3505
	// Scale the content
3506
	if ( scale === "content" || scale === "both" ) {
3507
3508
		// Vertical props scaling
3509
		if ( factor.from.y !== factor.to.y ) {
3510
			from = $.effects.setTransition( element, cProps, factor.from.y, from );
3511
			to = $.effects.setTransition( element, cProps, factor.to.y, to );
3512
		}
3513
	}
3514
3515
	// Adjust the position properties based on the provided origin points
3516
	if ( origin ) {
3517
		baseline = $.effects.getBaseline( origin, original );
3518
		from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
3519
		from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
3520
		to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
3521
		to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
3522
	}
3523
	element.css( from );
3524
3525
	// Animate the children if desired
3526
	if ( scale === "content" || scale === "both" ) {
3527
3528
		vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
3529
		hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
3530
3531
		// Only animate children with width attributes specified
3532
		// TODO: is this right? should we include anything with css width specified as well
3533
		element.find( "*[width]" ).each( function() {
3534
			var child = $( this ),
3535
				childOriginal = $.effects.scaledDimensions( child ),
3536
				childFrom = {
3537
					height: childOriginal.height * factor.from.y,
3538
					width: childOriginal.width * factor.from.x,
3539
					outerHeight: childOriginal.outerHeight * factor.from.y,
3540
					outerWidth: childOriginal.outerWidth * factor.from.x
3541
				},
3542
				childTo = {
3543
					height: childOriginal.height * factor.to.y,
3544
					width: childOriginal.width * factor.to.x,
3545
					outerHeight: childOriginal.height * factor.to.y,
3546
					outerWidth: childOriginal.width * factor.to.x
3547
				};
3548
3549
			// Vertical props scaling
3550
			if ( factor.from.y !== factor.to.y ) {
3551
				childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
3552
				childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
3553
			}
3554
3555
			// Horizontal props scaling
3556
			if ( factor.from.x !== factor.to.x ) {
3557
				childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
3558
				childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
3559
			}
3560
3561
			if ( restore ) {
3562
				$.effects.saveStyle( child );
3563
			}
3564
3565
			// Animate children
3566
			child.css( childFrom );
3567
			child.animate( childTo, options.duration, options.easing, function() {
3568
3569
				// Restore children
3570
				if ( restore ) {
3571
					$.effects.restoreStyle( child );
3572
				}
3573
			} );
3574
		} );
3575
	}
3576
3577
	// Animate
3578
	element.animate( to, {
3579
		queue: false,
3580
		duration: options.duration,
3581
		easing: options.easing,
3582
		complete: function() {
3583
3584
			var offset = element.offset();
3585
3586
			if ( to.opacity === 0 ) {
3587
				element.css( "opacity", from.opacity );
3588
			}
3589
3590
			if ( !restore ) {
3591
				element
3592
					.css( "position", position === "static" ? "relative" : position )
3593
					.offset( offset );
3594
3595
				// Need to save style here so that automatic style restoration
3596
				// doesn't restore to the original styles from before the animation.
3597
				$.effects.saveStyle( element );
3598
			}
3599
3600
			done();
3601
		}
3602
	} );
3603
3604
} );
3605
3606
3607
/*!
3608
 * jQuery UI Effects Scale 1.12.1
3609
 * http://jqueryui.com
3610
 *
3611
 * Copyright jQuery Foundation and other contributors
3612
 * Released under the MIT license.
3613
 * http://jquery.org/license
3614
 */
3615
3616
//>>label: Scale Effect
3617
//>>group: Effects
3618
//>>description: Grows or shrinks an element and its content.
3619
//>>docs: http://api.jqueryui.com/scale-effect/
3620
//>>demos: http://jqueryui.com/effect/
3621
3622
3623
3624
var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectScale seems to be never used. Consider removing it.
Loading history...
3625
3626
	// Create element
3627
	var el = $( this ),
3628
		mode = options.mode,
3629
		percent = parseInt( options.percent, 10 ) ||
3630
			( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
3631
3632
		newOptions = $.extend( true, {
3633
			from: $.effects.scaledDimensions( el ),
3634
			to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
3635
			origin: options.origin || [ "middle", "center" ]
3636
		}, options );
3637
3638
	// Fade option to support puff
3639
	if ( options.fade ) {
3640
		newOptions.from.opacity = 1;
3641
		newOptions.to.opacity = 0;
3642
	}
3643
3644
	$.effects.effect.size.call( this, newOptions, done );
3645
} );
3646
3647
3648
/*!
3649
 * jQuery UI Effects Puff 1.12.1
3650
 * http://jqueryui.com
3651
 *
3652
 * Copyright jQuery Foundation and other contributors
3653
 * Released under the MIT license.
3654
 * http://jquery.org/license
3655
 */
3656
3657
//>>label: Puff Effect
3658
//>>group: Effects
3659
//>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
3660
//>>docs: http://api.jqueryui.com/puff-effect/
3661
//>>demos: http://jqueryui.com/effect/
3662
3663
3664
3665
var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectPuff seems to be never used. Consider removing it.
Loading history...
3666
	var newOptions = $.extend( true, {}, options, {
3667
		fade: true,
3668
		percent: parseInt( options.percent, 10 ) || 150
3669
	} );
3670
3671
	$.effects.effect.scale.call( this, newOptions, done );
3672
} );
3673
3674
3675
/*!
3676
 * jQuery UI Effects Pulsate 1.12.1
3677
 * http://jqueryui.com
3678
 *
3679
 * Copyright jQuery Foundation and other contributors
3680
 * Released under the MIT license.
3681
 * http://jquery.org/license
3682
 */
3683
3684
//>>label: Pulsate Effect
3685
//>>group: Effects
3686
//>>description: Pulsates an element n times by changing the opacity to zero and back.
3687
//>>docs: http://api.jqueryui.com/pulsate-effect/
3688
//>>demos: http://jqueryui.com/effect/
3689
3690
3691
3692
var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectPulsate seems to be never used. Consider removing it.
Loading history...
3693
	var element = $( this ),
3694
		mode = options.mode,
3695
		show = mode === "show",
3696
		hide = mode === "hide",
3697
		showhide = show || hide,
3698
3699
		// Showing or hiding leaves off the "last" animation
3700
		anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
3701
		duration = options.duration / anims,
3702
		animateTo = 0,
3703
		i = 1,
3704
		queuelen = element.queue().length;
3705
3706
	if ( show || !element.is( ":visible" ) ) {
3707
		element.css( "opacity", 0 ).show();
3708
		animateTo = 1;
3709
	}
3710
3711
	// Anims - 1 opacity "toggles"
3712
	for ( ; i < anims; i++ ) {
3713
		element.animate( { opacity: animateTo }, duration, options.easing );
3714
		animateTo = 1 - animateTo;
3715
	}
3716
3717
	element.animate( { opacity: animateTo }, duration, options.easing );
3718
3719
	element.queue( done );
3720
3721
	$.effects.unshift( element, queuelen, anims + 1 );
3722
} );
3723
3724
3725
/*!
3726
 * jQuery UI Effects Shake 1.12.1
3727
 * http://jqueryui.com
3728
 *
3729
 * Copyright jQuery Foundation and other contributors
3730
 * Released under the MIT license.
3731
 * http://jquery.org/license
3732
 */
3733
3734
//>>label: Shake Effect
3735
//>>group: Effects
3736
//>>description: Shakes an element horizontally or vertically n times.
3737
//>>docs: http://api.jqueryui.com/shake-effect/
3738
//>>demos: http://jqueryui.com/effect/
3739
3740
3741
3742
var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectShake seems to be never used. Consider removing it.
Loading history...
3743
3744
	var i = 1,
3745
		element = $( this ),
3746
		direction = options.direction || "left",
3747
		distance = options.distance || 20,
3748
		times = options.times || 3,
3749
		anims = times * 2 + 1,
3750
		speed = Math.round( options.duration / anims ),
3751
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3752
		positiveMotion = ( direction === "up" || direction === "left" ),
3753
		animation = {},
3754
		animation1 = {},
3755
		animation2 = {},
3756
3757
		queuelen = element.queue().length;
3758
3759
	$.effects.createPlaceholder( element );
3760
3761
	// Animation
3762
	animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
3763
	animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
3764
	animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
3765
3766
	// Animate
3767
	element.animate( animation, speed, options.easing );
3768
3769
	// Shakes
3770
	for ( ; i < times; i++ ) {
3771
		element
3772
			.animate( animation1, speed, options.easing )
3773
			.animate( animation2, speed, options.easing );
3774
	}
3775
3776
	element
3777
		.animate( animation1, speed, options.easing )
3778
		.animate( animation, speed / 2, options.easing )
3779
		.queue( done );
3780
3781
	$.effects.unshift( element, queuelen, anims + 1 );
3782
} );
3783
3784
3785
/*!
3786
 * jQuery UI Effects Slide 1.12.1
3787
 * http://jqueryui.com
3788
 *
3789
 * Copyright jQuery Foundation and other contributors
3790
 * Released under the MIT license.
3791
 * http://jquery.org/license
3792
 */
3793
3794
//>>label: Slide Effect
3795
//>>group: Effects
3796
//>>description: Slides an element in and out of the viewport.
3797
//>>docs: http://api.jqueryui.com/slide-effect/
3798
//>>demos: http://jqueryui.com/effect/
3799
3800
3801
3802
var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectSlide seems to be never used. Consider removing it.
Loading history...
3803
	var startClip, startRef,
3804
		element = $( this ),
3805
		map = {
3806
			up: [ "bottom", "top" ],
3807
			down: [ "top", "bottom" ],
3808
			left: [ "right", "left" ],
3809
			right: [ "left", "right" ]
3810
		},
3811
		mode = options.mode,
3812
		direction = options.direction || "left",
3813
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3814
		positiveMotion = ( direction === "up" || direction === "left" ),
3815
		distance = options.distance ||
3816
			element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
3817
		animation = {};
3818
3819
	$.effects.createPlaceholder( element );
3820
3821
	startClip = element.cssClip();
3822
	startRef = element.position()[ ref ];
3823
3824
	// Define hide animation
3825
	animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
3826
	animation.clip = element.cssClip();
3827
	animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
3828
3829
	// Reverse the animation if we're showing
3830
	if ( mode === "show" ) {
3831
		element.cssClip( animation.clip );
3832
		element.css( ref, animation[ ref ] );
3833
		animation.clip = startClip;
3834
		animation[ ref ] = startRef;
3835
	}
3836
3837
	// Actually animate
3838
	element.animate( animation, {
3839
		queue: false,
3840
		duration: options.duration,
3841
		easing: options.easing,
3842
		complete: done
3843
	} );
3844
} );
3845
3846
3847
/*!
3848
 * jQuery UI Effects Transfer 1.12.1
3849
 * http://jqueryui.com
3850
 *
3851
 * Copyright jQuery Foundation and other contributors
3852
 * Released under the MIT license.
3853
 * http://jquery.org/license
3854
 */
3855
3856
//>>label: Transfer Effect
3857
//>>group: Effects
3858
//>>description: Displays a transfer effect from one element to another.
3859
//>>docs: http://api.jqueryui.com/transfer-effect/
3860
//>>demos: http://jqueryui.com/effect/
3861
3862
3863
3864
var effect;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable effect already seems to be declared on line 2921. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3865
if ( $.uiBackCompat !== false ) {
3866
	effect = $.effects.define( "transfer", function( options, done ) {
3867
		$( this ).transfer( options, done );
3868
	} );
3869
}
3870
var effectsEffectTransfer = effect;
0 ignored issues
show
Unused Code introduced by
The variable effectsEffectTransfer seems to be never used. Consider removing it.
Loading history...
3871
3872
3873
/*!
3874
 * jQuery UI Focusable 1.12.1
3875
 * http://jqueryui.com
3876
 *
3877
 * Copyright jQuery Foundation and other contributors
3878
 * Released under the MIT license.
3879
 * http://jquery.org/license
3880
 */
3881
3882
//>>label: :focusable Selector
3883
//>>group: Core
3884
//>>description: Selects elements which can be focused.
3885
//>>docs: http://api.jqueryui.com/focusable-selector/
3886
3887
3888
3889
// Selectors
3890
$.ui.focusable = function( element, hasTabindex ) {
3891
	var map, mapName, img, focusableIfVisible, fieldset,
3892
		nodeName = element.nodeName.toLowerCase();
3893
3894
	if ( "area" === nodeName ) {
3895
		map = element.parentNode;
3896
		mapName = map.name;
3897
		if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
3898
			return false;
3899
		}
3900
		img = $( "img[usemap='#" + mapName + "']" );
3901
		return img.length > 0 && img.is( ":visible" );
3902
	}
3903
3904
	if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
3905
		focusableIfVisible = !element.disabled;
3906
3907
		if ( focusableIfVisible ) {
3908
3909
			// Form controls within a disabled fieldset are disabled.
3910
			// However, controls within the fieldset's legend do not get disabled.
3911
			// Since controls generally aren't placed inside legends, we skip
3912
			// this portion of the check.
3913
			fieldset = $( element ).closest( "fieldset" )[ 0 ];
3914
			if ( fieldset ) {
3915
				focusableIfVisible = !fieldset.disabled;
3916
			}
3917
		}
3918
	} else if ( "a" === nodeName ) {
3919
		focusableIfVisible = element.href || hasTabindex;
3920
	} else {
3921
		focusableIfVisible = hasTabindex;
3922
	}
3923
3924
	return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
3925
};
3926
3927
// Support: IE 8 only
3928
// IE 8 doesn't resolve inherit to visible/hidden for computed values
3929
function visible( element ) {
3930
	var visibility = element.css( "visibility" );
3931
	while ( visibility === "inherit" ) {
3932
		element = element.parent();
3933
		visibility = element.css( "visibility" );
3934
	}
3935
	return visibility !== "hidden";
3936
}
3937
3938
$.extend( $.expr[ ":" ], {
3939
	focusable: function( element ) {
3940
		return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
0 ignored issues
show
Best Practice introduced by
Comparing $.attr(element, "tabindex") to null using the != operator is not safe. Consider using !== instead.
Loading history...
3941
	}
3942
} );
3943
3944
var focusable = $.ui.focusable;
3945
3946
3947
3948
3949
// Support: IE8 Only
3950
// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
3951
// with a string, so we need to find the proper form.
3952
var form = $.fn.form = function() {
3953
	return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
3954
};
3955
3956
3957
/*!
3958
 * jQuery UI Form Reset Mixin 1.12.1
3959
 * http://jqueryui.com
3960
 *
3961
 * Copyright jQuery Foundation and other contributors
3962
 * Released under the MIT license.
3963
 * http://jquery.org/license
3964
 */
3965
3966
//>>label: Form Reset Mixin
3967
//>>group: Core
3968
//>>description: Refresh input widgets when their form is reset
3969
//>>docs: http://api.jqueryui.com/form-reset-mixin/
3970
3971
3972
3973
var formResetMixin = $.ui.formResetMixin = {
3974
	_formResetHandler: function() {
3975
		var form = $( this );
3976
3977
		// Wait for the form reset to actually happen before refreshing
3978
		setTimeout( function() {
3979
			var instances = form.data( "ui-form-reset-instances" );
3980
			$.each( instances, function() {
3981
				this.refresh();
3982
			} );
3983
		} );
3984
	},
3985
3986
	_bindFormResetHandler: function() {
3987
		this.form = this.element.form();
3988
		if ( !this.form.length ) {
3989
			return;
3990
		}
3991
3992
		var instances = this.form.data( "ui-form-reset-instances" ) || [];
3993
		if ( !instances.length ) {
3994
3995
			// We don't use _on() here because we use a single event handler per form
3996
			this.form.on( "reset.ui-form-reset", this._formResetHandler );
3997
		}
3998
		instances.push( this );
3999
		this.form.data( "ui-form-reset-instances", instances );
4000
	},
4001
4002
	_unbindFormResetHandler: function() {
4003
		if ( !this.form.length ) {
4004
			return;
4005
		}
4006
4007
		var instances = this.form.data( "ui-form-reset-instances" );
4008
		instances.splice( $.inArray( this, instances ), 1 );
4009
		if ( instances.length ) {
4010
			this.form.data( "ui-form-reset-instances", instances );
4011
		} else {
4012
			this.form
4013
				.removeData( "ui-form-reset-instances" )
4014
				.off( "reset.ui-form-reset" );
4015
		}
4016
	}
4017
};
4018
4019
4020
/*!
4021
 * jQuery UI Support for jQuery core 1.7.x 1.12.1
4022
 * http://jqueryui.com
4023
 *
4024
 * Copyright jQuery Foundation and other contributors
4025
 * Released under the MIT license.
4026
 * http://jquery.org/license
4027
 *
4028
 */
4029
4030
//>>label: jQuery 1.7 Support
4031
//>>group: Core
4032
//>>description: Support version 1.7.x of jQuery core
4033
4034
4035
4036
// Support: jQuery 1.7 only
4037
// Not a great way to check versions, but since we only support 1.7+ and only
4038
// need to detect <1.8, this is a simple check that should suffice. Checking
4039
// for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0
4040
// and we'll never reach 1.70.0 (if we do, we certainly won't be supporting
4041
// 1.7 anymore). See #11197 for why we're not using feature detection.
4042
if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) {
4043
4044
	// Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()
4045
	// Unlike jQuery Core 1.8+, these only support numeric values to set the
4046
	// dimensions in pixels
4047
	$.each( [ "Width", "Height" ], function( i, name ) {
4048
		var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
4049
			type = name.toLowerCase(),
4050
			orig = {
4051
				innerWidth: $.fn.innerWidth,
4052
				innerHeight: $.fn.innerHeight,
4053
				outerWidth: $.fn.outerWidth,
4054
				outerHeight: $.fn.outerHeight
4055
			};
4056
4057
		function reduce( elem, size, border, margin ) {
4058
			$.each( side, function() {
4059
				size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
4060
				if ( border ) {
4061
					size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
4062
				}
4063
				if ( margin ) {
4064
					size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
4065
				}
4066
			} );
4067
			return size;
4068
		}
4069
4070
		$.fn[ "inner" + name ] = function( size ) {
4071
			if ( size === undefined ) {
4072
				return orig[ "inner" + name ].call( this );
4073
			}
4074
4075
			return this.each( function() {
4076
				$( this ).css( type, reduce( this, size ) + "px" );
4077
			} );
4078
		};
4079
4080
		$.fn[ "outer" + name ] = function( size, margin ) {
4081
			if ( typeof size !== "number" ) {
4082
				return orig[ "outer" + name ].call( this, size );
4083
			}
4084
4085
			return this.each( function() {
4086
				$( this ).css( type, reduce( this, size, true, margin ) + "px" );
4087
			} );
4088
		};
4089
	} );
4090
4091
	$.fn.addBack = function( selector ) {
4092
		return this.add( selector == null ?
0 ignored issues
show
Best Practice introduced by
Comparing selector to null using the == operator is not safe. Consider using === instead.
Loading history...
4093
			this.prevObject : this.prevObject.filter( selector )
4094
		);
4095
	};
4096
}
4097
4098
;
4099
/*!
4100
 * jQuery UI Keycode 1.12.1
4101
 * http://jqueryui.com
4102
 *
4103
 * Copyright jQuery Foundation and other contributors
4104
 * Released under the MIT license.
4105
 * http://jquery.org/license
4106
 */
4107
4108
//>>label: Keycode
4109
//>>group: Core
4110
//>>description: Provide keycodes as keynames
4111
//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
4112
4113
4114
var keycode = $.ui.keyCode = {
0 ignored issues
show
Unused Code introduced by
The variable keycode seems to be never used. Consider removing it.
Loading history...
4115
	BACKSPACE: 8,
4116
	COMMA: 188,
4117
	DELETE: 46,
4118
	DOWN: 40,
4119
	END: 35,
4120
	ENTER: 13,
4121
	ESCAPE: 27,
4122
	HOME: 36,
4123
	LEFT: 37,
4124
	PAGE_DOWN: 34,
4125
	PAGE_UP: 33,
4126
	PERIOD: 190,
4127
	RIGHT: 39,
4128
	SPACE: 32,
4129
	TAB: 9,
4130
	UP: 38
4131
};
4132
4133
4134
4135
4136
// Internal use only
4137
var escapeSelector = $.ui.escapeSelector = ( function() {
4138
	var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
4139
	return function( selector ) {
4140
		return selector.replace( selectorEscape, "\\$1" );
4141
	};
4142
} )();
4143
4144
4145
/*!
4146
 * jQuery UI Labels 1.12.1
4147
 * http://jqueryui.com
4148
 *
4149
 * Copyright jQuery Foundation and other contributors
4150
 * Released under the MIT license.
4151
 * http://jquery.org/license
4152
 */
4153
4154
//>>label: labels
4155
//>>group: Core
4156
//>>description: Find all the labels associated with a given input
4157
//>>docs: http://api.jqueryui.com/labels/
4158
4159
4160
4161
var labels = $.fn.labels = function() {
4162
	var ancestor, selector, id, labels, ancestors;
4163
4164
	// Check control.labels first
4165
	if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
4166
		return this.pushStack( this[ 0 ].labels );
4167
	}
4168
4169
	// Support: IE <= 11, FF <= 37, Android <= 2.3 only
4170
	// Above browsers do not support control.labels. Everything below is to support them
4171
	// as well as document fragments. control.labels does not work on document fragments
4172
	labels = this.eq( 0 ).parents( "label" );
4173
4174
	// Look for the label based on the id
4175
	id = this.attr( "id" );
4176
	if ( id ) {
4177
4178
		// We don't search against the document in case the element
4179
		// is disconnected from the DOM
4180
		ancestor = this.eq( 0 ).parents().last();
4181
4182
		// Get a full set of top level ancestors
4183
		ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
4184
4185
		// Create a selector for the label based on the id
4186
		selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
4187
4188
		labels = labels.add( ancestors.find( selector ).addBack( selector ) );
4189
4190
	}
4191
4192
	// Return whatever we have found for labels
4193
	return this.pushStack( labels );
4194
};
4195
4196
4197
/*!
4198
 * jQuery UI Scroll Parent 1.12.1
4199
 * http://jqueryui.com
4200
 *
4201
 * Copyright jQuery Foundation and other contributors
4202
 * Released under the MIT license.
4203
 * http://jquery.org/license
4204
 */
4205
4206
//>>label: scrollParent
4207
//>>group: Core
4208
//>>description: Get the closest ancestor element that is scrollable.
4209
//>>docs: http://api.jqueryui.com/scrollParent/
4210
4211
4212
4213
var scrollParent = $.fn.scrollParent = function( includeHidden ) {
4214
	var position = this.css( "position" ),
4215
		excludeStaticParent = position === "absolute",
4216
		overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
4217
		scrollParent = this.parents().filter( function() {
4218
			var parent = $( this );
4219
			if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
4220
				return false;
4221
			}
4222
			return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
4223
				parent.css( "overflow-x" ) );
4224
		} ).eq( 0 );
4225
4226
	return position === "fixed" || !scrollParent.length ?
4227
		$( this[ 0 ].ownerDocument || document ) :
4228
		scrollParent;
4229
};
4230
4231
4232
/*!
4233
 * jQuery UI Tabbable 1.12.1
4234
 * http://jqueryui.com
4235
 *
4236
 * Copyright jQuery Foundation and other contributors
4237
 * Released under the MIT license.
4238
 * http://jquery.org/license
4239
 */
4240
4241
//>>label: :tabbable Selector
4242
//>>group: Core
4243
//>>description: Selects elements which can be tabbed to.
4244
//>>docs: http://api.jqueryui.com/tabbable-selector/
4245
4246
4247
4248
var tabbable = $.extend( $.expr[ ":" ], {
0 ignored issues
show
Unused Code introduced by
The assignment to variable tabbable seems to be never used. Consider removing it.
Loading history...
4249
	tabbable: function( element ) {
4250
		var tabIndex = $.attr( element, "tabindex" ),
4251
			hasTabindex = tabIndex != null;
0 ignored issues
show
Best Practice introduced by
Comparing tabIndex to null using the != operator is not safe. Consider using !== instead.
Loading history...
4252
		return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
4253
	}
4254
} );
4255
4256
4257
/*!
4258
 * jQuery UI Unique ID 1.12.1
4259
 * http://jqueryui.com
4260
 *
4261
 * Copyright jQuery Foundation and other contributors
4262
 * Released under the MIT license.
4263
 * http://jquery.org/license
4264
 */
4265
4266
//>>label: uniqueId
4267
//>>group: Core
4268
//>>description: Functions to generate and remove uniqueId's
4269
//>>docs: http://api.jqueryui.com/uniqueId/
4270
4271
4272
4273
var uniqueId = $.fn.extend( {
4274
	uniqueId: ( function() {
4275
		var uuid = 0;
4276
4277
		return function() {
4278
			return this.each( function() {
4279
				if ( !this.id ) {
4280
					this.id = "ui-id-" + ( ++uuid );
4281
				}
4282
			} );
4283
		};
4284
	} )(),
4285
4286
	removeUniqueId: function() {
4287
		return this.each( function() {
4288
			if ( /^ui-id-\d+$/.test( this.id ) ) {
4289
				$( this ).removeAttr( "id" );
4290
			}
4291
		} );
4292
	}
4293
} );
4294
4295
4296
/*!
4297
 * jQuery UI Accordion 1.12.1
4298
 * http://jqueryui.com
4299
 *
4300
 * Copyright jQuery Foundation and other contributors
4301
 * Released under the MIT license.
4302
 * http://jquery.org/license
4303
 */
4304
4305
//>>label: Accordion
4306
//>>group: Widgets
4307
// jscs:disable maximumLineLength
4308
//>>description: Displays collapsible content panels for presenting information in a limited amount of space.
4309
// jscs:enable maximumLineLength
4310
//>>docs: http://api.jqueryui.com/accordion/
4311
//>>demos: http://jqueryui.com/accordion/
4312
//>>css.structure: ../../themes/base/core.css
4313
//>>css.structure: ../../themes/base/accordion.css
4314
//>>css.theme: ../../themes/base/theme.css
4315
4316
4317
4318
var widgetsAccordion = $.widget( "ui.accordion", {
0 ignored issues
show
Unused Code introduced by
The variable widgetsAccordion seems to be never used. Consider removing it.
Loading history...
4319
	version: "1.12.1",
4320
	options: {
4321
		active: 0,
4322
		animate: {},
4323
		classes: {
4324
			"ui-accordion-header": "ui-corner-top",
4325
			"ui-accordion-header-collapsed": "ui-corner-all",
4326
			"ui-accordion-content": "ui-corner-bottom"
4327
		},
4328
		collapsible: false,
4329
		event: "click",
4330
		header: "> li > :first-child, > :not(li):even",
4331
		heightStyle: "auto",
4332
		icons: {
4333
			activeHeader: "ui-icon-triangle-1-s",
4334
			header: "ui-icon-triangle-1-e"
4335
		},
4336
4337
		// Callbacks
4338
		activate: null,
4339
		beforeActivate: null
4340
	},
4341
4342
	hideProps: {
4343
		borderTopWidth: "hide",
4344
		borderBottomWidth: "hide",
4345
		paddingTop: "hide",
4346
		paddingBottom: "hide",
4347
		height: "hide"
4348
	},
4349
4350
	showProps: {
4351
		borderTopWidth: "show",
4352
		borderBottomWidth: "show",
4353
		paddingTop: "show",
4354
		paddingBottom: "show",
4355
		height: "show"
4356
	},
4357
4358
	_create: function() {
4359
		var options = this.options;
4360
4361
		this.prevShow = this.prevHide = $();
4362
		this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
4363
		this.element.attr( "role", "tablist" );
4364
4365
		// Don't allow collapsible: false and active: false / null
4366
		if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
0 ignored issues
show
Best Practice introduced by
Comparing options.active to null using the == operator is not safe. Consider using === instead.
Loading history...
4367
			options.active = 0;
4368
		}
4369
4370
		this._processPanels();
4371
4372
		// handle negative values
4373
		if ( options.active < 0 ) {
4374
			options.active += this.headers.length;
4375
		}
4376
		this._refresh();
4377
	},
4378
4379
	_getCreateEventData: function() {
4380
		return {
4381
			header: this.active,
4382
			panel: !this.active.length ? $() : this.active.next()
4383
		};
4384
	},
4385
4386
	_createIcons: function() {
4387
		var icon, children,
4388
			icons = this.options.icons;
4389
4390
		if ( icons ) {
4391
			icon = $( "<span>" );
4392
			this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
4393
			icon.prependTo( this.headers );
4394
			children = this.active.children( ".ui-accordion-header-icon" );
4395
			this._removeClass( children, icons.header )
4396
				._addClass( children, null, icons.activeHeader )
4397
				._addClass( this.headers, "ui-accordion-icons" );
4398
		}
4399
	},
4400
4401
	_destroyIcons: function() {
4402
		this._removeClass( this.headers, "ui-accordion-icons" );
4403
		this.headers.children( ".ui-accordion-header-icon" ).remove();
4404
	},
4405
4406
	_destroy: function() {
4407
		var contents;
4408
4409
		// Clean up main element
4410
		this.element.removeAttr( "role" );
4411
4412
		// Clean up headers
4413
		this.headers
4414
			.removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
4415
			.removeUniqueId();
4416
4417
		this._destroyIcons();
4418
4419
		// Clean up content panels
4420
		contents = this.headers.next()
4421
			.css( "display", "" )
4422
			.removeAttr( "role aria-hidden aria-labelledby" )
4423
			.removeUniqueId();
4424
4425
		if ( this.options.heightStyle !== "content" ) {
4426
			contents.css( "height", "" );
4427
		}
4428
	},
4429
4430
	_setOption: function( key, value ) {
4431
		if ( key === "active" ) {
4432
4433
			// _activate() will handle invalid values and update this.options
4434
			this._activate( value );
4435
			return;
4436
		}
4437
4438
		if ( key === "event" ) {
4439
			if ( this.options.event ) {
4440
				this._off( this.headers, this.options.event );
4441
			}
4442
			this._setupEvents( value );
4443
		}
4444
4445
		this._super( key, value );
4446
4447
		// Setting collapsible: false while collapsed; open first panel
4448
		if ( key === "collapsible" && !value && this.options.active === false ) {
4449
			this._activate( 0 );
4450
		}
4451
4452
		if ( key === "icons" ) {
4453
			this._destroyIcons();
4454
			if ( value ) {
4455
				this._createIcons();
4456
			}
4457
		}
4458
	},
4459
4460
	_setOptionDisabled: function( value ) {
4461
		this._super( value );
4462
4463
		this.element.attr( "aria-disabled", value );
4464
4465
		// Support: IE8 Only
4466
		// #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
4467
		// so we need to add the disabled class to the headers and panels
4468
		this._toggleClass( null, "ui-state-disabled", !!value );
4469
		this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
4470
			!!value );
4471
	},
4472
4473
	_keydown: function( event ) {
4474
		if ( event.altKey || event.ctrlKey ) {
4475
			return;
4476
		}
4477
4478
		var keyCode = $.ui.keyCode,
4479
			length = this.headers.length,
4480
			currentIndex = this.headers.index( event.target ),
4481
			toFocus = false;
4482
4483
		switch ( event.keyCode ) {
4484
		case keyCode.RIGHT:
4485
		case keyCode.DOWN:
4486
			toFocus = this.headers[ ( currentIndex + 1 ) % length ];
4487
			break;
4488
		case keyCode.LEFT:
4489
		case keyCode.UP:
4490
			toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
4491
			break;
4492
		case keyCode.SPACE:
4493
		case keyCode.ENTER:
4494
			this._eventHandler( event );
4495
			break;
4496
		case keyCode.HOME:
4497
			toFocus = this.headers[ 0 ];
4498
			break;
4499
		case keyCode.END:
4500
			toFocus = this.headers[ length - 1 ];
4501
			break;
4502
		}
4503
4504
		if ( toFocus ) {
4505
			$( event.target ).attr( "tabIndex", -1 );
4506
			$( toFocus ).attr( "tabIndex", 0 );
4507
			$( toFocus ).trigger( "focus" );
4508
			event.preventDefault();
4509
		}
4510
	},
4511
4512
	_panelKeyDown: function( event ) {
4513
		if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
4514
			$( event.currentTarget ).prev().trigger( "focus" );
4515
		}
4516
	},
4517
4518
	refresh: function() {
4519
		var options = this.options;
4520
		this._processPanels();
4521
4522
		// Was collapsed or no panel
4523
		if ( ( options.active === false && options.collapsible === true ) ||
4524
				!this.headers.length ) {
4525
			options.active = false;
4526
			this.active = $();
4527
4528
		// active false only when collapsible is true
4529
		} else if ( options.active === false ) {
4530
			this._activate( 0 );
4531
4532
		// was active, but active panel is gone
4533
		} else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
4534
4535
			// all remaining panel are disabled
4536
			if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
4537
				options.active = false;
4538
				this.active = $();
4539
4540
			// activate previous panel
4541
			} else {
4542
				this._activate( Math.max( 0, options.active - 1 ) );
4543
			}
4544
4545
		// was active, active panel still exists
4546
		} else {
4547
4548
			// make sure active index is correct
4549
			options.active = this.headers.index( this.active );
4550
		}
4551
4552
		this._destroyIcons();
4553
4554
		this._refresh();
4555
	},
4556
4557
	_processPanels: function() {
4558
		var prevHeaders = this.headers,
4559
			prevPanels = this.panels;
4560
4561
		this.headers = this.element.find( this.options.header );
4562
		this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
4563
			"ui-state-default" );
4564
4565
		this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
4566
		this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
4567
4568
		// Avoid memory leaks (#10056)
4569
		if ( prevPanels ) {
4570
			this._off( prevHeaders.not( this.headers ) );
4571
			this._off( prevPanels.not( this.panels ) );
4572
		}
4573
	},
4574
4575
	_refresh: function() {
4576
		var maxHeight,
4577
			options = this.options,
4578
			heightStyle = options.heightStyle,
4579
			parent = this.element.parent();
4580
4581
		this.active = this._findActive( options.active );
4582
		this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
4583
			._removeClass( this.active, "ui-accordion-header-collapsed" );
4584
		this._addClass( this.active.next(), "ui-accordion-content-active" );
4585
		this.active.next().show();
4586
4587
		this.headers
4588
			.attr( "role", "tab" )
4589
			.each( function() {
4590
				var header = $( this ),
4591
					headerId = header.uniqueId().attr( "id" ),
4592
					panel = header.next(),
4593
					panelId = panel.uniqueId().attr( "id" );
4594
				header.attr( "aria-controls", panelId );
4595
				panel.attr( "aria-labelledby", headerId );
4596
			} )
4597
			.next()
4598
				.attr( "role", "tabpanel" );
4599
4600
		this.headers
4601
			.not( this.active )
4602
				.attr( {
4603
					"aria-selected": "false",
4604
					"aria-expanded": "false",
4605
					tabIndex: -1
4606
				} )
4607
				.next()
4608
					.attr( {
4609
						"aria-hidden": "true"
4610
					} )
4611
					.hide();
4612
4613
		// Make sure at least one header is in the tab order
4614
		if ( !this.active.length ) {
4615
			this.headers.eq( 0 ).attr( "tabIndex", 0 );
4616
		} else {
4617
			this.active.attr( {
4618
				"aria-selected": "true",
4619
				"aria-expanded": "true",
4620
				tabIndex: 0
4621
			} )
4622
				.next()
4623
					.attr( {
4624
						"aria-hidden": "false"
4625
					} );
4626
		}
4627
4628
		this._createIcons();
4629
4630
		this._setupEvents( options.event );
4631
4632
		if ( heightStyle === "fill" ) {
4633
			maxHeight = parent.height();
4634
			this.element.siblings( ":visible" ).each( function() {
4635
				var elem = $( this ),
4636
					position = elem.css( "position" );
4637
4638
				if ( position === "absolute" || position === "fixed" ) {
4639
					return;
4640
				}
4641
				maxHeight -= elem.outerHeight( true );
4642
			} );
4643
4644
			this.headers.each( function() {
4645
				maxHeight -= $( this ).outerHeight( true );
4646
			} );
4647
4648
			this.headers.next()
4649
				.each( function() {
4650
					$( this ).height( Math.max( 0, maxHeight -
4651
						$( this ).innerHeight() + $( this ).height() ) );
4652
				} )
4653
				.css( "overflow", "auto" );
4654
		} else if ( heightStyle === "auto" ) {
4655
			maxHeight = 0;
4656
			this.headers.next()
4657
				.each( function() {
4658
					var isVisible = $( this ).is( ":visible" );
4659
					if ( !isVisible ) {
4660
						$( this ).show();
4661
					}
4662
					maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
4663
					if ( !isVisible ) {
4664
						$( this ).hide();
4665
					}
4666
				} )
4667
				.height( maxHeight );
4668
		}
4669
	},
4670
4671
	_activate: function( index ) {
4672
		var active = this._findActive( index )[ 0 ];
4673
4674
		// Trying to activate the already active panel
4675
		if ( active === this.active[ 0 ] ) {
4676
			return;
4677
		}
4678
4679
		// Trying to collapse, simulate a click on the currently active header
4680
		active = active || this.active[ 0 ];
4681
4682
		this._eventHandler( {
4683
			target: active,
4684
			currentTarget: active,
4685
			preventDefault: $.noop
4686
		} );
4687
	},
4688
4689
	_findActive: function( selector ) {
4690
		return typeof selector === "number" ? this.headers.eq( selector ) : $();
4691
	},
4692
4693
	_setupEvents: function( event ) {
4694
		var events = {
4695
			keydown: "_keydown"
4696
		};
4697
		if ( event ) {
4698
			$.each( event.split( " " ), function( index, eventName ) {
4699
				events[ eventName ] = "_eventHandler";
4700
			} );
4701
		}
4702
4703
		this._off( this.headers.add( this.headers.next() ) );
4704
		this._on( this.headers, events );
4705
		this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
4706
		this._hoverable( this.headers );
4707
		this._focusable( this.headers );
4708
	},
4709
4710
	_eventHandler: function( event ) {
4711
		var activeChildren, clickedChildren,
4712
			options = this.options,
4713
			active = this.active,
4714
			clicked = $( event.currentTarget ),
4715
			clickedIsActive = clicked[ 0 ] === active[ 0 ],
4716
			collapsing = clickedIsActive && options.collapsible,
4717
			toShow = collapsing ? $() : clicked.next(),
4718
			toHide = active.next(),
4719
			eventData = {
4720
				oldHeader: active,
4721
				oldPanel: toHide,
4722
				newHeader: collapsing ? $() : clicked,
4723
				newPanel: toShow
4724
			};
4725
4726
		event.preventDefault();
4727
4728
		if (
4729
4730
				// click on active header, but not collapsible
4731
				( clickedIsActive && !options.collapsible ) ||
4732
4733
				// allow canceling activation
4734
				( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
4735
			return;
4736
		}
4737
4738
		options.active = collapsing ? false : this.headers.index( clicked );
4739
4740
		// When the call to ._toggle() comes after the class changes
4741
		// it causes a very odd bug in IE 8 (see #6720)
4742
		this.active = clickedIsActive ? $() : clicked;
4743
		this._toggle( eventData );
4744
4745
		// Switch classes
4746
		// corner classes on the previously active header stay after the animation
4747
		this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
4748
		if ( options.icons ) {
4749
			activeChildren = active.children( ".ui-accordion-header-icon" );
4750
			this._removeClass( activeChildren, null, options.icons.activeHeader )
4751
				._addClass( activeChildren, null, options.icons.header );
4752
		}
4753
4754
		if ( !clickedIsActive ) {
4755
			this._removeClass( clicked, "ui-accordion-header-collapsed" )
4756
				._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
4757
			if ( options.icons ) {
4758
				clickedChildren = clicked.children( ".ui-accordion-header-icon" );
4759
				this._removeClass( clickedChildren, null, options.icons.header )
4760
					._addClass( clickedChildren, null, options.icons.activeHeader );
4761
			}
4762
4763
			this._addClass( clicked.next(), "ui-accordion-content-active" );
4764
		}
4765
	},
4766
4767
	_toggle: function( data ) {
4768
		var toShow = data.newPanel,
4769
			toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
4770
4771
		// Handle activating a panel during the animation for another activation
4772
		this.prevShow.add( this.prevHide ).stop( true, true );
4773
		this.prevShow = toShow;
4774
		this.prevHide = toHide;
4775
4776
		if ( this.options.animate ) {
4777
			this._animate( toShow, toHide, data );
4778
		} else {
4779
			toHide.hide();
4780
			toShow.show();
4781
			this._toggleComplete( data );
4782
		}
4783
4784
		toHide.attr( {
4785
			"aria-hidden": "true"
4786
		} );
4787
		toHide.prev().attr( {
4788
			"aria-selected": "false",
4789
			"aria-expanded": "false"
4790
		} );
4791
4792
		// if we're switching panels, remove the old header from the tab order
4793
		// if we're opening from collapsed state, remove the previous header from the tab order
4794
		// if we're collapsing, then keep the collapsing header in the tab order
4795
		if ( toShow.length && toHide.length ) {
4796
			toHide.prev().attr( {
4797
				"tabIndex": -1,
4798
				"aria-expanded": "false"
4799
			} );
4800
		} else if ( toShow.length ) {
4801
			this.headers.filter( function() {
4802
				return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
4803
			} )
4804
				.attr( "tabIndex", -1 );
4805
		}
4806
4807
		toShow
4808
			.attr( "aria-hidden", "false" )
4809
			.prev()
4810
				.attr( {
4811
					"aria-selected": "true",
4812
					"aria-expanded": "true",
4813
					tabIndex: 0
4814
				} );
4815
	},
4816
4817
	_animate: function( toShow, toHide, data ) {
4818
		var total, easing, duration,
4819
			that = this,
4820
			adjust = 0,
4821
			boxSizing = toShow.css( "box-sizing" ),
4822
			down = toShow.length &&
4823
				( !toHide.length || ( toShow.index() < toHide.index() ) ),
4824
			animate = this.options.animate || {},
4825
			options = down && animate.down || animate,
4826
			complete = function() {
4827
				that._toggleComplete( data );
4828
			};
4829
4830
		if ( typeof options === "number" ) {
4831
			duration = options;
4832
		}
4833
		if ( typeof options === "string" ) {
4834
			easing = options;
4835
		}
4836
4837
		// fall back from options to animation in case of partial down settings
4838
		easing = easing || options.easing || animate.easing;
4839
		duration = duration || options.duration || animate.duration;
4840
4841
		if ( !toHide.length ) {
4842
			return toShow.animate( this.showProps, duration, easing, complete );
4843
		}
4844
		if ( !toShow.length ) {
4845
			return toHide.animate( this.hideProps, duration, easing, complete );
4846
		}
4847
4848
		total = toShow.show().outerHeight();
4849
		toHide.animate( this.hideProps, {
4850
			duration: duration,
4851
			easing: easing,
4852
			step: function( now, fx ) {
4853
				fx.now = Math.round( now );
4854
			}
4855
		} );
4856
		toShow
4857
			.hide()
4858
			.animate( this.showProps, {
4859
				duration: duration,
4860
				easing: easing,
4861
				complete: complete,
4862
				step: function( now, fx ) {
4863
					fx.now = Math.round( now );
4864
					if ( fx.prop !== "height" ) {
4865
						if ( boxSizing === "content-box" ) {
4866
							adjust += fx.now;
4867
						}
4868
					} else if ( that.options.heightStyle !== "content" ) {
4869
						fx.now = Math.round( total - toHide.outerHeight() - adjust );
4870
						adjust = 0;
4871
					}
4872
				}
4873
			} );
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
4874
	},
4875
4876
	_toggleComplete: function( data ) {
4877
		var toHide = data.oldPanel,
4878
			prev = toHide.prev();
4879
4880
		this._removeClass( toHide, "ui-accordion-content-active" );
4881
		this._removeClass( prev, "ui-accordion-header-active" )
4882
			._addClass( prev, "ui-accordion-header-collapsed" );
4883
4884
		// Work around for rendering bug in IE (#5421)
4885
		if ( toHide.length ) {
4886
			toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
4887
		}
4888
		this._trigger( "activate", null, data );
4889
	}
4890
} );
4891
4892
4893
4894
var safeActiveElement = $.ui.safeActiveElement = function( document ) {
4895
	var activeElement;
4896
4897
	// Support: IE 9 only
4898
	// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
4899
	try {
4900
		activeElement = document.activeElement;
4901
	} catch ( error ) {
4902
		activeElement = document.body;
4903
	}
4904
4905
	// Support: IE 9 - 11 only
4906
	// IE may return null instead of an element
4907
	// Interestingly, this only seems to occur when NOT in an iframe
4908
	if ( !activeElement ) {
4909
		activeElement = document.body;
4910
	}
4911
4912
	// Support: IE 11 only
4913
	// IE11 returns a seemingly empty object in some cases when accessing
4914
	// document.activeElement from an <iframe>
4915
	if ( !activeElement.nodeName ) {
4916
		activeElement = document.body;
4917
	}
4918
4919
	return activeElement;
4920
};
4921
4922
4923
/*!
4924
 * jQuery UI Menu 1.12.1
4925
 * http://jqueryui.com
4926
 *
4927
 * Copyright jQuery Foundation and other contributors
4928
 * Released under the MIT license.
4929
 * http://jquery.org/license
4930
 */
4931
4932
//>>label: Menu
4933
//>>group: Widgets
4934
//>>description: Creates nestable menus.
4935
//>>docs: http://api.jqueryui.com/menu/
4936
//>>demos: http://jqueryui.com/menu/
4937
//>>css.structure: ../../themes/base/core.css
4938
//>>css.structure: ../../themes/base/menu.css
4939
//>>css.theme: ../../themes/base/theme.css
4940
4941
4942
4943
var widgetsMenu = $.widget( "ui.menu", {
0 ignored issues
show
Unused Code introduced by
The variable widgetsMenu seems to be never used. Consider removing it.
Loading history...
4944
	version: "1.12.1",
4945
	defaultElement: "<ul>",
4946
	delay: 300,
4947
	options: {
4948
		icons: {
4949
			submenu: "ui-icon-caret-1-e"
4950
		},
4951
		items: "> *",
4952
		menus: "ul",
4953
		position: {
4954
			my: "left top",
4955
			at: "right top"
4956
		},
4957
		role: "menu",
4958
4959
		// Callbacks
4960
		blur: null,
4961
		focus: null,
4962
		select: null
4963
	},
4964
4965
	_create: function() {
4966
		this.activeMenu = this.element;
4967
4968
		// Flag used to prevent firing of the click handler
4969
		// as the event bubbles up through nested menus
4970
		this.mouseHandled = false;
4971
		this.element
4972
			.uniqueId()
4973
			.attr( {
4974
				role: this.options.role,
4975
				tabIndex: 0
4976
			} );
4977
4978
		this._addClass( "ui-menu", "ui-widget ui-widget-content" );
4979
		this._on( {
4980
4981
			// Prevent focus from sticking to links inside menu after clicking
4982
			// them (focus should always stay on UL during navigation).
4983
			"mousedown .ui-menu-item": function( event ) {
4984
				event.preventDefault();
4985
			},
4986
			"click .ui-menu-item": function( event ) {
4987
				var target = $( event.target );
4988
				var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
4989
				if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
4990
					this.select( event );
4991
4992
					// Only set the mouseHandled flag if the event will bubble, see #9469.
4993
					if ( !event.isPropagationStopped() ) {
4994
						this.mouseHandled = true;
4995
					}
4996
4997
					// Open submenu on click
4998
					if ( target.has( ".ui-menu" ).length ) {
4999
						this.expand( event );
5000
					} else if ( !this.element.is( ":focus" ) &&
5001
							active.closest( ".ui-menu" ).length ) {
5002
5003
						// Redirect focus to the menu
5004
						this.element.trigger( "focus", [ true ] );
5005
5006
						// If the active item is on the top level, let it stay active.
5007
						// Otherwise, blur the active item since it is no longer visible.
5008
						if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
5009
							clearTimeout( this.timer );
5010
						}
5011
					}
5012
				}
5013
			},
5014
			"mouseenter .ui-menu-item": function( event ) {
5015
5016
				// Ignore mouse events while typeahead is active, see #10458.
5017
				// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
5018
				// is over an item in the menu
5019
				if ( this.previousFilter ) {
5020
					return;
5021
				}
5022
5023
				var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
5024
					target = $( event.currentTarget );
5025
5026
				// Ignore bubbled events on parent items, see #11641
5027
				if ( actualTarget[ 0 ] !== target[ 0 ] ) {
5028
					return;
5029
				}
5030
5031
				// Remove ui-state-active class from siblings of the newly focused menu item
5032
				// to avoid a jump caused by adjacent elements both having a class with a border
5033
				this._removeClass( target.siblings().children( ".ui-state-active" ),
5034
					null, "ui-state-active" );
5035
				this.focus( event, target );
5036
			},
5037
			mouseleave: "collapseAll",
5038
			"mouseleave .ui-menu": "collapseAll",
5039
			focus: function( event, keepActiveItem ) {
5040
5041
				// If there's already an active item, keep it active
5042
				// If not, activate the first item
5043
				var item = this.active || this.element.find( this.options.items ).eq( 0 );
5044
5045
				if ( !keepActiveItem ) {
5046
					this.focus( event, item );
5047
				}
5048
			},
5049
			blur: function( event ) {
5050
				this._delay( function() {
5051
					var notContained = !$.contains(
5052
						this.element[ 0 ],
5053
						$.ui.safeActiveElement( this.document[ 0 ] )
5054
					);
5055
					if ( notContained ) {
5056
						this.collapseAll( event );
5057
					}
5058
				} );
5059
			},
5060
			keydown: "_keydown"
5061
		} );
5062
5063
		this.refresh();
5064
5065
		// Clicks outside of a menu collapse any open menus
5066
		this._on( this.document, {
5067
			click: function( event ) {
5068
				if ( this._closeOnDocumentClick( event ) ) {
5069
					this.collapseAll( event );
5070
				}
5071
5072
				// Reset the mouseHandled flag
5073
				this.mouseHandled = false;
5074
			}
5075
		} );
5076
	},
5077
5078
	_destroy: function() {
5079
		var items = this.element.find( ".ui-menu-item" )
5080
				.removeAttr( "role aria-disabled" ),
5081
			submenus = items.children( ".ui-menu-item-wrapper" )
5082
				.removeUniqueId()
5083
				.removeAttr( "tabIndex role aria-haspopup" );
5084
5085
		// Destroy (sub)menus
5086
		this.element
5087
			.removeAttr( "aria-activedescendant" )
5088
			.find( ".ui-menu" ).addBack()
5089
				.removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
5090
					"tabIndex" )
5091
				.removeUniqueId()
5092
				.show();
5093
5094
		submenus.children().each( function() {
5095
			var elem = $( this );
5096
			if ( elem.data( "ui-menu-submenu-caret" ) ) {
5097
				elem.remove();
5098
			}
5099
		} );
5100
	},
5101
5102
	_keydown: function( event ) {
5103
		var match, prev, character, skip,
5104
			preventDefault = true;
5105
5106
		switch ( event.keyCode ) {
5107
		case $.ui.keyCode.PAGE_UP:
5108
			this.previousPage( event );
5109
			break;
5110
		case $.ui.keyCode.PAGE_DOWN:
5111
			this.nextPage( event );
5112
			break;
5113
		case $.ui.keyCode.HOME:
5114
			this._move( "first", "first", event );
5115
			break;
5116
		case $.ui.keyCode.END:
5117
			this._move( "last", "last", event );
5118
			break;
5119
		case $.ui.keyCode.UP:
5120
			this.previous( event );
5121
			break;
5122
		case $.ui.keyCode.DOWN:
5123
			this.next( event );
5124
			break;
5125
		case $.ui.keyCode.LEFT:
5126
			this.collapse( event );
5127
			break;
5128
		case $.ui.keyCode.RIGHT:
5129
			if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5130
				this.expand( event );
5131
			}
5132
			break;
5133
		case $.ui.keyCode.ENTER:
5134
		case $.ui.keyCode.SPACE:
5135
			this._activate( event );
5136
			break;
5137
		case $.ui.keyCode.ESCAPE:
5138
			this.collapse( event );
5139
			break;
5140
		default:
5141
			preventDefault = false;
5142
			prev = this.previousFilter || "";
5143
			skip = false;
5144
5145
			// Support number pad values
5146
			character = event.keyCode >= 96 && event.keyCode <= 105 ?
5147
				( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
5148
5149
			clearTimeout( this.filterTimer );
5150
5151
			if ( character === prev ) {
5152
				skip = true;
5153
			} else {
5154
				character = prev + character;
5155
			}
5156
5157
			match = this._filterMenuItems( character );
5158
			match = skip && match.index( this.active.next() ) !== -1 ?
5159
				this.active.nextAll( ".ui-menu-item" ) :
5160
				match;
5161
5162
			// If no matches on the current filter, reset to the last character pressed
5163
			// to move down the menu to the first item that starts with that character
5164
			if ( !match.length ) {
5165
				character = String.fromCharCode( event.keyCode );
5166
				match = this._filterMenuItems( character );
5167
			}
5168
5169
			if ( match.length ) {
5170
				this.focus( event, match );
5171
				this.previousFilter = character;
5172
				this.filterTimer = this._delay( function() {
5173
					delete this.previousFilter;
5174
				}, 1000 );
5175
			} else {
5176
				delete this.previousFilter;
5177
			}
5178
		}
5179
5180
		if ( preventDefault ) {
5181
			event.preventDefault();
5182
		}
5183
	},
5184
5185
	_activate: function( event ) {
5186
		if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5187
			if ( this.active.children( "[aria-haspopup='true']" ).length ) {
5188
				this.expand( event );
5189
			} else {
5190
				this.select( event );
5191
			}
5192
		}
5193
	},
5194
5195
	refresh: function() {
5196
		var menus, items, newSubmenus, newItems, newWrappers,
5197
			that = this,
5198
			icon = this.options.icons.submenu,
5199
			submenus = this.element.find( this.options.menus );
5200
5201
		this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
5202
5203
		// Initialize nested menus
5204
		newSubmenus = submenus.filter( ":not(.ui-menu)" )
5205
			.hide()
5206
			.attr( {
5207
				role: this.options.role,
5208
				"aria-hidden": "true",
5209
				"aria-expanded": "false"
5210
			} )
5211
			.each( function() {
5212
				var menu = $( this ),
5213
					item = menu.prev(),
5214
					submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
5215
5216
				that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
5217
				item
5218
					.attr( "aria-haspopup", "true" )
5219
					.prepend( submenuCaret );
5220
				menu.attr( "aria-labelledby", item.attr( "id" ) );
5221
			} );
5222
5223
		this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
5224
5225
		menus = submenus.add( this.element );
5226
		items = menus.find( this.options.items );
5227
5228
		// Initialize menu-items containing spaces and/or dashes only as dividers
5229
		items.not( ".ui-menu-item" ).each( function() {
5230
			var item = $( this );
5231
			if ( that._isDivider( item ) ) {
5232
				that._addClass( item, "ui-menu-divider", "ui-widget-content" );
5233
			}
5234
		} );
5235
5236
		// Don't refresh list items that are already adapted
5237
		newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
5238
		newWrappers = newItems.children()
5239
			.not( ".ui-menu" )
5240
				.uniqueId()
5241
				.attr( {
5242
					tabIndex: -1,
5243
					role: this._itemRole()
5244
				} );
5245
		this._addClass( newItems, "ui-menu-item" )
5246
			._addClass( newWrappers, "ui-menu-item-wrapper" );
5247
5248
		// Add aria-disabled attribute to any disabled menu item
5249
		items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
5250
5251
		// If the active item has been removed, blur the menu
5252
		if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
5253
			this.blur();
5254
		}
5255
	},
5256
5257
	_itemRole: function() {
5258
		return {
5259
			menu: "menuitem",
5260
			listbox: "option"
5261
		}[ this.options.role ];
5262
	},
5263
5264
	_setOption: function( key, value ) {
5265
		if ( key === "icons" ) {
5266
			var icons = this.element.find( ".ui-menu-icon" );
5267
			this._removeClass( icons, null, this.options.icons.submenu )
5268
				._addClass( icons, null, value.submenu );
5269
		}
5270
		this._super( key, value );
5271
	},
5272
5273
	_setOptionDisabled: function( value ) {
5274
		this._super( value );
5275
5276
		this.element.attr( "aria-disabled", String( value ) );
5277
		this._toggleClass( null, "ui-state-disabled", !!value );
5278
	},
5279
5280
	focus: function( event, item ) {
5281
		var nested, focused, activeParent;
5282
		this.blur( event, event && event.type === "focus" );
5283
5284
		this._scrollIntoView( item );
5285
5286
		this.active = item.first();
5287
5288
		focused = this.active.children( ".ui-menu-item-wrapper" );
5289
		this._addClass( focused, null, "ui-state-active" );
5290
5291
		// Only update aria-activedescendant if there's a role
5292
		// otherwise we assume focus is managed elsewhere
5293
		if ( this.options.role ) {
5294
			this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
5295
		}
5296
5297
		// Highlight active parent menu item, if any
5298
		activeParent = this.active
5299
			.parent()
5300
				.closest( ".ui-menu-item" )
5301
					.children( ".ui-menu-item-wrapper" );
5302
		this._addClass( activeParent, null, "ui-state-active" );
5303
5304
		if ( event && event.type === "keydown" ) {
5305
			this._close();
5306
		} else {
5307
			this.timer = this._delay( function() {
5308
				this._close();
5309
			}, this.delay );
5310
		}
5311
5312
		nested = item.children( ".ui-menu" );
5313
		if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
5314
			this._startOpening( nested );
5315
		}
5316
		this.activeMenu = item.parent();
5317
5318
		this._trigger( "focus", event, { item: item } );
5319
	},
5320
5321
	_scrollIntoView: function( item ) {
5322
		var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
5323
		if ( this._hasScroll() ) {
5324
			borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
5325
			paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
5326
			offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
5327
			scroll = this.activeMenu.scrollTop();
5328
			elementHeight = this.activeMenu.height();
5329
			itemHeight = item.outerHeight();
5330
5331
			if ( offset < 0 ) {
5332
				this.activeMenu.scrollTop( scroll + offset );
5333
			} else if ( offset + itemHeight > elementHeight ) {
5334
				this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
5335
			}
5336
		}
5337
	},
5338
5339
	blur: function( event, fromFocus ) {
5340
		if ( !fromFocus ) {
5341
			clearTimeout( this.timer );
5342
		}
5343
5344
		if ( !this.active ) {
5345
			return;
5346
		}
5347
5348
		this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
5349
			null, "ui-state-active" );
5350
5351
		this._trigger( "blur", event, { item: this.active } );
5352
		this.active = null;
5353
	},
5354
5355
	_startOpening: function( submenu ) {
5356
		clearTimeout( this.timer );
5357
5358
		// Don't open if already open fixes a Firefox bug that caused a .5 pixel
5359
		// shift in the submenu position when mousing over the caret icon
5360
		if ( submenu.attr( "aria-hidden" ) !== "true" ) {
5361
			return;
5362
		}
5363
5364
		this.timer = this._delay( function() {
5365
			this._close();
5366
			this._open( submenu );
5367
		}, this.delay );
5368
	},
5369
5370
	_open: function( submenu ) {
5371
		var position = $.extend( {
5372
			of: this.active
5373
		}, this.options.position );
5374
5375
		clearTimeout( this.timer );
5376
		this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
5377
			.hide()
5378
			.attr( "aria-hidden", "true" );
5379
5380
		submenu
5381
			.show()
5382
			.removeAttr( "aria-hidden" )
5383
			.attr( "aria-expanded", "true" )
5384
			.position( position );
5385
	},
5386
5387
	collapseAll: function( event, all ) {
5388
		clearTimeout( this.timer );
5389
		this.timer = this._delay( function() {
5390
5391
			// If we were passed an event, look for the submenu that contains the event
5392
			var currentMenu = all ? this.element :
5393
				$( event && event.target ).closest( this.element.find( ".ui-menu" ) );
5394
5395
			// If we found no valid submenu ancestor, use the main menu to close all
5396
			// sub menus anyway
5397
			if ( !currentMenu.length ) {
5398
				currentMenu = this.element;
5399
			}
5400
5401
			this._close( currentMenu );
5402
5403
			this.blur( event );
5404
5405
			// Work around active item staying active after menu is blurred
5406
			this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
5407
5408
			this.activeMenu = currentMenu;
5409
		}, this.delay );
5410
	},
5411
5412
	// With no arguments, closes the currently active menu - if nothing is active
5413
	// it closes all menus.  If passed an argument, it will search for menus BELOW
5414
	_close: function( startMenu ) {
5415
		if ( !startMenu ) {
5416
			startMenu = this.active ? this.active.parent() : this.element;
5417
		}
5418
5419
		startMenu.find( ".ui-menu" )
5420
			.hide()
5421
			.attr( "aria-hidden", "true" )
5422
			.attr( "aria-expanded", "false" );
5423
	},
5424
5425
	_closeOnDocumentClick: function( event ) {
5426
		return !$( event.target ).closest( ".ui-menu" ).length;
5427
	},
5428
5429
	_isDivider: function( item ) {
5430
5431
		// Match hyphen, em dash, en dash
5432
		return !/[^\-\u2014\u2013\s]/.test( item.text() );
5433
	},
5434
5435
	collapse: function( event ) {
5436
		var newItem = this.active &&
5437
			this.active.parent().closest( ".ui-menu-item", this.element );
5438
		if ( newItem && newItem.length ) {
5439
			this._close();
5440
			this.focus( event, newItem );
5441
		}
5442
	},
5443
5444
	expand: function( event ) {
5445
		var newItem = this.active &&
5446
			this.active
5447
				.children( ".ui-menu " )
5448
					.find( this.options.items )
5449
						.first();
5450
5451
		if ( newItem && newItem.length ) {
5452
			this._open( newItem.parent() );
5453
5454
			// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
5455
			this._delay( function() {
5456
				this.focus( event, newItem );
5457
			} );
5458
		}
5459
	},
5460
5461
	next: function( event ) {
5462
		this._move( "next", "first", event );
5463
	},
5464
5465
	previous: function( event ) {
5466
		this._move( "prev", "last", event );
5467
	},
5468
5469
	isFirstItem: function() {
5470
		return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
5471
	},
5472
5473
	isLastItem: function() {
5474
		return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
5475
	},
5476
5477
	_move: function( direction, filter, event ) {
5478
		var next;
5479
		if ( this.active ) {
5480
			if ( direction === "first" || direction === "last" ) {
5481
				next = this.active
5482
					[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
5483
					.eq( -1 );
5484
			} else {
5485
				next = this.active
5486
					[ direction + "All" ]( ".ui-menu-item" )
5487
					.eq( 0 );
5488
			}
5489
		}
5490
		if ( !next || !next.length || !this.active ) {
5491
			next = this.activeMenu.find( this.options.items )[ filter ]();
5492
		}
5493
5494
		this.focus( event, next );
5495
	},
5496
5497
	nextPage: function( event ) {
5498
		var item, base, height;
5499
5500
		if ( !this.active ) {
5501
			this.next( event );
5502
			return;
5503
		}
5504
		if ( this.isLastItem() ) {
5505
			return;
5506
		}
5507
		if ( this._hasScroll() ) {
5508
			base = this.active.offset().top;
5509
			height = this.element.height();
5510
			this.active.nextAll( ".ui-menu-item" ).each( function() {
5511
				item = $( this );
5512
				return item.offset().top - base - height < 0;
5513
			} );
5514
5515
			this.focus( event, item );
5516
		} else {
5517
			this.focus( event, this.activeMenu.find( this.options.items )
5518
				[ !this.active ? "first" : "last" ]() );
5519
		}
5520
	},
5521
5522
	previousPage: function( event ) {
5523
		var item, base, height;
5524
		if ( !this.active ) {
5525
			this.next( event );
5526
			return;
5527
		}
5528
		if ( this.isFirstItem() ) {
5529
			return;
5530
		}
5531
		if ( this._hasScroll() ) {
5532
			base = this.active.offset().top;
5533
			height = this.element.height();
5534
			this.active.prevAll( ".ui-menu-item" ).each( function() {
5535
				item = $( this );
5536
				return item.offset().top - base + height > 0;
5537
			} );
5538
5539
			this.focus( event, item );
5540
		} else {
5541
			this.focus( event, this.activeMenu.find( this.options.items ).first() );
5542
		}
5543
	},
5544
5545
	_hasScroll: function() {
5546
		return this.element.outerHeight() < this.element.prop( "scrollHeight" );
5547
	},
5548
5549
	select: function( event ) {
5550
5551
		// TODO: It should never be possible to not have an active item at this
5552
		// point, but the tests don't trigger mouseenter before click.
5553
		this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
5554
		var ui = { item: this.active };
5555
		if ( !this.active.has( ".ui-menu" ).length ) {
5556
			this.collapseAll( event, true );
5557
		}
5558
		this._trigger( "select", event, ui );
5559
	},
5560
5561
	_filterMenuItems: function( character ) {
5562
		var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
5563
			regex = new RegExp( "^" + escapedCharacter, "i" );
5564
5565
		return this.activeMenu
5566
			.find( this.options.items )
5567
5568
				// Only match on items, not dividers or other content (#10571)
5569
				.filter( ".ui-menu-item" )
5570
					.filter( function() {
5571
						return regex.test(
5572
							$.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
5573
					} );
5574
	}
5575
} );
5576
5577
5578
/*!
5579
 * jQuery UI Autocomplete 1.12.1
5580
 * http://jqueryui.com
5581
 *
5582
 * Copyright jQuery Foundation and other contributors
5583
 * Released under the MIT license.
5584
 * http://jquery.org/license
5585
 */
5586
5587
//>>label: Autocomplete
5588
//>>group: Widgets
5589
//>>description: Lists suggested words as the user is typing.
5590
//>>docs: http://api.jqueryui.com/autocomplete/
5591
//>>demos: http://jqueryui.com/autocomplete/
5592
//>>css.structure: ../../themes/base/core.css
5593
//>>css.structure: ../../themes/base/autocomplete.css
5594
//>>css.theme: ../../themes/base/theme.css
5595
5596
5597
5598
$.widget( "ui.autocomplete", {
5599
	version: "1.12.1",
5600
	defaultElement: "<input>",
5601
	options: {
5602
		appendTo: null,
5603
		autoFocus: false,
5604
		delay: 300,
5605
		minLength: 1,
5606
		position: {
5607
			my: "left top",
5608
			at: "left bottom",
5609
			collision: "none"
5610
		},
5611
		source: null,
5612
5613
		// Callbacks
5614
		change: null,
5615
		close: null,
5616
		focus: null,
5617
		open: null,
5618
		response: null,
5619
		search: null,
5620
		select: null
5621
	},
5622
5623
	requestIndex: 0,
5624
	pending: 0,
5625
5626
	_create: function() {
5627
5628
		// Some browsers only repeat keydown events, not keypress events,
5629
		// so we use the suppressKeyPress flag to determine if we've already
5630
		// handled the keydown event. #7269
5631
		// Unfortunately the code for & in keypress is the same as the up arrow,
5632
		// so we use the suppressKeyPressRepeat flag to avoid handling keypress
5633
		// events when we know the keydown event was used to modify the
5634
		// search term. #7799
5635
		var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
5636
			nodeName = this.element[ 0 ].nodeName.toLowerCase(),
5637
			isTextarea = nodeName === "textarea",
5638
			isInput = nodeName === "input";
5639
5640
		// Textareas are always multi-line
5641
		// Inputs are always single-line, even if inside a contentEditable element
5642
		// IE also treats inputs as contentEditable
5643
		// All other element types are determined by whether or not they're contentEditable
5644
		this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
5645
5646
		this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
5647
		this.isNewMenu = true;
5648
5649
		this._addClass( "ui-autocomplete-input" );
5650
		this.element.attr( "autocomplete", "off" );
5651
5652
		this._on( this.element, {
5653
			keydown: function( event ) {
5654
				if ( this.element.prop( "readOnly" ) ) {
5655
					suppressKeyPress = true;
5656
					suppressInput = true;
5657
					suppressKeyPressRepeat = true;
5658
					return;
5659
				}
5660
5661
				suppressKeyPress = false;
5662
				suppressInput = false;
5663
				suppressKeyPressRepeat = false;
5664
				var keyCode = $.ui.keyCode;
5665
				switch ( event.keyCode ) {
5666
				case keyCode.PAGE_UP:
5667
					suppressKeyPress = true;
5668
					this._move( "previousPage", event );
5669
					break;
5670
				case keyCode.PAGE_DOWN:
5671
					suppressKeyPress = true;
5672
					this._move( "nextPage", event );
5673
					break;
5674
				case keyCode.UP:
5675
					suppressKeyPress = true;
5676
					this._keyEvent( "previous", event );
5677
					break;
5678
				case keyCode.DOWN:
5679
					suppressKeyPress = true;
5680
					this._keyEvent( "next", event );
5681
					break;
5682
				case keyCode.ENTER:
5683
5684
					// when menu is open and has focus
5685
					if ( this.menu.active ) {
5686
5687
						// #6055 - Opera still allows the keypress to occur
5688
						// which causes forms to submit
5689
						suppressKeyPress = true;
5690
						event.preventDefault();
5691
						this.menu.select( event );
5692
					}
5693
					break;
5694
				case keyCode.TAB:
5695
					if ( this.menu.active ) {
5696
						this.menu.select( event );
5697
					}
5698
					break;
5699
				case keyCode.ESCAPE:
5700
					if ( this.menu.element.is( ":visible" ) ) {
5701
						if ( !this.isMultiLine ) {
5702
							this._value( this.term );
5703
						}
5704
						this.close( event );
5705
5706
						// Different browsers have different default behavior for escape
5707
						// Single press can mean undo or clear
5708
						// Double press in IE means clear the whole form
5709
						event.preventDefault();
5710
					}
5711
					break;
5712
				default:
5713
					suppressKeyPressRepeat = true;
5714
5715
					// search timeout should be triggered before the input value is changed
5716
					this._searchTimeout( event );
5717
					break;
5718
				}
5719
			},
5720
			keypress: function( event ) {
5721
				if ( suppressKeyPress ) {
5722
					suppressKeyPress = false;
5723
					if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5724
						event.preventDefault();
5725
					}
5726
					return;
5727
				}
5728
				if ( suppressKeyPressRepeat ) {
5729
					return;
5730
				}
5731
5732
				// Replicate some key handlers to allow them to repeat in Firefox and Opera
5733
				var keyCode = $.ui.keyCode;
5734
				switch ( event.keyCode ) {
5735
				case keyCode.PAGE_UP:
5736
					this._move( "previousPage", event );
5737
					break;
5738
				case keyCode.PAGE_DOWN:
5739
					this._move( "nextPage", event );
5740
					break;
5741
				case keyCode.UP:
5742
					this._keyEvent( "previous", event );
5743
					break;
5744
				case keyCode.DOWN:
5745
					this._keyEvent( "next", event );
5746
					break;
5747
				}
5748
			},
5749
			input: function( event ) {
5750
				if ( suppressInput ) {
5751
					suppressInput = false;
5752
					event.preventDefault();
5753
					return;
5754
				}
5755
				this._searchTimeout( event );
5756
			},
5757
			focus: function() {
5758
				this.selectedItem = null;
5759
				this.previous = this._value();
5760
			},
5761
			blur: function( event ) {
5762
				if ( this.cancelBlur ) {
5763
					delete this.cancelBlur;
5764
					return;
5765
				}
5766
5767
				clearTimeout( this.searching );
5768
				this.close( event );
5769
				this._change( event );
5770
			}
5771
		} );
5772
5773
		this._initSource();
5774
		this.menu = $( "<ul>" )
5775
			.appendTo( this._appendTo() )
5776
			.menu( {
5777
5778
				// disable ARIA support, the live region takes care of that
5779
				role: null
5780
			} )
5781
			.hide()
5782
			.menu( "instance" );
5783
5784
		this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
5785
		this._on( this.menu.element, {
5786
			mousedown: function( event ) {
5787
5788
				// prevent moving focus out of the text field
5789
				event.preventDefault();
5790
5791
				// IE doesn't prevent moving focus even with event.preventDefault()
5792
				// so we set a flag to know when we should ignore the blur event
5793
				this.cancelBlur = true;
5794
				this._delay( function() {
5795
					delete this.cancelBlur;
5796
5797
					// Support: IE 8 only
5798
					// Right clicking a menu item or selecting text from the menu items will
5799
					// result in focus moving out of the input. However, we've already received
5800
					// and ignored the blur event because of the cancelBlur flag set above. So
5801
					// we restore focus to ensure that the menu closes properly based on the user's
5802
					// next actions.
5803
					if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
5804
						this.element.trigger( "focus" );
5805
					}
5806
				} );
5807
			},
5808
			menufocus: function( event, ui ) {
5809
				var label, item;
5810
5811
				// support: Firefox
5812
				// Prevent accidental activation of menu items in Firefox (#7024 #9118)
5813
				if ( this.isNewMenu ) {
5814
					this.isNewMenu = false;
5815
					if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
5816
						this.menu.blur();
5817
5818
						this.document.one( "mousemove", function() {
5819
							$( event.target ).trigger( event.originalEvent );
5820
						} );
5821
5822
						return;
5823
					}
5824
				}
5825
5826
				item = ui.item.data( "ui-autocomplete-item" );
5827
				if ( false !== this._trigger( "focus", event, { item: item } ) ) {
5828
5829
					// use value to match what will end up in the input, if it was a key event
5830
					if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
5831
						this._value( item.value );
5832
					}
5833
				}
5834
5835
				// Announce the value in the liveRegion
5836
				label = ui.item.attr( "aria-label" ) || item.value;
5837
				if ( label && $.trim( label ).length ) {
5838
					this.liveRegion.children().hide();
5839
					$( "<div>" ).text( label ).appendTo( this.liveRegion );
5840
				}
5841
			},
5842
			menuselect: function( event, ui ) {
5843
				var item = ui.item.data( "ui-autocomplete-item" ),
5844
					previous = this.previous;
5845
5846
				// Only trigger when focus was lost (click on menu)
5847
				if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
5848
					this.element.trigger( "focus" );
5849
					this.previous = previous;
5850
5851
					// #6109 - IE triggers two focus events and the second
5852
					// is asynchronous, so we need to reset the previous
5853
					// term synchronously and asynchronously :-(
5854
					this._delay( function() {
5855
						this.previous = previous;
5856
						this.selectedItem = item;
5857
					} );
5858
				}
5859
5860
				if ( false !== this._trigger( "select", event, { item: item } ) ) {
5861
					this._value( item.value );
5862
				}
5863
5864
				// reset the term after the select event
5865
				// this allows custom select handling to work properly
5866
				this.term = this._value();
5867
5868
				this.close( event );
5869
				this.selectedItem = item;
5870
			}
5871
		} );
5872
5873
		this.liveRegion = $( "<div>", {
5874
			role: "status",
5875
			"aria-live": "assertive",
5876
			"aria-relevant": "additions"
5877
		} )
5878
			.appendTo( this.document[ 0 ].body );
5879
5880
		this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
5881
5882
		// Turning off autocomplete prevents the browser from remembering the
5883
		// value when navigating through history, so we re-enable autocomplete
5884
		// if the page is unloaded before the widget is destroyed. #7790
5885
		this._on( this.window, {
5886
			beforeunload: function() {
5887
				this.element.removeAttr( "autocomplete" );
5888
			}
5889
		} );
5890
	},
5891
5892
	_destroy: function() {
5893
		clearTimeout( this.searching );
5894
		this.element.removeAttr( "autocomplete" );
5895
		this.menu.element.remove();
5896
		this.liveRegion.remove();
5897
	},
5898
5899
	_setOption: function( key, value ) {
5900
		this._super( key, value );
5901
		if ( key === "source" ) {
5902
			this._initSource();
5903
		}
5904
		if ( key === "appendTo" ) {
5905
			this.menu.element.appendTo( this._appendTo() );
5906
		}
5907
		if ( key === "disabled" && value && this.xhr ) {
5908
			this.xhr.abort();
5909
		}
5910
	},
5911
5912
	_isEventTargetInWidget: function( event ) {
5913
		var menuElement = this.menu.element[ 0 ];
5914
5915
		return event.target === this.element[ 0 ] ||
5916
			event.target === menuElement ||
5917
			$.contains( menuElement, event.target );
5918
	},
5919
5920
	_closeOnClickOutside: function( event ) {
5921
		if ( !this._isEventTargetInWidget( event ) ) {
5922
			this.close();
5923
		}
5924
	},
5925
5926
	_appendTo: function() {
5927
		var element = this.options.appendTo;
5928
5929
		if ( element ) {
5930
			element = element.jquery || element.nodeType ?
5931
				$( element ) :
5932
				this.document.find( element ).eq( 0 );
5933
		}
5934
5935
		if ( !element || !element[ 0 ] ) {
5936
			element = this.element.closest( ".ui-front, dialog" );
5937
		}
5938
5939
		if ( !element.length ) {
5940
			element = this.document[ 0 ].body;
5941
		}
5942
5943
		return element;
5944
	},
5945
5946
	_initSource: function() {
5947
		var array, url,
5948
			that = this;
5949
		if ( $.isArray( this.options.source ) ) {
5950
			array = this.options.source;
5951
			this.source = function( request, response ) {
5952
				response( $.ui.autocomplete.filter( array, request.term ) );
5953
			};
5954
		} else if ( typeof this.options.source === "string" ) {
5955
			url = this.options.source;
5956
			this.source = function( request, response ) {
5957
				if ( that.xhr ) {
5958
					that.xhr.abort();
5959
				}
5960
				that.xhr = $.ajax( {
5961
					url: url,
5962
					data: request,
5963
					dataType: "json",
5964
					success: function( data ) {
5965
						response( data );
5966
					},
5967
					error: function() {
5968
						response( [] );
5969
					}
5970
				} );
5971
			};
5972
		} else {
5973
			this.source = this.options.source;
5974
		}
5975
	},
5976
5977
	_searchTimeout: function( event ) {
5978
		clearTimeout( this.searching );
5979
		this.searching = this._delay( function() {
5980
5981
			// Search if the value has changed, or if the user retypes the same value (see #7434)
5982
			var equalValues = this.term === this._value(),
5983
				menuVisible = this.menu.element.is( ":visible" ),
5984
				modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
5985
5986
			if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
5987
				this.selectedItem = null;
5988
				this.search( null, event );
5989
			}
5990
		}, this.options.delay );
5991
	},
5992
5993
	search: function( value, event ) {
5994
		value = value != null ? value : this._value();
0 ignored issues
show
Best Practice introduced by
Comparing value to null using the != operator is not safe. Consider using !== instead.
Loading history...
5995
5996
		// Always save the actual value, not the one passed as an argument
5997
		this.term = this._value();
5998
5999
		if ( value.length < this.options.minLength ) {
6000
			return this.close( event );
6001
		}
6002
6003
		if ( this._trigger( "search", event ) === false ) {
6004
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
6005
		}
6006
6007
		return this._search( value );
6008
	},
6009
6010
	_search: function( value ) {
6011
		this.pending++;
6012
		this._addClass( "ui-autocomplete-loading" );
6013
		this.cancelSearch = false;
6014
6015
		this.source( { term: value }, this._response() );
6016
	},
6017
6018
	_response: function() {
6019
		var index = ++this.requestIndex;
6020
6021
		return $.proxy( function( content ) {
6022
			if ( index === this.requestIndex ) {
6023
				this.__response( content );
6024
			}
6025
6026
			this.pending--;
6027
			if ( !this.pending ) {
6028
				this._removeClass( "ui-autocomplete-loading" );
6029
			}
6030
		}, this );
6031
	},
6032
6033
	__response: function( content ) {
6034
		if ( content ) {
6035
			content = this._normalize( content );
6036
		}
6037
		this._trigger( "response", null, { content: content } );
6038
		if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
6039
			this._suggest( content );
6040
			this._trigger( "open" );
6041
		} else {
6042
6043
			// use ._close() instead of .close() so we don't cancel future searches
6044
			this._close();
6045
		}
6046
	},
6047
6048
	close: function( event ) {
6049
		this.cancelSearch = true;
6050
		this._close( event );
6051
	},
6052
6053
	_close: function( event ) {
6054
6055
		// Remove the handler that closes the menu on outside clicks
6056
		this._off( this.document, "mousedown" );
6057
6058
		if ( this.menu.element.is( ":visible" ) ) {
6059
			this.menu.element.hide();
6060
			this.menu.blur();
6061
			this.isNewMenu = true;
6062
			this._trigger( "close", event );
6063
		}
6064
	},
6065
6066
	_change: function( event ) {
6067
		if ( this.previous !== this._value() ) {
6068
			this._trigger( "change", event, { item: this.selectedItem } );
6069
		}
6070
	},
6071
6072
	_normalize: function( items ) {
6073
6074
		// assume all items have the right format when the first item is complete
6075
		if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
6076
			return items;
6077
		}
6078
		return $.map( items, function( item ) {
6079
			if ( typeof item === "string" ) {
6080
				return {
6081
					label: item,
6082
					value: item
6083
				};
6084
			}
6085
			return $.extend( {}, item, {
6086
				label: item.label || item.value,
6087
				value: item.value || item.label
6088
			} );
6089
		} );
6090
	},
6091
6092
	_suggest: function( items ) {
6093
		var ul = this.menu.element.empty();
6094
		this._renderMenu( ul, items );
6095
		this.isNewMenu = true;
6096
		this.menu.refresh();
6097
6098
		// Size and position menu
6099
		ul.show();
6100
		this._resizeMenu();
6101
		ul.position( $.extend( {
6102
			of: this.element
6103
		}, this.options.position ) );
6104
6105
		if ( this.options.autoFocus ) {
6106
			this.menu.next();
6107
		}
6108
6109
		// Listen for interactions outside of the widget (#6642)
6110
		this._on( this.document, {
6111
			mousedown: "_closeOnClickOutside"
6112
		} );
6113
	},
6114
6115
	_resizeMenu: function() {
6116
		var ul = this.menu.element;
6117
		ul.outerWidth( Math.max(
6118
6119
			// Firefox wraps long text (possibly a rounding bug)
6120
			// so we add 1px to avoid the wrapping (#7513)
6121
			ul.width( "" ).outerWidth() + 1,
6122
			this.element.outerWidth()
6123
		) );
6124
	},
6125
6126
	_renderMenu: function( ul, items ) {
6127
		var that = this;
6128
		$.each( items, function( index, item ) {
6129
			that._renderItemData( ul, item );
6130
		} );
6131
	},
6132
6133
	_renderItemData: function( ul, item ) {
6134
		return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
6135
	},
6136
6137
	_renderItem: function( ul, item ) {
6138
		return $( "<li>" )
6139
			.append( $( "<div>" ).text( item.label ) )
6140
			.appendTo( ul );
6141
	},
6142
6143
	_move: function( direction, event ) {
6144
		if ( !this.menu.element.is( ":visible" ) ) {
6145
			this.search( null, event );
6146
			return;
6147
		}
6148
		if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
6149
				this.menu.isLastItem() && /^next/.test( direction ) ) {
6150
6151
			if ( !this.isMultiLine ) {
6152
				this._value( this.term );
6153
			}
6154
6155
			this.menu.blur();
6156
			return;
6157
		}
6158
		this.menu[ direction ]( event );
6159
	},
6160
6161
	widget: function() {
6162
		return this.menu.element;
6163
	},
6164
6165
	_value: function() {
6166
		return this.valueMethod.apply( this.element, arguments );
6167
	},
6168
6169
	_keyEvent: function( keyEvent, event ) {
6170
		if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
6171
			this._move( keyEvent, event );
6172
6173
			// Prevents moving cursor to beginning/end of the text field in some browsers
6174
			event.preventDefault();
6175
		}
6176
	},
6177
6178
	// Support: Chrome <=50
6179
	// We should be able to just use this.element.prop( "isContentEditable" )
6180
	// but hidden elements always report false in Chrome.
6181
	// https://code.google.com/p/chromium/issues/detail?id=313082
6182
	_isContentEditable: function( element ) {
6183
		if ( !element.length ) {
6184
			return false;
6185
		}
6186
6187
		var editable = element.prop( "contentEditable" );
6188
6189
		if ( editable === "inherit" ) {
6190
		  return this._isContentEditable( element.parent() );
6191
		}
6192
6193
		return editable === "true";
6194
	}
6195
} );
6196
6197
$.extend( $.ui.autocomplete, {
6198
	escapeRegex: function( value ) {
6199
		return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
6200
	},
6201
	filter: function( array, term ) {
6202
		var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
6203
		return $.grep( array, function( value ) {
6204
			return matcher.test( value.label || value.value || value );
6205
		} );
6206
	}
6207
} );
6208
6209
// Live region extension, adding a `messages` option
6210
// NOTE: This is an experimental API. We are still investigating
6211
// a full solution for string manipulation and internationalization.
6212
$.widget( "ui.autocomplete", $.ui.autocomplete, {
6213
	options: {
6214
		messages: {
6215
			noResults: "No search results.",
6216
			results: function( amount ) {
6217
				return amount + ( amount > 1 ? " results are" : " result is" ) +
6218
					" available, use up and down arrow keys to navigate.";
6219
			}
6220
		}
6221
	},
6222
6223
	__response: function( content ) {
6224
		var message;
6225
		this._superApply( arguments );
6226
		if ( this.options.disabled || this.cancelSearch ) {
6227
			return;
6228
		}
6229
		if ( content && content.length ) {
6230
			message = this.options.messages.results( content.length );
6231
		} else {
6232
			message = this.options.messages.noResults;
6233
		}
6234
		this.liveRegion.children().hide();
6235
		$( "<div>" ).text( message ).appendTo( this.liveRegion );
6236
	}
6237
} );
6238
6239
var widgetsAutocomplete = $.ui.autocomplete;
0 ignored issues
show
Unused Code introduced by
The variable widgetsAutocomplete seems to be never used. Consider removing it.
Loading history...
6240
6241
6242
/*!
6243
 * jQuery UI Controlgroup 1.12.1
6244
 * http://jqueryui.com
6245
 *
6246
 * Copyright jQuery Foundation and other contributors
6247
 * Released under the MIT license.
6248
 * http://jquery.org/license
6249
 */
6250
6251
//>>label: Controlgroup
6252
//>>group: Widgets
6253
//>>description: Visually groups form control widgets
6254
//>>docs: http://api.jqueryui.com/controlgroup/
6255
//>>demos: http://jqueryui.com/controlgroup/
6256
//>>css.structure: ../../themes/base/core.css
6257
//>>css.structure: ../../themes/base/controlgroup.css
6258
//>>css.theme: ../../themes/base/theme.css
6259
6260
6261
var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
6262
6263
var widgetsControlgroup = $.widget( "ui.controlgroup", {
0 ignored issues
show
Unused Code introduced by
The variable widgetsControlgroup seems to be never used. Consider removing it.
Loading history...
6264
	version: "1.12.1",
6265
	defaultElement: "<div>",
6266
	options: {
6267
		direction: "horizontal",
6268
		disabled: null,
6269
		onlyVisible: true,
6270
		items: {
6271
			"button": "input[type=button], input[type=submit], input[type=reset], button, a",
6272
			"controlgroupLabel": ".ui-controlgroup-label",
6273
			"checkboxradio": "input[type='checkbox'], input[type='radio']",
6274
			"selectmenu": "select",
6275
			"spinner": ".ui-spinner-input"
6276
		}
6277
	},
6278
6279
	_create: function() {
6280
		this._enhance();
6281
	},
6282
6283
	// To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
6284
	_enhance: function() {
6285
		this.element.attr( "role", "toolbar" );
6286
		this.refresh();
6287
	},
6288
6289
	_destroy: function() {
6290
		this._callChildMethod( "destroy" );
6291
		this.childWidgets.removeData( "ui-controlgroup-data" );
6292
		this.element.removeAttr( "role" );
6293
		if ( this.options.items.controlgroupLabel ) {
6294
			this.element
6295
				.find( this.options.items.controlgroupLabel )
6296
				.find( ".ui-controlgroup-label-contents" )
6297
				.contents().unwrap();
6298
		}
6299
	},
6300
6301
	_initWidgets: function() {
6302
		var that = this,
6303
			childWidgets = [];
6304
6305
		// First we iterate over each of the items options
6306
		$.each( this.options.items, function( widget, selector ) {
6307
			var labels;
6308
			var options = {};
0 ignored issues
show
Unused Code introduced by
The assignment to variable options seems to be never used. Consider removing it.
Loading history...
6309
6310
			// Make sure the widget has a selector set
6311
			if ( !selector ) {
6312
				return;
6313
			}
6314
6315
			if ( widget === "controlgroupLabel" ) {
6316
				labels = that.element.find( selector );
6317
				labels.each( function() {
6318
					var element = $( this );
6319
6320
					if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
6321
						return;
6322
					}
6323
					element.contents()
6324
						.wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
6325
				} );
6326
				that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
6327
				childWidgets = childWidgets.concat( labels.get() );
6328
				return;
6329
			}
6330
6331
			// Make sure the widget actually exists
6332
			if ( !$.fn[ widget ] ) {
6333
				return;
6334
			}
6335
6336
			// We assume everything is in the middle to start because we can't determine
6337
			// first / last elements until all enhancments are done.
6338
			if ( that[ "_" + widget + "Options" ] ) {
6339
				options = that[ "_" + widget + "Options" ]( "middle" );
6340
			} else {
6341
				options = { classes: {} };
6342
			}
6343
6344
			// Find instances of this widget inside controlgroup and init them
6345
			that.element
6346
				.find( selector )
6347
				.each( function() {
6348
					var element = $( this );
6349
					var instance = element[ widget ]( "instance" );
6350
6351
					// We need to clone the default options for this type of widget to avoid
6352
					// polluting the variable options which has a wider scope than a single widget.
6353
					var instanceOptions = $.widget.extend( {}, options );
6354
6355
					// If the button is the child of a spinner ignore it
6356
					// TODO: Find a more generic solution
6357
					if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
6358
						return;
6359
					}
6360
6361
					// Create the widget if it doesn't exist
6362
					if ( !instance ) {
6363
						instance = element[ widget ]()[ widget ]( "instance" );
6364
					}
6365
					if ( instance ) {
6366
						instanceOptions.classes =
6367
							that._resolveClassesValues( instanceOptions.classes, instance );
6368
					}
6369
					element[ widget ]( instanceOptions );
6370
6371
					// Store an instance of the controlgroup to be able to reference
6372
					// from the outermost element for changing options and refresh
6373
					var widgetElement = element[ widget ]( "widget" );
6374
					$.data( widgetElement[ 0 ], "ui-controlgroup-data",
6375
						instance ? instance : element[ widget ]( "instance" ) );
6376
6377
					childWidgets.push( widgetElement[ 0 ] );
6378
				} );
6379
		} );
6380
6381
		this.childWidgets = $( $.unique( childWidgets ) );
6382
		this._addClass( this.childWidgets, "ui-controlgroup-item" );
6383
	},
6384
6385
	_callChildMethod: function( method ) {
6386
		this.childWidgets.each( function() {
6387
			var element = $( this ),
6388
				data = element.data( "ui-controlgroup-data" );
6389
			if ( data && data[ method ] ) {
6390
				data[ method ]();
6391
			}
6392
		} );
6393
	},
6394
6395
	_updateCornerClass: function( element, position ) {
6396
		var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
6397
		var add = this._buildSimpleOptions( position, "label" ).classes.label;
6398
6399
		this._removeClass( element, null, remove );
6400
		this._addClass( element, null, add );
6401
	},
6402
6403
	_buildSimpleOptions: function( position, key ) {
6404
		var direction = this.options.direction === "vertical";
6405
		var result = {
6406
			classes: {}
6407
		};
6408
		result.classes[ key ] = {
6409
			"middle": "",
6410
			"first": "ui-corner-" + ( direction ? "top" : "left" ),
6411
			"last": "ui-corner-" + ( direction ? "bottom" : "right" ),
6412
			"only": "ui-corner-all"
6413
		}[ position ];
6414
6415
		return result;
6416
	},
6417
6418
	_spinnerOptions: function( position ) {
6419
		var options = this._buildSimpleOptions( position, "ui-spinner" );
6420
6421
		options.classes[ "ui-spinner-up" ] = "";
6422
		options.classes[ "ui-spinner-down" ] = "";
6423
6424
		return options;
6425
	},
6426
6427
	_buttonOptions: function( position ) {
6428
		return this._buildSimpleOptions( position, "ui-button" );
6429
	},
6430
6431
	_checkboxradioOptions: function( position ) {
6432
		return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
6433
	},
6434
6435
	_selectmenuOptions: function( position ) {
6436
		var direction = this.options.direction === "vertical";
6437
		return {
6438
			width: direction ? "auto" : false,
6439
			classes: {
6440
				middle: {
6441
					"ui-selectmenu-button-open": "",
6442
					"ui-selectmenu-button-closed": ""
6443
				},
6444
				first: {
6445
					"ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
6446
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
6447
				},
6448
				last: {
6449
					"ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
6450
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
6451
				},
6452
				only: {
6453
					"ui-selectmenu-button-open": "ui-corner-top",
6454
					"ui-selectmenu-button-closed": "ui-corner-all"
6455
				}
6456
6457
			}[ position ]
6458
		};
6459
	},
6460
6461
	_resolveClassesValues: function( classes, instance ) {
6462
		var result = {};
6463
		$.each( classes, function( key ) {
6464
			var current = instance.options.classes[ key ] || "";
6465
			current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
6466
			result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
6467
		} );
6468
		return result;
6469
	},
6470
6471
	_setOption: function( key, value ) {
6472
		if ( key === "direction" ) {
6473
			this._removeClass( "ui-controlgroup-" + this.options.direction );
6474
		}
6475
6476
		this._super( key, value );
6477
		if ( key === "disabled" ) {
6478
			this._callChildMethod( value ? "disable" : "enable" );
6479
			return;
6480
		}
6481
6482
		this.refresh();
6483
	},
6484
6485
	refresh: function() {
6486
		var children,
6487
			that = this;
6488
6489
		this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
6490
6491
		if ( this.options.direction === "horizontal" ) {
6492
			this._addClass( null, "ui-helper-clearfix" );
6493
		}
6494
		this._initWidgets();
6495
6496
		children = this.childWidgets;
6497
6498
		// We filter here because we need to track all childWidgets not just the visible ones
6499
		if ( this.options.onlyVisible ) {
6500
			children = children.filter( ":visible" );
6501
		}
6502
6503
		if ( children.length ) {
6504
6505
			// We do this last because we need to make sure all enhancment is done
6506
			// before determining first and last
6507
			$.each( [ "first", "last" ], function( index, value ) {
6508
				var instance = children[ value ]().data( "ui-controlgroup-data" );
6509
6510
				if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
6511
					var options = that[ "_" + instance.widgetName + "Options" ](
6512
						children.length === 1 ? "only" : value
6513
					);
6514
					options.classes = that._resolveClassesValues( options.classes, instance );
6515
					instance.element[ instance.widgetName ]( options );
6516
				} else {
6517
					that._updateCornerClass( children[ value ](), value );
6518
				}
6519
			} );
6520
6521
			// Finally call the refresh method on each of the child widgets.
6522
			this._callChildMethod( "refresh" );
6523
		}
6524
	}
6525
} );
6526
6527
/*!
6528
 * jQuery UI Checkboxradio 1.12.1
6529
 * http://jqueryui.com
6530
 *
6531
 * Copyright jQuery Foundation and other contributors
6532
 * Released under the MIT license.
6533
 * http://jquery.org/license
6534
 */
6535
6536
//>>label: Checkboxradio
6537
//>>group: Widgets
6538
//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
6539
//>>docs: http://api.jqueryui.com/checkboxradio/
6540
//>>demos: http://jqueryui.com/checkboxradio/
6541
//>>css.structure: ../../themes/base/core.css
6542
//>>css.structure: ../../themes/base/button.css
6543
//>>css.structure: ../../themes/base/checkboxradio.css
6544
//>>css.theme: ../../themes/base/theme.css
6545
6546
6547
6548
$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
6549
	version: "1.12.1",
6550
	options: {
6551
		disabled: null,
6552
		label: null,
6553
		icon: true,
6554
		classes: {
6555
			"ui-checkboxradio-label": "ui-corner-all",
6556
			"ui-checkboxradio-icon": "ui-corner-all"
6557
		}
6558
	},
6559
6560
	_getCreateOptions: function() {
6561
		var disabled, labels;
6562
		var that = this;
6563
		var options = this._super() || {};
6564
6565
		// We read the type here, because it makes more sense to throw a element type error first,
6566
		// rather then the error for lack of a label. Often if its the wrong type, it
6567
		// won't have a label (e.g. calling on a div, btn, etc)
6568
		this._readType();
6569
6570
		labels = this.element.labels();
6571
6572
		// If there are multiple labels, use the last one
6573
		this.label = $( labels[ labels.length - 1 ] );
6574
		if ( !this.label.length ) {
6575
			$.error( "No label found for checkboxradio widget" );
6576
		}
6577
6578
		this.originalLabel = "";
6579
6580
		// We need to get the label text but this may also need to make sure it does not contain the
6581
		// input itself.
6582
		this.label.contents().not( this.element[ 0 ] ).each( function() {
6583
6584
			// The label contents could be text, html, or a mix. We concat each element to get a
6585
			// string representation of the label, without the input as part of it.
6586
			that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
6587
		} );
6588
6589
		// Set the label option if we found label text
6590
		if ( this.originalLabel ) {
6591
			options.label = this.originalLabel;
6592
		}
6593
6594
		disabled = this.element[ 0 ].disabled;
6595
		if ( disabled != null ) {
0 ignored issues
show
Best Practice introduced by
Comparing disabled to null using the != operator is not safe. Consider using !== instead.
Loading history...
6596
			options.disabled = disabled;
6597
		}
6598
		return options;
6599
	},
6600
6601
	_create: function() {
6602
		var checked = this.element[ 0 ].checked;
6603
6604
		this._bindFormResetHandler();
6605
6606
		if ( this.options.disabled == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing this.options.disabled to null using the == operator is not safe. Consider using === instead.
Loading history...
6607
			this.options.disabled = this.element[ 0 ].disabled;
6608
		}
6609
6610
		this._setOption( "disabled", this.options.disabled );
6611
		this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
6612
		this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
6613
6614
		if ( this.type === "radio" ) {
6615
			this._addClass( this.label, "ui-checkboxradio-radio-label" );
6616
		}
6617
6618
		if ( this.options.label && this.options.label !== this.originalLabel ) {
6619
			this._updateLabel();
6620
		} else if ( this.originalLabel ) {
6621
			this.options.label = this.originalLabel;
6622
		}
6623
6624
		this._enhance();
6625
6626
		if ( checked ) {
6627
			this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
6628
			if ( this.icon ) {
6629
				this._addClass( this.icon, null, "ui-state-hover" );
6630
			}
6631
		}
6632
6633
		this._on( {
6634
			change: "_toggleClasses",
6635
			focus: function() {
6636
				this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
6637
			},
6638
			blur: function() {
6639
				this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
6640
			}
6641
		} );
6642
	},
6643
6644
	_readType: function() {
6645
		var nodeName = this.element[ 0 ].nodeName.toLowerCase();
6646
		this.type = this.element[ 0 ].type;
6647
		if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
6648
			$.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
6649
				" and element.type=" + this.type );
6650
		}
6651
	},
6652
6653
	// Support jQuery Mobile enhanced option
6654
	_enhance: function() {
6655
		this._updateIcon( this.element[ 0 ].checked );
6656
	},
6657
6658
	widget: function() {
6659
		return this.label;
6660
	},
6661
6662
	_getRadioGroup: function() {
6663
		var group;
6664
		var name = this.element[ 0 ].name;
6665
		var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
6666
6667
		if ( !name ) {
6668
			return $( [] );
6669
		}
6670
6671
		if ( this.form.length ) {
6672
			group = $( this.form[ 0 ].elements ).filter( nameSelector );
6673
		} else {
6674
6675
			// Not inside a form, check all inputs that also are not inside a form
6676
			group = $( nameSelector ).filter( function() {
6677
				return $( this ).form().length === 0;
6678
			} );
6679
		}
6680
6681
		return group.not( this.element );
6682
	},
6683
6684
	_toggleClasses: function() {
6685
		var checked = this.element[ 0 ].checked;
6686
		this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
6687
6688
		if ( this.options.icon && this.type === "checkbox" ) {
6689
			this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
6690
				._toggleClass( this.icon, null, "ui-icon-blank", !checked );
6691
		}
6692
6693
		if ( this.type === "radio" ) {
6694
			this._getRadioGroup()
6695
				.each( function() {
6696
					var instance = $( this ).checkboxradio( "instance" );
6697
6698
					if ( instance ) {
6699
						instance._removeClass( instance.label,
6700
							"ui-checkboxradio-checked", "ui-state-active" );
6701
					}
6702
				} );
6703
		}
6704
	},
6705
6706
	_destroy: function() {
6707
		this._unbindFormResetHandler();
6708
6709
		if ( this.icon ) {
6710
			this.icon.remove();
6711
			this.iconSpace.remove();
6712
		}
6713
	},
6714
6715
	_setOption: function( key, value ) {
6716
6717
		// We don't allow the value to be set to nothing
6718
		if ( key === "label" && !value ) {
6719
			return;
6720
		}
6721
6722
		this._super( key, value );
6723
6724
		if ( key === "disabled" ) {
6725
			this._toggleClass( this.label, null, "ui-state-disabled", value );
6726
			this.element[ 0 ].disabled = value;
6727
6728
			// Don't refresh when setting disabled
6729
			return;
6730
		}
6731
		this.refresh();
6732
	},
6733
6734
	_updateIcon: function( checked ) {
6735
		var toAdd = "ui-icon ui-icon-background ";
6736
6737
		if ( this.options.icon ) {
6738
			if ( !this.icon ) {
6739
				this.icon = $( "<span>" );
6740
				this.iconSpace = $( "<span> </span>" );
6741
				this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
6742
			}
6743
6744
			if ( this.type === "checkbox" ) {
6745
				toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
6746
				this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
6747
			} else {
6748
				toAdd += "ui-icon-blank";
6749
			}
6750
			this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
6751
			if ( !checked ) {
6752
				this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
6753
			}
6754
			this.icon.prependTo( this.label ).after( this.iconSpace );
6755
		} else if ( this.icon !== undefined ) {
6756
			this.icon.remove();
6757
			this.iconSpace.remove();
6758
			delete this.icon;
6759
		}
6760
	},
6761
6762
	_updateLabel: function() {
6763
6764
		// Remove the contents of the label ( minus the icon, icon space, and input )
6765
		var contents = this.label.contents().not( this.element[ 0 ] );
6766
		if ( this.icon ) {
6767
			contents = contents.not( this.icon[ 0 ] );
6768
		}
6769
		if ( this.iconSpace ) {
6770
			contents = contents.not( this.iconSpace[ 0 ] );
6771
		}
6772
		contents.remove();
6773
6774
		this.label.append( this.options.label );
6775
	},
6776
6777
	refresh: function() {
6778
		var checked = this.element[ 0 ].checked,
6779
			isDisabled = this.element[ 0 ].disabled;
6780
6781
		this._updateIcon( checked );
6782
		this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
6783
		if ( this.options.label !== null ) {
6784
			this._updateLabel();
6785
		}
6786
6787
		if ( isDisabled !== this.options.disabled ) {
6788
			this._setOptions( { "disabled": isDisabled } );
6789
		}
6790
	}
6791
6792
} ] );
6793
6794
var widgetsCheckboxradio = $.ui.checkboxradio;
0 ignored issues
show
Unused Code introduced by
The variable widgetsCheckboxradio seems to be never used. Consider removing it.
Loading history...
6795
6796
6797
/*!
6798
 * jQuery UI Button 1.12.1
6799
 * http://jqueryui.com
6800
 *
6801
 * Copyright jQuery Foundation and other contributors
6802
 * Released under the MIT license.
6803
 * http://jquery.org/license
6804
 */
6805
6806
//>>label: Button
6807
//>>group: Widgets
6808
//>>description: Enhances a form with themeable buttons.
6809
//>>docs: http://api.jqueryui.com/button/
6810
//>>demos: http://jqueryui.com/button/
6811
//>>css.structure: ../../themes/base/core.css
6812
//>>css.structure: ../../themes/base/button.css
6813
//>>css.theme: ../../themes/base/theme.css
6814
6815
6816
6817
$.widget( "ui.button", {
6818
	version: "1.12.1",
6819
	defaultElement: "<button>",
6820
	options: {
6821
		classes: {
6822
			"ui-button": "ui-corner-all"
6823
		},
6824
		disabled: null,
6825
		icon: null,
6826
		iconPosition: "beginning",
6827
		label: null,
6828
		showLabel: true
6829
	},
6830
6831
	_getCreateOptions: function() {
6832
		var disabled,
6833
6834
			// This is to support cases like in jQuery Mobile where the base widget does have
6835
			// an implementation of _getCreateOptions
6836
			options = this._super() || {};
6837
6838
		this.isInput = this.element.is( "input" );
6839
6840
		disabled = this.element[ 0 ].disabled;
6841
		if ( disabled != null ) {
0 ignored issues
show
Best Practice introduced by
Comparing disabled to null using the != operator is not safe. Consider using !== instead.
Loading history...
6842
			options.disabled = disabled;
6843
		}
6844
6845
		this.originalLabel = this.isInput ? this.element.val() : this.element.html();
6846
		if ( this.originalLabel ) {
6847
			options.label = this.originalLabel;
6848
		}
6849
6850
		return options;
6851
	},
6852
6853
	_create: function() {
6854
		if ( !this.option.showLabel & !this.options.icon ) {
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
6855
			this.options.showLabel = true;
6856
		}
6857
6858
		// We have to check the option again here even though we did in _getCreateOptions,
6859
		// because null may have been passed on init which would override what was set in
6860
		// _getCreateOptions
6861
		if ( this.options.disabled == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing this.options.disabled to null using the == operator is not safe. Consider using === instead.
Loading history...
6862
			this.options.disabled = this.element[ 0 ].disabled || false;
6863
		}
6864
6865
		this.hasTitle = !!this.element.attr( "title" );
6866
6867
		// Check to see if the label needs to be set or if its already correct
6868
		if ( this.options.label && this.options.label !== this.originalLabel ) {
6869
			if ( this.isInput ) {
6870
				this.element.val( this.options.label );
6871
			} else {
6872
				this.element.html( this.options.label );
6873
			}
6874
		}
6875
		this._addClass( "ui-button", "ui-widget" );
6876
		this._setOption( "disabled", this.options.disabled );
6877
		this._enhance();
6878
6879
		if ( this.element.is( "a" ) ) {
6880
			this._on( {
6881
				"keyup": function( event ) {
6882
					if ( event.keyCode === $.ui.keyCode.SPACE ) {
6883
						event.preventDefault();
6884
6885
						// Support: PhantomJS <= 1.9, IE 8 Only
6886
						// If a native click is available use it so we actually cause navigation
6887
						// otherwise just trigger a click event
6888
						if ( this.element[ 0 ].click ) {
6889
							this.element[ 0 ].click();
6890
						} else {
6891
							this.element.trigger( "click" );
6892
						}
6893
					}
6894
				}
6895
			} );
6896
		}
6897
	},
6898
6899
	_enhance: function() {
6900
		if ( !this.element.is( "button" ) ) {
6901
			this.element.attr( "role", "button" );
6902
		}
6903
6904
		if ( this.options.icon ) {
6905
			this._updateIcon( "icon", this.options.icon );
6906
			this._updateTooltip();
6907
		}
6908
	},
6909
6910
	_updateTooltip: function() {
6911
		this.title = this.element.attr( "title" );
6912
6913
		if ( !this.options.showLabel && !this.title ) {
6914
			this.element.attr( "title", this.options.label );
6915
		}
6916
	},
6917
6918
	_updateIcon: function( option, value ) {
6919
		var icon = option !== "iconPosition",
6920
			position = icon ? this.options.iconPosition : value,
6921
			displayBlock = position === "top" || position === "bottom";
6922
6923
		// Create icon
6924
		if ( !this.icon ) {
6925
			this.icon = $( "<span>" );
6926
6927
			this._addClass( this.icon, "ui-button-icon", "ui-icon" );
6928
6929
			if ( !this.options.showLabel ) {
6930
				this._addClass( "ui-button-icon-only" );
6931
			}
6932
		} else if ( icon ) {
6933
6934
			// If we are updating the icon remove the old icon class
6935
			this._removeClass( this.icon, null, this.options.icon );
6936
		}
6937
6938
		// If we are updating the icon add the new icon class
6939
		if ( icon ) {
6940
			this._addClass( this.icon, null, value );
6941
		}
6942
6943
		this._attachIcon( position );
6944
6945
		// If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
6946
		// the iconSpace if there is one.
6947
		if ( displayBlock ) {
6948
			this._addClass( this.icon, null, "ui-widget-icon-block" );
6949
			if ( this.iconSpace ) {
6950
				this.iconSpace.remove();
6951
			}
6952
		} else {
6953
6954
			// Position is beginning or end so remove the ui-widget-icon-block class and add the
6955
			// space if it does not exist
6956
			if ( !this.iconSpace ) {
6957
				this.iconSpace = $( "<span> </span>" );
6958
				this._addClass( this.iconSpace, "ui-button-icon-space" );
6959
			}
6960
			this._removeClass( this.icon, null, "ui-wiget-icon-block" );
6961
			this._attachIconSpace( position );
6962
		}
6963
	},
6964
6965
	_destroy: function() {
6966
		this.element.removeAttr( "role" );
6967
6968
		if ( this.icon ) {
6969
			this.icon.remove();
6970
		}
6971
		if ( this.iconSpace ) {
6972
			this.iconSpace.remove();
6973
		}
6974
		if ( !this.hasTitle ) {
6975
			this.element.removeAttr( "title" );
6976
		}
6977
	},
6978
6979
	_attachIconSpace: function( iconPosition ) {
6980
		this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
6981
	},
6982
6983
	_attachIcon: function( iconPosition ) {
6984
		this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
6985
	},
6986
6987
	_setOptions: function( options ) {
6988
		var newShowLabel = options.showLabel === undefined ?
6989
				this.options.showLabel :
6990
				options.showLabel,
6991
			newIcon = options.icon === undefined ? this.options.icon : options.icon;
6992
6993
		if ( !newShowLabel && !newIcon ) {
6994
			options.showLabel = true;
6995
		}
6996
		this._super( options );
6997
	},
6998
6999
	_setOption: function( key, value ) {
7000
		if ( key === "icon" ) {
7001
			if ( value ) {
7002
				this._updateIcon( key, value );
7003
			} else if ( this.icon ) {
7004
				this.icon.remove();
7005
				if ( this.iconSpace ) {
7006
					this.iconSpace.remove();
7007
				}
7008
			}
7009
		}
7010
7011
		if ( key === "iconPosition" ) {
7012
			this._updateIcon( key, value );
7013
		}
7014
7015
		// Make sure we can't end up with a button that has neither text nor icon
7016
		if ( key === "showLabel" ) {
7017
				this._toggleClass( "ui-button-icon-only", null, !value );
7018
				this._updateTooltip();
7019
		}
7020
7021
		if ( key === "label" ) {
7022
			if ( this.isInput ) {
7023
				this.element.val( value );
7024
			} else {
7025
7026
				// If there is an icon, append it, else nothing then append the value
7027
				// this avoids removal of the icon when setting label text
7028
				this.element.html( value );
7029
				if ( this.icon ) {
7030
					this._attachIcon( this.options.iconPosition );
7031
					this._attachIconSpace( this.options.iconPosition );
7032
				}
7033
			}
7034
		}
7035
7036
		this._super( key, value );
7037
7038
		if ( key === "disabled" ) {
7039
			this._toggleClass( null, "ui-state-disabled", value );
7040
			this.element[ 0 ].disabled = value;
7041
			if ( value ) {
7042
				this.element.blur();
7043
			}
7044
		}
7045
	},
7046
7047
	refresh: function() {
7048
7049
		// Make sure to only check disabled if its an element that supports this otherwise
7050
		// check for the disabled class to determine state
7051
		var isDisabled = this.element.is( "input, button" ) ?
7052
			this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
7053
7054
		if ( isDisabled !== this.options.disabled ) {
7055
			this._setOptions( { disabled: isDisabled } );
7056
		}
7057
7058
		this._updateTooltip();
7059
	}
7060
} );
7061
7062
// DEPRECATED
7063
if ( $.uiBackCompat !== false ) {
7064
7065
	// Text and Icons options
7066
	$.widget( "ui.button", $.ui.button, {
7067
		options: {
7068
			text: true,
7069
			icons: {
7070
				primary: null,
7071
				secondary: null
7072
			}
7073
		},
7074
7075 View Code Duplication
		_create: function() {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
7076
			if ( this.options.showLabel && !this.options.text ) {
7077
				this.options.showLabel = this.options.text;
7078
			}
7079
			if ( !this.options.showLabel && this.options.text ) {
7080
				this.options.text = this.options.showLabel;
7081
			}
7082
			if ( !this.options.icon && ( this.options.icons.primary ||
7083
					this.options.icons.secondary ) ) {
7084
				if ( this.options.icons.primary ) {
7085
					this.options.icon = this.options.icons.primary;
7086
				} else {
7087
					this.options.icon = this.options.icons.secondary;
7088
					this.options.iconPosition = "end";
7089
				}
7090
			} else if ( this.options.icon ) {
7091
				this.options.icons.primary = this.options.icon;
7092
			}
7093
			this._super();
7094
		},
7095
7096
		_setOption: function( key, value ) {
7097
			if ( key === "text" ) {
7098
				this._super( "showLabel", value );
7099
				return;
7100
			}
7101
			if ( key === "showLabel" ) {
7102
				this.options.text = value;
7103
			}
7104
			if ( key === "icon" ) {
7105
				this.options.icons.primary = value;
7106
			}
7107
			if ( key === "icons" ) {
7108
				if ( value.primary ) {
7109
					this._super( "icon", value.primary );
7110
					this._super( "iconPosition", "beginning" );
7111
				} else if ( value.secondary ) {
7112
					this._super( "icon", value.secondary );
7113
					this._super( "iconPosition", "end" );
7114
				}
7115
			}
7116
			this._superApply( arguments );
7117
		}
7118
	} );
7119
7120
	$.fn.button = ( function( orig ) {
7121
		return function() {
7122
			if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
7123
					( this.length && this[ 0 ].tagName === "INPUT" && (
7124
						this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
7125
					) ) ) {
7126
				return orig.apply( this, arguments );
7127
			}
7128
			if ( !$.ui.checkboxradio ) {
7129
				$.error( "Checkboxradio widget missing" );
7130
			}
7131
			if ( arguments.length === 0 ) {
7132
				return this.checkboxradio( {
7133
					"icon": false
7134
				} );
7135
			}
7136
			return this.checkboxradio.apply( this, arguments );
7137
		};
7138
	} )( $.fn.button );
7139
7140
	$.fn.buttonset = function() {
7141
		if ( !$.ui.controlgroup ) {
7142
			$.error( "Controlgroup widget missing" );
7143
		}
7144
		if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
7145
			return this.controlgroup.apply( this,
7146
				[ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
7147
		}
7148
		if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
7149
			return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
7150
		}
7151
		if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
7152
			arguments[ 0 ].items = {
7153
				button: arguments[ 0 ].items
7154
			};
7155
		}
7156
		return this.controlgroup.apply( this, arguments );
7157
	};
7158
}
7159
7160
var widgetsButton = $.ui.button;
0 ignored issues
show
Unused Code introduced by
The variable widgetsButton seems to be never used. Consider removing it.
Loading history...
7161
7162
7163
// jscs:disable maximumLineLength
7164
/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
7165
/*!
7166
 * jQuery UI Datepicker 1.12.1
7167
 * http://jqueryui.com
7168
 *
7169
 * Copyright jQuery Foundation and other contributors
7170
 * Released under the MIT license.
7171
 * http://jquery.org/license
7172
 */
7173
7174
//>>label: Datepicker
7175
//>>group: Widgets
7176
//>>description: Displays a calendar from an input or inline for selecting dates.
7177
//>>docs: http://api.jqueryui.com/datepicker/
7178
//>>demos: http://jqueryui.com/datepicker/
7179
//>>css.structure: ../../themes/base/core.css
7180
//>>css.structure: ../../themes/base/datepicker.css
7181
//>>css.theme: ../../themes/base/theme.css
7182
7183
7184
7185
$.extend( $.ui, { datepicker: { version: "1.12.1" } } );
7186
7187
var datepicker_instActive;
7188
7189
function datepicker_getZindex( elem ) {
7190
	var position, value;
7191
	while ( elem.length && elem[ 0 ] !== document ) {
7192
7193
		// Ignore z-index if position is set to a value where z-index is ignored by the browser
7194
		// This makes behavior of this function consistent across browsers
7195
		// WebKit always returns auto if the element is positioned
7196
		position = elem.css( "position" );
7197
		if ( position === "absolute" || position === "relative" || position === "fixed" ) {
7198
7199
			// IE returns 0 when zIndex is not specified
7200
			// other browsers return a string
7201
			// we ignore the case of nested elements with an explicit value of 0
7202
			// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
7203
			value = parseInt( elem.css( "zIndex" ), 10 );
7204
			if ( !isNaN( value ) && value !== 0 ) {
7205
				return value;
7206
			}
7207
		}
7208
		elem = elem.parent();
7209
	}
7210
7211
	return 0;
7212
}
7213
/* Date picker manager.
7214
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7215
   Settings for (groups of) date pickers are maintained in an instance object,
7216
   allowing multiple different settings on the same page. */
7217
7218
function Datepicker() {
7219
	this._curInst = null; // The current instance in use
7220
	this._keyEvent = false; // If the last event was a key event
7221
	this._disabledInputs = []; // List of date picker inputs that have been disabled
7222
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
7223
	this._inDialog = false; // True if showing within a "dialog", false if not
7224
	this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
7225
	this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
7226
	this._appendClass = "ui-datepicker-append"; // The name of the append marker class
7227
	this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
7228
	this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
7229
	this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
7230
	this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
7231
	this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
7232
	this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
7233
	this.regional = []; // Available regional settings, indexed by language code
7234
	this.regional[ "" ] = { // Default regional settings
7235
		closeText: "Done", // Display text for close link
7236
		prevText: "Prev", // Display text for previous month link
7237
		nextText: "Next", // Display text for next month link
7238
		currentText: "Today", // Display text for current month link
7239
		monthNames: [ "January","February","March","April","May","June",
7240
			"July","August","September","October","November","December" ], // Names of months for drop-down and formatting
7241
		monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
7242
		dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
7243
		dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
7244
		dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
7245
		weekHeader: "Wk", // Column header for week of the year
7246
		dateFormat: "mm/dd/yy", // See format options on parseDate
7247
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7248
		isRTL: false, // True if right-to-left language, false if left-to-right
7249
		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7250
		yearSuffix: "" // Additional text to append to the year in the month headers
7251
	};
7252
	this._defaults = { // Global defaults for all the date picker instances
7253
		showOn: "focus", // "focus" for popup on focus,
7254
			// "button" for trigger button, or "both" for either
7255
		showAnim: "fadeIn", // Name of jQuery animation for popup
7256
		showOptions: {}, // Options for enhanced animations
7257
		defaultDate: null, // Used when field is blank: actual date,
7258
			// +/-number for offset from today, null for today
7259
		appendText: "", // Display text following the input box, e.g. showing the format
7260
		buttonText: "...", // Text for trigger button
7261
		buttonImage: "", // URL for trigger button image
7262
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7263
		hideIfNoPrevNext: false, // True to hide next/previous month links
7264
			// if not applicable, false to just disable them
7265
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7266
		gotoCurrent: false, // True if today link goes back to current selection instead
7267
		changeMonth: false, // True if month can be selected directly, false if only prev/next
7268
		changeYear: false, // True if year can be selected directly, false if only prev/next
7269
		yearRange: "c-10:c+10", // Range of years to display in drop-down,
7270
			// either relative to today's year (-nn:+nn), relative to currently displayed year
7271
			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
7272
		showOtherMonths: false, // True to show dates in other months, false to leave blank
7273
		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
7274
		showWeek: false, // True to show week of the year, false to not show it
7275
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7276
			// takes a Date and returns the number of the week for it
7277
		shortYearCutoff: "+10", // Short year values < this are in the current century,
7278
			// > this are in the previous century,
7279
			// string value starting with "+" for current year + value
7280
		minDate: null, // The earliest selectable date, or null for no limit
7281
		maxDate: null, // The latest selectable date, or null for no limit
7282
		duration: "fast", // Duration of display/closure
7283
		beforeShowDay: null, // Function that takes a date and returns an array with
7284
			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
7285
			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
7286
		beforeShow: null, // Function that takes an input field and
7287
			// returns a set of custom settings for the date picker
7288
		onSelect: null, // Define a callback function when a date is selected
7289
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
7290
		onClose: null, // Define a callback function when the datepicker is closed
7291
		numberOfMonths: 1, // Number of months to show at a time
7292
		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
7293
		stepMonths: 1, // Number of months to step back/forward
7294
		stepBigMonths: 12, // Number of months to step back/forward for the big links
7295
		altField: "", // Selector for an alternate field to store selected dates into
7296
		altFormat: "", // The date format to use for the alternate field
7297
		constrainInput: true, // The input is constrained by the current date format
7298
		showButtonPanel: false, // True to show button panel, false to not show it
7299
		autoSize: false, // True to size the input for the date format, false to leave as is
7300
		disabled: false // The initial disabled state
7301
	};
7302
	$.extend( this._defaults, this.regional[ "" ] );
7303
	this.regional.en = $.extend( true, {}, this.regional[ "" ] );
7304
	this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
7305
	this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
7306
}
7307
7308
$.extend( Datepicker.prototype, {
7309
	/* Class name added to elements to indicate already configured with a date picker. */
7310
	markerClassName: "hasDatepicker",
7311
7312
	//Keep track of the maximum number of rows displayed (see #7043)
7313
	maxRows: 4,
7314
7315
	// TODO rename to "widget" when switching to widget factory
7316
	_widgetDatepicker: function() {
7317
		return this.dpDiv;
7318
	},
7319
7320
	/* Override the default settings for all instances of the date picker.
7321
	 * @param  settings  object - the new settings to use as defaults (anonymous object)
7322
	 * @return the manager object
7323
	 */
7324
	setDefaults: function( settings ) {
7325
		datepicker_extendRemove( this._defaults, settings || {} );
7326
		return this;
7327
	},
7328
7329
	/* Attach the date picker to a jQuery selection.
7330
	 * @param  target	element - the target input field or division or span
7331
	 * @param  settings  object - the new settings to use for this date picker instance (anonymous)
7332
	 */
7333
	_attachDatepicker: function( target, settings ) {
7334
		var nodeName, inline, inst;
7335
		nodeName = target.nodeName.toLowerCase();
7336
		inline = ( nodeName === "div" || nodeName === "span" );
7337
		if ( !target.id ) {
7338
			this.uuid += 1;
7339
			target.id = "dp" + this.uuid;
7340
		}
7341
		inst = this._newInst( $( target ), inline );
7342
		inst.settings = $.extend( {}, settings || {} );
7343
		if ( nodeName === "input" ) {
7344
			this._connectDatepicker( target, inst );
7345
		} else if ( inline ) {
7346
			this._inlineDatepicker( target, inst );
7347
		}
7348
	},
7349
7350
	/* Create a new instance object. */
7351
	_newInst: function( target, inline ) {
7352
		var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
7353
		return { id: id, input: target, // associated target
7354
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
7355
			drawMonth: 0, drawYear: 0, // month being drawn
7356
			inline: inline, // is datepicker inline or not
7357
			dpDiv: ( !inline ? this.dpDiv : // presentation div
7358
			datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
7359
	},
7360
7361
	/* Attach the date picker to an input field. */
7362
	_connectDatepicker: function( target, inst ) {
7363
		var input = $( target );
7364
		inst.append = $( [] );
7365
		inst.trigger = $( [] );
7366
		if ( input.hasClass( this.markerClassName ) ) {
7367
			return;
7368
		}
7369
		this._attachments( input, inst );
7370
		input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
7371
			on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
7372
		this._autoSize( inst );
7373
		$.data( target, "datepicker", inst );
7374
7375
		//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
7376
		if ( inst.settings.disabled ) {
7377
			this._disableDatepicker( target );
7378
		}
7379
	},
7380
7381
	/* Make attachments based on settings. */
7382
	_attachments: function( input, inst ) {
7383
		var showOn, buttonText, buttonImage,
7384
			appendText = this._get( inst, "appendText" ),
7385
			isRTL = this._get( inst, "isRTL" );
7386
7387
		if ( inst.append ) {
7388
			inst.append.remove();
7389
		}
7390
		if ( appendText ) {
7391
			inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
7392
			input[ isRTL ? "before" : "after" ]( inst.append );
7393
		}
7394
7395
		input.off( "focus", this._showDatepicker );
7396
7397
		if ( inst.trigger ) {
7398
			inst.trigger.remove();
7399
		}
7400
7401
		showOn = this._get( inst, "showOn" );
7402
		if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
7403
			input.on( "focus", this._showDatepicker );
7404
		}
7405
		if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
7406
			buttonText = this._get( inst, "buttonText" );
7407
			buttonImage = this._get( inst, "buttonImage" );
7408
			inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
7409
				$( "<img/>" ).addClass( this._triggerClass ).
7410
					attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
7411
				$( "<button type='button'></button>" ).addClass( this._triggerClass ).
7412
					html( !buttonImage ? buttonText : $( "<img/>" ).attr(
7413
					{ src:buttonImage, alt:buttonText, title:buttonText } ) ) );
7414
			input[ isRTL ? "before" : "after" ]( inst.trigger );
7415
			inst.trigger.on( "click", function() {
7416
				if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
7417
					$.datepicker._hideDatepicker();
7418
				} else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
7419
					$.datepicker._hideDatepicker();
7420
					$.datepicker._showDatepicker( input[ 0 ] );
7421
				} else {
7422
					$.datepicker._showDatepicker( input[ 0 ] );
7423
				}
7424
				return false;
7425
			} );
7426
		}
7427
	},
7428
7429
	/* Apply the maximum length for the date format. */
7430
	_autoSize: function( inst ) {
7431
		if ( this._get( inst, "autoSize" ) && !inst.inline ) {
7432
			var findMax, max, maxI, i,
7433
				date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
7434
				dateFormat = this._get( inst, "dateFormat" );
7435
7436
			if ( dateFormat.match( /[DM]/ ) ) {
7437
				findMax = function( names ) {
7438
					max = 0;
7439
					maxI = 0;
7440
					for ( i = 0; i < names.length; i++ ) {
0 ignored issues
show
Bug introduced by
The variable i is changed as part of the for loop for example by i++ on line 7440. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
7441
						if ( names[ i ].length > max ) {
0 ignored issues
show
Bug introduced by
The variable max is changed as part of the for loop for example by names.i.length on line 7442. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
7442
							max = names[ i ].length;
7443
							maxI = i;
7444
						}
7445
					}
7446
					return maxI;
7447
				};
7448
				date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
7449
					"monthNames" : "monthNamesShort" ) ) ) );
7450
				date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
7451
					"dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
7452
			}
7453
			inst.input.attr( "size", this._formatDate( inst, date ).length );
7454
		}
7455
	},
7456
7457
	/* Attach an inline date picker to a div. */
7458
	_inlineDatepicker: function( target, inst ) {
7459
		var divSpan = $( target );
7460
		if ( divSpan.hasClass( this.markerClassName ) ) {
7461
			return;
7462
		}
7463
		divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
7464
		$.data( target, "datepicker", inst );
7465
		this._setDate( inst, this._getDefaultDate( inst ), true );
7466
		this._updateDatepicker( inst );
7467
		this._updateAlternate( inst );
7468
7469
		//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
7470
		if ( inst.settings.disabled ) {
7471
			this._disableDatepicker( target );
7472
		}
7473
7474
		// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
7475
		// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
7476
		inst.dpDiv.css( "display", "block" );
7477
	},
7478
7479
	/* Pop-up the date picker in a "dialog" box.
7480
	 * @param  input element - ignored
7481
	 * @param  date	string or Date - the initial date to display
7482
	 * @param  onSelect  function - the function to call when a date is selected
7483
	 * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
7484
	 * @param  pos int[2] - coordinates for the dialog's position within the screen or
7485
	 *					event - with x/y coordinates or
7486
	 *					leave empty for default (screen centre)
7487
	 * @return the manager object
7488
	 */
7489
	_dialogDatepicker: function( input, date, onSelect, settings, pos ) {
7490
		var id, browserWidth, browserHeight, scrollX, scrollY,
7491
			inst = this._dialogInst; // internal instance
7492
7493
		if ( !inst ) {
7494
			this.uuid += 1;
7495
			id = "dp" + this.uuid;
7496
			this._dialogInput = $( "<input type='text' id='" + id +
7497
				"' style='position: absolute; top: -100px; width: 0px;'/>" );
7498
			this._dialogInput.on( "keydown", this._doKeyDown );
7499
			$( "body" ).append( this._dialogInput );
7500
			inst = this._dialogInst = this._newInst( this._dialogInput, false );
7501
			inst.settings = {};
7502
			$.data( this._dialogInput[ 0 ], "datepicker", inst );
7503
		}
7504
		datepicker_extendRemove( inst.settings, settings || {} );
7505
		date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
7506
		this._dialogInput.val( date );
7507
7508
		this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
7509
		if ( !this._pos ) {
7510
			browserWidth = document.documentElement.clientWidth;
7511
			browserHeight = document.documentElement.clientHeight;
7512
			scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
7513
			scrollY = document.documentElement.scrollTop || document.body.scrollTop;
7514
			this._pos = // should use actual width/height below
7515
				[ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
7516
		}
7517
7518
		// Move input on screen for focus, but hidden behind dialog
7519
		this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
7520
		inst.settings.onSelect = onSelect;
7521
		this._inDialog = true;
7522
		this.dpDiv.addClass( this._dialogClass );
7523
		this._showDatepicker( this._dialogInput[ 0 ] );
7524
		if ( $.blockUI ) {
7525
			$.blockUI( this.dpDiv );
7526
		}
7527
		$.data( this._dialogInput[ 0 ], "datepicker", inst );
7528
		return this;
7529
	},
7530
7531
	/* Detach a datepicker from its control.
7532
	 * @param  target	element - the target input field or division or span
7533
	 */
7534
	_destroyDatepicker: function( target ) {
7535
		var nodeName,
7536
			$target = $( target ),
7537
			inst = $.data( target, "datepicker" );
7538
7539
		if ( !$target.hasClass( this.markerClassName ) ) {
7540
			return;
7541
		}
7542
7543
		nodeName = target.nodeName.toLowerCase();
7544
		$.removeData( target, "datepicker" );
7545
		if ( nodeName === "input" ) {
7546
			inst.append.remove();
7547
			inst.trigger.remove();
7548
			$target.removeClass( this.markerClassName ).
7549
				off( "focus", this._showDatepicker ).
7550
				off( "keydown", this._doKeyDown ).
7551
				off( "keypress", this._doKeyPress ).
7552
				off( "keyup", this._doKeyUp );
7553
		} else if ( nodeName === "div" || nodeName === "span" ) {
7554
			$target.removeClass( this.markerClassName ).empty();
7555
		}
7556
7557
		if ( datepicker_instActive === inst ) {
7558
			datepicker_instActive = null;
7559
		}
7560
	},
7561
7562
	/* Enable the date picker to a jQuery selection.
7563
	 * @param  target	element - the target input field or division or span
7564
	 */
7565
	_enableDatepicker: function( target ) {
7566
		var nodeName, inline,
7567
			$target = $( target ),
7568
			inst = $.data( target, "datepicker" );
7569
7570
		if ( !$target.hasClass( this.markerClassName ) ) {
7571
			return;
7572
		}
7573
7574
		nodeName = target.nodeName.toLowerCase();
7575
		if ( nodeName === "input" ) {
7576
			target.disabled = false;
7577
			inst.trigger.filter( "button" ).
7578
				each( function() { this.disabled = false; } ).end().
7579
				filter( "img" ).css( { opacity: "1.0", cursor: "" } );
7580
		} else if ( nodeName === "div" || nodeName === "span" ) {
7581
			inline = $target.children( "." + this._inlineClass );
7582
			inline.children().removeClass( "ui-state-disabled" );
7583
			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
7584
				prop( "disabled", false );
7585
		}
7586
		this._disabledInputs = $.map( this._disabledInputs,
7587
			function( value ) { return ( value === target ? null : value ); } ); // delete entry
7588
	},
7589
7590
	/* Disable the date picker to a jQuery selection.
7591
	 * @param  target	element - the target input field or division or span
7592
	 */
7593
	_disableDatepicker: function( target ) {
7594
		var nodeName, inline,
7595
			$target = $( target ),
7596
			inst = $.data( target, "datepicker" );
7597
7598
		if ( !$target.hasClass( this.markerClassName ) ) {
7599
			return;
7600
		}
7601
7602
		nodeName = target.nodeName.toLowerCase();
7603
		if ( nodeName === "input" ) {
7604
			target.disabled = true;
7605
			inst.trigger.filter( "button" ).
7606
				each( function() { this.disabled = true; } ).end().
7607
				filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
7608
		} else if ( nodeName === "div" || nodeName === "span" ) {
7609
			inline = $target.children( "." + this._inlineClass );
7610
			inline.children().addClass( "ui-state-disabled" );
7611
			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
7612
				prop( "disabled", true );
7613
		}
7614
		this._disabledInputs = $.map( this._disabledInputs,
7615
			function( value ) { return ( value === target ? null : value ); } ); // delete entry
7616
		this._disabledInputs[ this._disabledInputs.length ] = target;
7617
	},
7618
7619
	/* Is the first field in a jQuery collection disabled as a datepicker?
7620
	 * @param  target	element - the target input field or division or span
7621
	 * @return boolean - true if disabled, false if enabled
7622
	 */
7623
	_isDisabledDatepicker: function( target ) {
7624
		if ( !target ) {
7625
			return false;
7626
		}
7627
		for ( var i = 0; i < this._disabledInputs.length; i++ ) {
7628
			if ( this._disabledInputs[ i ] === target ) {
7629
				return true;
7630
			}
7631
		}
7632
		return false;
7633
	},
7634
7635
	/* Retrieve the instance data for the target control.
7636
	 * @param  target  element - the target input field or division or span
7637
	 * @return  object - the associated instance data
7638
	 * @throws  error if a jQuery problem getting data
7639
	 */
7640
	_getInst: function( target ) {
7641
		try {
7642
			return $.data( target, "datepicker" );
7643
		}
7644
		catch ( err ) {
7645
			throw "Missing instance data for this datepicker";
7646
		}
7647
	},
7648
7649
	/* Update or retrieve the settings for a date picker attached to an input field or division.
7650
	 * @param  target  element - the target input field or division or span
7651
	 * @param  name	object - the new settings to update or
7652
	 *				string - the name of the setting to change or retrieve,
7653
	 *				when retrieving also "all" for all instance settings or
7654
	 *				"defaults" for all global defaults
7655
	 * @param  value   any - the new value for the setting
7656
	 *				(omit if above is an object or to retrieve a value)
7657
	 */
7658
	_optionDatepicker: function( target, name, value ) {
7659
		var settings, date, minDate, maxDate,
7660
			inst = this._getInst( target );
7661
7662
		if ( arguments.length === 2 && typeof name === "string" ) {
7663
			return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
7664
				( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
7665
				this._get( inst, name ) ) : null ) );
7666
		}
7667
7668
		settings = name || {};
7669
		if ( typeof name === "string" ) {
7670
			settings = {};
7671
			settings[ name ] = value;
7672
		}
7673
7674
		if ( inst ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if inst 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...
7675
			if ( this._curInst === inst ) {
7676
				this._hideDatepicker();
7677
			}
7678
7679
			date = this._getDateDatepicker( target, true );
7680
			minDate = this._getMinMaxDate( inst, "min" );
7681
			maxDate = this._getMinMaxDate( inst, "max" );
7682
			datepicker_extendRemove( inst.settings, settings );
7683
7684
			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
7685
			if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
7686
				inst.settings.minDate = this._formatDate( inst, minDate );
7687
			}
7688
			if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
7689
				inst.settings.maxDate = this._formatDate( inst, maxDate );
7690
			}
7691
			if ( "disabled" in settings ) {
7692
				if ( settings.disabled ) {
7693
					this._disableDatepicker( target );
7694
				} else {
7695
					this._enableDatepicker( target );
7696
				}
7697
			}
7698
			this._attachments( $( target ), inst );
7699
			this._autoSize( inst );
7700
			this._setDate( inst, date );
7701
			this._updateAlternate( inst );
7702
			this._updateDatepicker( inst );
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
7703
		}
7704
	},
7705
7706
	// Change method deprecated
7707
	_changeDatepicker: function( target, name, value ) {
7708
		this._optionDatepicker( target, name, value );
7709
	},
7710
7711
	/* Redraw the date picker attached to an input field or division.
7712
	 * @param  target  element - the target input field or division or span
7713
	 */
7714
	_refreshDatepicker: function( target ) {
7715
		var inst = this._getInst( target );
7716
		if ( inst ) {
7717
			this._updateDatepicker( inst );
7718
		}
7719
	},
7720
7721
	/* Set the dates for a jQuery selection.
7722
	 * @param  target element - the target input field or division or span
7723
	 * @param  date	Date - the new date
7724
	 */
7725
	_setDateDatepicker: function( target, date ) {
7726
		var inst = this._getInst( target );
7727
		if ( inst ) {
7728
			this._setDate( inst, date );
7729
			this._updateDatepicker( inst );
7730
			this._updateAlternate( inst );
7731
		}
7732
	},
7733
7734
	/* Get the date(s) for the first entry in a jQuery selection.
7735
	 * @param  target element - the target input field or division or span
7736
	 * @param  noDefault boolean - true if no default date is to be used
7737
	 * @return Date - the current date
7738
	 */
7739
	_getDateDatepicker: function( target, noDefault ) {
7740
		var inst = this._getInst( target );
7741
		if ( inst && !inst.inline ) {
7742
			this._setDateFromField( inst, noDefault );
7743
		}
7744
		return ( inst ? this._getDate( inst ) : null );
7745
	},
7746
7747
	/* Handle keystrokes. */
7748
	_doKeyDown: function( event ) {
7749
		var onSelect, dateStr, sel,
7750
			inst = $.datepicker._getInst( event.target ),
7751
			handled = true,
7752
			isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
7753
7754
		inst._keyEvent = true;
7755
		if ( $.datepicker._datepickerShowing ) {
7756
			switch ( event.keyCode ) {
7757
				case 9: $.datepicker._hideDatepicker();
7758
						handled = false;
7759
						break; // hide on tab out
7760
				case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
7761
									$.datepicker._currentClass + ")", inst.dpDiv );
7762
						if ( sel[ 0 ] ) {
7763
							$.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
7764
						}
7765
7766
						onSelect = $.datepicker._get( inst, "onSelect" );
7767
						if ( onSelect ) {
7768
							dateStr = $.datepicker._formatDate( inst );
7769
7770
							// Trigger custom callback
7771
							onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
7772
						} else {
7773
							$.datepicker._hideDatepicker();
7774
						}
7775
7776
						return false; // don't submit the form
7777
				case 27: $.datepicker._hideDatepicker();
7778
						break; // hide on escape
7779
				case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7780
							-$.datepicker._get( inst, "stepBigMonths" ) :
7781
							-$.datepicker._get( inst, "stepMonths" ) ), "M" );
7782
						break; // previous month/year on page up/+ ctrl
7783
				case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7784
							+$.datepicker._get( inst, "stepBigMonths" ) :
7785
							+$.datepicker._get( inst, "stepMonths" ) ), "M" );
7786
						break; // next month/year on page down/+ ctrl
7787
				case 35: if ( event.ctrlKey || event.metaKey ) {
7788
							$.datepicker._clearDate( event.target );
7789
						}
7790
						handled = event.ctrlKey || event.metaKey;
7791
						break; // clear on ctrl or command +end
7792
				case 36: if ( event.ctrlKey || event.metaKey ) {
7793
							$.datepicker._gotoToday( event.target );
7794
						}
7795
						handled = event.ctrlKey || event.metaKey;
7796
						break; // current on ctrl or command +home
7797
				case 37: if ( event.ctrlKey || event.metaKey ) {
7798
							$.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
7799
						}
7800
						handled = event.ctrlKey || event.metaKey;
7801
7802
						// -1 day on ctrl or command +left
7803
						if ( event.originalEvent.altKey ) {
7804
							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7805
								-$.datepicker._get( inst, "stepBigMonths" ) :
7806
								-$.datepicker._get( inst, "stepMonths" ) ), "M" );
7807
						}
7808
7809
						// next month/year on alt +left on Mac
7810
						break;
7811
				case 38: if ( event.ctrlKey || event.metaKey ) {
7812
							$.datepicker._adjustDate( event.target, -7, "D" );
7813
						}
7814
						handled = event.ctrlKey || event.metaKey;
7815
						break; // -1 week on ctrl or command +up
7816
				case 39: if ( event.ctrlKey || event.metaKey ) {
7817
							$.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
7818
						}
7819
						handled = event.ctrlKey || event.metaKey;
7820
7821
						// +1 day on ctrl or command +right
7822
						if ( event.originalEvent.altKey ) {
7823
							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7824
								+$.datepicker._get( inst, "stepBigMonths" ) :
7825
								+$.datepicker._get( inst, "stepMonths" ) ), "M" );
7826
						}
7827
7828
						// next month/year on alt +right
7829
						break;
7830
				case 40: if ( event.ctrlKey || event.metaKey ) {
7831
							$.datepicker._adjustDate( event.target, +7, "D" );
7832
						}
7833
						handled = event.ctrlKey || event.metaKey;
7834
						break; // +1 week on ctrl or command +down
7835
				default: handled = false;
7836
			}
7837
		} else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
7838
			$.datepicker._showDatepicker( this );
7839
		} else {
7840
			handled = false;
7841
		}
7842
7843
		if ( handled ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if handled 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...
7844
			event.preventDefault();
7845
			event.stopPropagation();
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
7846
		}
7847
	},
7848
7849
	/* Filter entered characters - based on date format. */
7850
	_doKeyPress: function( event ) {
7851
		var chars, chr,
7852
			inst = $.datepicker._getInst( event.target );
7853
7854
		if ( $.datepicker._get( inst, "constrainInput" ) ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $.datepicker._get(inst, "constrainInput") 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...
7855
			chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
7856
			chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
0 ignored issues
show
Best Practice introduced by
Comparing event.charCode to null using the == operator is not safe. Consider using === instead.
Loading history...
7857
			return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
7858
		}
7859
	},
7860
7861
	/* Synchronise manual entry and field/alternate field. */
7862
	_doKeyUp: function( event ) {
7863
		var date,
7864
			inst = $.datepicker._getInst( event.target );
7865
7866
		if ( inst.input.val() !== inst.lastVal ) {
7867
			try {
7868
				date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
7869
					( inst.input ? inst.input.val() : null ),
7870
					$.datepicker._getFormatConfig( inst ) );
7871
7872
				if ( date ) { // only if valid
7873
					$.datepicker._setDateFromField( inst );
7874
					$.datepicker._updateAlternate( inst );
7875
					$.datepicker._updateDatepicker( inst );
7876
				}
7877
			}
7878
			catch ( err ) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
7879
			}
7880
		}
7881
		return true;
7882
	},
7883
7884
	/* Pop-up the date picker for a given input field.
7885
	 * If false returned from beforeShow event handler do not show.
7886
	 * @param  input  element - the input field attached to the date picker or
7887
	 *					event - if triggered by focus
7888
	 */
7889
	_showDatepicker: function( input ) {
7890
		input = input.target || input;
7891
		if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
7892
			input = $( "input", input.parentNode )[ 0 ];
7893
		}
7894
7895
		if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
7896
			return;
7897
		}
7898
7899
		var inst, beforeShow, beforeShowSettings, isFixed,
7900
			offset, showAnim, duration;
7901
7902
		inst = $.datepicker._getInst( input );
7903
		if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
7904
			$.datepicker._curInst.dpDiv.stop( true, true );
7905
			if ( inst && $.datepicker._datepickerShowing ) {
7906
				$.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
7907
			}
7908
		}
7909
7910
		beforeShow = $.datepicker._get( inst, "beforeShow" );
7911
		beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
7912
		if ( beforeShowSettings === false ) {
7913
			return;
7914
		}
7915
		datepicker_extendRemove( inst.settings, beforeShowSettings );
7916
7917
		inst.lastVal = null;
7918
		$.datepicker._lastInput = input;
7919
		$.datepicker._setDateFromField( inst );
7920
7921
		if ( $.datepicker._inDialog ) { // hide cursor
7922
			input.value = "";
7923
		}
7924
		if ( !$.datepicker._pos ) { // position below input
7925
			$.datepicker._pos = $.datepicker._findPos( input );
7926
			$.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
7927
		}
7928
7929
		isFixed = false;
7930
		$( input ).parents().each( function() {
7931
			isFixed |= $( this ).css( "position" ) === "fixed";
7932
			return !isFixed;
7933
		} );
7934
7935
		offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
7936
		$.datepicker._pos = null;
7937
7938
		//to avoid flashes on Firefox
7939
		inst.dpDiv.empty();
7940
7941
		// determine sizing offscreen
7942
		inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
7943
		$.datepicker._updateDatepicker( inst );
7944
7945
		// fix width for dynamic number of date pickers
7946
		// and adjust position before showing
7947
		offset = $.datepicker._checkOffset( inst, offset, isFixed );
7948
		inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
7949
			"static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
7950
			left: offset.left + "px", top: offset.top + "px" } );
7951
7952
		if ( !inst.inline ) {
7953
			showAnim = $.datepicker._get( inst, "showAnim" );
7954
			duration = $.datepicker._get( inst, "duration" );
7955
			inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
7956
			$.datepicker._datepickerShowing = true;
7957
7958
			if ( $.effects && $.effects.effect[ showAnim ] ) {
7959
				inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
7960
			} else {
7961
				inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
7962
			}
7963
7964
			if ( $.datepicker._shouldFocusInput( inst ) ) {
7965
				inst.input.trigger( "focus" );
7966
			}
7967
7968
			$.datepicker._curInst = inst;
7969
		}
7970
	},
7971
7972
	/* Generate the date picker content. */
7973
	_updateDatepicker: function( inst ) {
7974
		this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
7975
		datepicker_instActive = inst; // for delegate hover events
7976
		inst.dpDiv.empty().append( this._generateHTML( inst ) );
7977
		this._attachHandlers( inst );
7978
7979
		var origyearshtml,
7980
			numMonths = this._getNumberOfMonths( inst ),
7981
			cols = numMonths[ 1 ],
7982
			width = 17,
7983
			activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
7984
7985
		if ( activeCell.length > 0 ) {
7986
			datepicker_handleMouseover.apply( activeCell.get( 0 ) );
7987
		}
7988
7989
		inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
7990
		if ( cols > 1 ) {
7991
			inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
7992
		}
7993
		inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
7994
			"Class" ]( "ui-datepicker-multi" );
7995
		inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
7996
			"Class" ]( "ui-datepicker-rtl" );
7997
7998
		if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
7999
			inst.input.trigger( "focus" );
8000
		}
8001
8002
		// Deffered render of the years select (to avoid flashes on Firefox)
8003
		if ( inst.yearshtml ) {
8004
			origyearshtml = inst.yearshtml;
8005
			setTimeout( function() {
8006
8007
				//assure that inst.yearshtml didn't change.
8008
				if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
8009
					inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
8010
				}
8011
				origyearshtml = inst.yearshtml = null;
8012
			}, 0 );
8013
		}
8014
	},
8015
8016
	// #6694 - don't focus the input if it's already focused
8017
	// this breaks the change event in IE
8018
	// Support: IE and jQuery <1.9
8019
	_shouldFocusInput: function( inst ) {
8020
		return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
8021
	},
8022
8023
	/* Check positioning to remain on screen. */
8024
	_checkOffset: function( inst, offset, isFixed ) {
8025
		var dpWidth = inst.dpDiv.outerWidth(),
8026
			dpHeight = inst.dpDiv.outerHeight(),
8027
			inputWidth = inst.input ? inst.input.outerWidth() : 0,
8028
			inputHeight = inst.input ? inst.input.outerHeight() : 0,
8029
			viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
8030
			viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
8031
8032
		offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
8033
		offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
8034
		offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
8035
8036
		// Now check if datepicker is showing outside window viewport - move to a better place if so.
8037
		offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
8038
			Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
8039
		offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
8040
			Math.abs( dpHeight + inputHeight ) : 0 );
8041
8042
		return offset;
8043
	},
8044
8045
	/* Find an object's position on the screen. */
8046
	_findPos: function( obj ) {
8047
		var position,
8048
			inst = this._getInst( obj ),
8049
			isRTL = this._get( inst, "isRTL" );
8050
8051
		while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
8052
			obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
8053
		}
8054
8055
		position = $( obj ).offset();
8056
		return [ position.left, position.top ];
8057
	},
8058
8059
	/* Hide the date picker from view.
8060
	 * @param  input  element - the input field attached to the date picker
8061
	 */
8062
	_hideDatepicker: function( input ) {
8063
		var showAnim, duration, postProcess, onClose,
8064
			inst = this._curInst;
8065
8066
		if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
8067
			return;
8068
		}
8069
8070
		if ( this._datepickerShowing ) {
8071
			showAnim = this._get( inst, "showAnim" );
8072
			duration = this._get( inst, "duration" );
8073
			postProcess = function() {
8074
				$.datepicker._tidyDialog( inst );
8075
			};
8076
8077
			// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
8078
			if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
8079
				inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
8080
			} else {
8081
				inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
8082
					( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
8083
			}
8084
8085
			if ( !showAnim ) {
8086
				postProcess();
8087
			}
8088
			this._datepickerShowing = false;
8089
8090
			onClose = this._get( inst, "onClose" );
8091
			if ( onClose ) {
8092
				onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
8093
			}
8094
8095
			this._lastInput = null;
8096
			if ( this._inDialog ) {
8097
				this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
8098
				if ( $.blockUI ) {
8099
					$.unblockUI();
8100
					$( "body" ).append( this.dpDiv );
8101
				}
8102
			}
8103
			this._inDialog = false;
8104
		}
8105
	},
8106
8107
	/* Tidy up after a dialog display. */
8108
	_tidyDialog: function( inst ) {
8109
		inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
8110
	},
8111
8112
	/* Close date picker if clicked elsewhere. */
8113
	_checkExternalClick: function( event ) {
8114
		if ( !$.datepicker._curInst ) {
8115
			return;
8116
		}
8117
8118
		var $target = $( event.target ),
8119
			inst = $.datepicker._getInst( $target[ 0 ] );
8120
8121
		if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
8122
				$target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
8123
				!$target.hasClass( $.datepicker.markerClassName ) &&
8124
				!$target.closest( "." + $.datepicker._triggerClass ).length &&
8125
				$.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
8126
			( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
8127
				$.datepicker._hideDatepicker();
8128
		}
8129
	},
8130
8131
	/* Adjust one of the date sub-fields. */
8132
	_adjustDate: function( id, offset, period ) {
8133
		var target = $( id ),
8134
			inst = this._getInst( target[ 0 ] );
8135
8136
		if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
8137
			return;
8138
		}
8139
		this._adjustInstDate( inst, offset +
8140
			( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
8141
			period );
8142
		this._updateDatepicker( inst );
8143
	},
8144
8145
	/* Action for current link. */
8146
	_gotoToday: function( id ) {
8147
		var date,
8148
			target = $( id ),
8149
			inst = this._getInst( target[ 0 ] );
8150
8151
		if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
8152
			inst.selectedDay = inst.currentDay;
8153
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8154
			inst.drawYear = inst.selectedYear = inst.currentYear;
8155
		} else {
8156
			date = new Date();
8157
			inst.selectedDay = date.getDate();
8158
			inst.drawMonth = inst.selectedMonth = date.getMonth();
8159
			inst.drawYear = inst.selectedYear = date.getFullYear();
8160
		}
8161
		this._notifyChange( inst );
8162
		this._adjustDate( target );
8163
	},
8164
8165
	/* Action for selecting a new month/year. */
8166
	_selectMonthYear: function( id, select, period ) {
8167
		var target = $( id ),
8168
			inst = this._getInst( target[ 0 ] );
8169
8170
		inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
8171
		inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
8172
			parseInt( select.options[ select.selectedIndex ].value, 10 );
8173
8174
		this._notifyChange( inst );
8175
		this._adjustDate( target );
8176
	},
8177
8178
	/* Action for selecting a day. */
8179
	_selectDay: function( id, month, year, td ) {
8180
		var inst,
8181
			target = $( id );
8182
8183
		if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
8184
			return;
8185
		}
8186
8187
		inst = this._getInst( target[ 0 ] );
8188
		inst.selectedDay = inst.currentDay = $( "a", td ).html();
8189
		inst.selectedMonth = inst.currentMonth = month;
8190
		inst.selectedYear = inst.currentYear = year;
8191
		this._selectDate( id, this._formatDate( inst,
8192
			inst.currentDay, inst.currentMonth, inst.currentYear ) );
8193
	},
8194
8195
	/* Erase the input field and hide the date picker. */
8196
	_clearDate: function( id ) {
8197
		var target = $( id );
8198
		this._selectDate( target, "" );
8199
	},
8200
8201
	/* Update the input field with the selected date. */
8202
	_selectDate: function( id, dateStr ) {
8203
		var onSelect,
8204
			target = $( id ),
8205
			inst = this._getInst( target[ 0 ] );
8206
8207
		dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
0 ignored issues
show
Best Practice introduced by
Comparing dateStr to null using the != operator is not safe. Consider using !== instead.
Loading history...
8208
		if ( inst.input ) {
8209
			inst.input.val( dateStr );
8210
		}
8211
		this._updateAlternate( inst );
8212
8213
		onSelect = this._get( inst, "onSelect" );
8214
		if ( onSelect ) {
8215
			onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );  // trigger custom callback
8216
		} else if ( inst.input ) {
8217
			inst.input.trigger( "change" ); // fire the change event
8218
		}
8219
8220
		if ( inst.inline ) {
8221
			this._updateDatepicker( inst );
8222
		} else {
8223
			this._hideDatepicker();
8224
			this._lastInput = inst.input[ 0 ];
8225
			if ( typeof( inst.input[ 0 ] ) !== "object" ) {
8226
				inst.input.trigger( "focus" ); // restore focus
8227
			}
8228
			this._lastInput = null;
8229
		}
8230
	},
8231
8232
	/* Update any alternate field to synchronise with the main field. */
8233
	_updateAlternate: function( inst ) {
8234
		var altFormat, date, dateStr,
8235
			altField = this._get( inst, "altField" );
8236
8237
		if ( altField ) { // update alternate field too
8238
			altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
8239
			date = this._getDate( inst );
8240
			dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
8241
			$( altField ).val( dateStr );
8242
		}
8243
	},
8244
8245
	/* Set as beforeShowDay function to prevent selection of weekends.
8246
	 * @param  date  Date - the date to customise
8247
	 * @return [boolean, string] - is this date selectable?, what is its CSS class?
8248
	 */
8249
	noWeekends: function( date ) {
8250
		var day = date.getDay();
8251
		return [ ( day > 0 && day < 6 ), "" ];
8252
	},
8253
8254
	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8255
	 * @param  date  Date - the date to get the week for
8256
	 * @return  number - the number of the week within the year that contains this date
8257
	 */
8258
	iso8601Week: function( date ) {
8259
		var time,
8260
			checkDate = new Date( date.getTime() );
8261
8262
		// Find Thursday of this week starting on Monday
8263
		checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
8264
8265
		time = checkDate.getTime();
8266
		checkDate.setMonth( 0 ); // Compare with Jan 1
8267
		checkDate.setDate( 1 );
8268
		return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
8269
	},
8270
8271
	/* Parse a string value into a date object.
8272
	 * See formatDate below for the possible formats.
8273
	 *
8274
	 * @param  format string - the expected format of the date
8275
	 * @param  value string - the date in the above format
8276
	 * @param  settings Object - attributes include:
8277
	 *					shortYearCutoff  number - the cutoff year for determining the century (optional)
8278
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
8279
	 *					dayNames		string[7] - names of the days from Sunday (optional)
8280
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
8281
	 *					monthNames		string[12] - names of the months (optional)
8282
	 * @return  Date - the extracted date value or null if value is blank
8283
	 */
8284
	parseDate: function( format, value, settings ) {
8285
		if ( format == null || value == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing value to null using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing format to null using the == operator is not safe. Consider using === instead.
Loading history...
8286
			throw "Invalid arguments";
8287
		}
8288
8289
		value = ( typeof value === "object" ? value.toString() : value + "" );
8290
		if ( value === "" ) {
8291
			return null;
8292
		}
8293
8294
		var iFormat, dim, extra,
8295
			iValue = 0,
8296
			shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
8297
			shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
8298
				new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
8299
			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
8300
			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
8301
			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
8302
			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
8303
			year = -1,
8304
			month = -1,
8305
			day = -1,
8306
			doy = -1,
8307
			literal = false,
8308
			date,
8309
8310
			// Check whether a format character is doubled
8311
			lookAhead = function( match ) {
8312
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8313
				if ( matches ) {
8314
					iFormat++;
8315
				}
8316
				return matches;
8317
			},
8318
8319
			// Extract a number from the string value
8320
			getNumber = function( match ) {
8321
				var isDoubled = lookAhead( match ),
8322
					size = ( match === "@" ? 14 : ( match === "!" ? 20 :
8323
					( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
8324
					minSize = ( match === "y" ? size : 1 ),
8325
					digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
8326
					num = value.substring( iValue ).match( digits );
8327
				if ( !num ) {
8328
					throw "Missing number at position " + iValue;
8329
				}
8330
				iValue += num[ 0 ].length;
8331
				return parseInt( num[ 0 ], 10 );
8332
			},
8333
8334
			// Extract a name from the string value and convert to an index
8335
			getName = function( match, shortNames, longNames ) {
8336
				var index = -1,
8337
					names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
8338
						return [ [ k, v ] ];
8339
					} ).sort( function( a, b ) {
8340
						return -( a[ 1 ].length - b[ 1 ].length );
8341
					} );
8342
8343
				$.each( names, function( i, pair ) {
8344
					var name = pair[ 1 ];
8345
					if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if value.substr(iValue, nam... === name.toLowerCase() 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...
8346
						index = pair[ 0 ];
8347
						iValue += name.length;
8348
						return false;
8349
					}
8350
				} );
8351
				if ( index !== -1 ) {
8352
					return index + 1;
8353
				} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
8354
					throw "Unknown name at position " + iValue;
8355
				}
8356
			},
8357
8358
			// Confirm that a literal character matches the string value
8359
			checkLiteral = function() {
8360
				if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
8361
					throw "Unexpected literal at position " + iValue;
8362
				}
8363
				iValue++;
8364
			};
8365
8366
		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8367
			if ( literal ) {
8368
				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8369
					literal = false;
8370
				} else {
8371
					checkLiteral();
8372
				}
8373
			} else {
8374
				switch ( format.charAt( iFormat ) ) {
8375
					case "d":
8376
						day = getNumber( "d" );
8377
						break;
8378
					case "D":
8379
						getName( "D", dayNamesShort, dayNames );
8380
						break;
8381
					case "o":
8382
						doy = getNumber( "o" );
8383
						break;
8384
					case "m":
8385
						month = getNumber( "m" );
8386
						break;
8387
					case "M":
8388
						month = getName( "M", monthNamesShort, monthNames );
8389
						break;
8390
					case "y":
8391
						year = getNumber( "y" );
8392
						break;
8393
					case "@":
8394
						date = new Date( getNumber( "@" ) );
8395
						year = date.getFullYear();
8396
						month = date.getMonth() + 1;
8397
						day = date.getDate();
8398
						break;
8399
					case "!":
8400
						date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
8401
						year = date.getFullYear();
8402
						month = date.getMonth() + 1;
8403
						day = date.getDate();
8404
						break;
8405
					case "'":
8406
						if ( lookAhead( "'" ) ) {
8407
							checkLiteral();
8408
						} else {
8409
							literal = true;
8410
						}
8411
						break;
8412
					default:
8413
						checkLiteral();
8414
				}
8415
			}
8416
		}
8417
8418
		if ( iValue < value.length ) {
8419
			extra = value.substr( iValue );
8420
			if ( !/^\s+/.test( extra ) ) {
8421
				throw "Extra/unparsed characters found in date: " + extra;
8422
			}
8423
		}
8424
8425
		if ( year === -1 ) {
8426
			year = new Date().getFullYear();
8427
		} else if ( year < 100 ) {
8428
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8429
				( year <= shortYearCutoff ? 0 : -100 );
8430
		}
8431
8432
		if ( doy > -1 ) {
8433
			month = 1;
8434
			day = doy;
8435
			do {
8436
				dim = this._getDaysInMonth( year, month - 1 );
8437
				if ( day <= dim ) {
8438
					break;
8439
				}
8440
				month++;
8441
				day -= dim;
8442
			} while ( true );
8443
		}
8444
8445
		date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
8446
		if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
8447
			throw "Invalid date"; // E.g. 31/02/00
8448
		}
8449
		return date;
8450
	},
8451
8452
	/* Standard date formats. */
8453
	ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
8454
	COOKIE: "D, dd M yy",
8455
	ISO_8601: "yy-mm-dd",
8456
	RFC_822: "D, d M y",
8457
	RFC_850: "DD, dd-M-y",
8458
	RFC_1036: "D, d M y",
8459
	RFC_1123: "D, d M yy",
8460
	RFC_2822: "D, d M yy",
8461
	RSS: "D, d M y", // RFC 822
8462
	TICKS: "!",
8463
	TIMESTAMP: "@",
8464
	W3C: "yy-mm-dd", // ISO 8601
8465
8466
	_ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
8467
		Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
8468
8469
	/* Format a date object into a string value.
8470
	 * The format can be combinations of the following:
8471
	 * d  - day of month (no leading zero)
8472
	 * dd - day of month (two digit)
8473
	 * o  - day of year (no leading zeros)
8474
	 * oo - day of year (three digit)
8475
	 * D  - day name short
8476
	 * DD - day name long
8477
	 * m  - month of year (no leading zero)
8478
	 * mm - month of year (two digit)
8479
	 * M  - month name short
8480
	 * MM - month name long
8481
	 * y  - year (two digit)
8482
	 * yy - year (four digit)
8483
	 * @ - Unix timestamp (ms since 01/01/1970)
8484
	 * ! - Windows ticks (100ns since 01/01/0001)
8485
	 * "..." - literal text
8486
	 * '' - single quote
8487
	 *
8488
	 * @param  format string - the desired format of the date
8489
	 * @param  date Date - the date value to format
8490
	 * @param  settings Object - attributes include:
8491
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
8492
	 *					dayNames		string[7] - names of the days from Sunday (optional)
8493
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
8494
	 *					monthNames		string[12] - names of the months (optional)
8495
	 * @return  string - the date in the above format
8496
	 */
8497
	formatDate: function( format, date, settings ) {
8498
		if ( !date ) {
8499
			return "";
8500
		}
8501
8502
		var iFormat,
8503
			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
8504
			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
8505
			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
8506
			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
8507
8508
			// Check whether a format character is doubled
8509
			lookAhead = function( match ) {
8510
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8511
				if ( matches ) {
8512
					iFormat++;
8513
				}
8514
				return matches;
8515
			},
8516
8517
			// Format a number, with leading zero if necessary
8518
			formatNumber = function( match, value, len ) {
8519
				var num = "" + value;
8520
				if ( lookAhead( match ) ) {
8521
					while ( num.length < len ) {
8522
						num = "0" + num;
8523
					}
8524
				}
8525
				return num;
8526
			},
8527
8528
			// Format a name, short or long as requested
8529
			formatName = function( match, value, shortNames, longNames ) {
8530
				return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
8531
			},
8532
			output = "",
8533
			literal = false;
8534
8535
		if ( date ) {
8536
			for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8537
				if ( literal ) {
8538
					if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8539
						literal = false;
8540
					} else {
8541
						output += format.charAt( iFormat );
8542
					}
8543
				} else {
8544
					switch ( format.charAt( iFormat ) ) {
8545
						case "d":
8546
							output += formatNumber( "d", date.getDate(), 2 );
8547
							break;
8548
						case "D":
8549
							output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
8550
							break;
8551
						case "o":
8552
							output += formatNumber( "o",
8553
								Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
8554
							break;
8555
						case "m":
8556
							output += formatNumber( "m", date.getMonth() + 1, 2 );
8557
							break;
8558
						case "M":
8559
							output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
8560
							break;
8561
						case "y":
8562
							output += ( lookAhead( "y" ) ? date.getFullYear() :
8563
								( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
8564
							break;
8565
						case "@":
8566
							output += date.getTime();
8567
							break;
8568
						case "!":
8569
							output += date.getTime() * 10000 + this._ticksTo1970;
8570
							break;
8571
						case "'":
8572
							if ( lookAhead( "'" ) ) {
8573
								output += "'";
8574
							} else {
8575
								literal = true;
8576
							}
8577
							break;
8578
						default:
8579
							output += format.charAt( iFormat );
8580
					}
8581
				}
8582
			}
8583
		}
8584
		return output;
8585
	},
8586
8587
	/* Extract all possible characters from the date format. */
8588
	_possibleChars: function( format ) {
8589
		var iFormat,
8590
			chars = "",
8591
			literal = false,
8592
8593
			// Check whether a format character is doubled
8594
			lookAhead = function( match ) {
8595
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8596
				if ( matches ) {
8597
					iFormat++;
8598
				}
8599
				return matches;
8600
			};
8601
8602
		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8603
			if ( literal ) {
8604
				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8605
					literal = false;
8606
				} else {
8607
					chars += format.charAt( iFormat );
8608
				}
8609
			} else {
8610
				switch ( format.charAt( iFormat ) ) {
8611
					case "d": case "m": case "y": case "@":
8612
						chars += "0123456789";
8613
						break;
8614
					case "D": case "M":
8615
						return null; // Accept anything
8616
					case "'":
8617
						if ( lookAhead( "'" ) ) {
8618
							chars += "'";
8619
						} else {
8620
							literal = true;
8621
						}
8622
						break;
8623
					default:
8624
						chars += format.charAt( iFormat );
8625
				}
8626
			}
8627
		}
8628
		return chars;
8629
	},
8630
8631
	/* Get a setting value, defaulting if necessary. */
8632
	_get: function( inst, name ) {
8633
		return inst.settings[ name ] !== undefined ?
8634
			inst.settings[ name ] : this._defaults[ name ];
8635
	},
8636
8637
	/* Parse existing date and initialise date picker. */
8638
	_setDateFromField: function( inst, noDefault ) {
8639
		if ( inst.input.val() === inst.lastVal ) {
8640
			return;
8641
		}
8642
8643
		var dateFormat = this._get( inst, "dateFormat" ),
8644
			dates = inst.lastVal = inst.input ? inst.input.val() : null,
8645
			defaultDate = this._getDefaultDate( inst ),
8646
			date = defaultDate,
0 ignored issues
show
Unused Code introduced by
The assignment to variable date seems to be never used. Consider removing it.
Loading history...
8647
			settings = this._getFormatConfig( inst );
8648
8649
		try {
8650
			date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
8651
		} catch ( event ) {
8652
			dates = ( noDefault ? "" : dates );
8653
		}
8654
		inst.selectedDay = date.getDate();
8655
		inst.drawMonth = inst.selectedMonth = date.getMonth();
8656
		inst.drawYear = inst.selectedYear = date.getFullYear();
8657
		inst.currentDay = ( dates ? date.getDate() : 0 );
8658
		inst.currentMonth = ( dates ? date.getMonth() : 0 );
8659
		inst.currentYear = ( dates ? date.getFullYear() : 0 );
8660
		this._adjustInstDate( inst );
8661
	},
8662
8663
	/* Retrieve the default date shown on opening. */
8664
	_getDefaultDate: function( inst ) {
8665
		return this._restrictMinMax( inst,
8666
			this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
8667
	},
8668
8669
	/* A date may be specified as an exact value or a relative one. */
8670
	_determineDate: function( inst, date, defaultDate ) {
8671
		var offsetNumeric = function( offset ) {
8672
				var date = new Date();
8673
				date.setDate( date.getDate() + offset );
8674
				return date;
8675
			},
8676
			offsetString = function( offset ) {
8677
				try {
8678
					return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
8679
						offset, $.datepicker._getFormatConfig( inst ) );
8680
				}
8681
				catch ( e ) {
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
8682
8683
					// Ignore
8684
				}
8685
8686
				var date = ( offset.toLowerCase().match( /^c/ ) ?
8687
					$.datepicker._getDate( inst ) : null ) || new Date(),
8688
					year = date.getFullYear(),
8689
					month = date.getMonth(),
8690
					day = date.getDate(),
8691
					pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
8692
					matches = pattern.exec( offset );
8693
8694
				while ( matches ) {
8695
					switch ( matches[ 2 ] || "d" ) {
8696
						case "d" : case "D" :
8697
							day += parseInt( matches[ 1 ], 10 ); break;
8698
						case "w" : case "W" :
8699
							day += parseInt( matches[ 1 ], 10 ) * 7; break;
8700
						case "m" : case "M" :
8701
							month += parseInt( matches[ 1 ], 10 );
8702
							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
8703
							break;
8704
						case "y": case "Y" :
8705
							year += parseInt( matches[ 1 ], 10 );
8706
							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
8707
							break;
8708
					}
8709
					matches = pattern.exec( offset );
8710
				}
8711
				return new Date( year, month, day );
8712
			},
8713
			newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
0 ignored issues
show
Best Practice introduced by
Comparing date to null using the == operator is not safe. Consider using === instead.
Loading history...
8714
				( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
8715
8716
		newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
8717
		if ( newDate ) {
8718
			newDate.setHours( 0 );
8719
			newDate.setMinutes( 0 );
8720
			newDate.setSeconds( 0 );
8721
			newDate.setMilliseconds( 0 );
8722
		}
8723
		return this._daylightSavingAdjust( newDate );
8724
	},
8725
8726
	/* Handle switch to/from daylight saving.
8727
	 * Hours may be non-zero on daylight saving cut-over:
8728
	 * > 12 when midnight changeover, but then cannot generate
8729
	 * midnight datetime, so jump to 1AM, otherwise reset.
8730
	 * @param  date  (Date) the date to check
8731
	 * @return  (Date) the corrected date
8732
	 */
8733
	_daylightSavingAdjust: function( date ) {
8734
		if ( !date ) {
8735
			return null;
8736
		}
8737
		date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
8738
		return date;
8739
	},
8740
8741
	/* Set the date(s) directly. */
8742
	_setDate: function( inst, date, noChange ) {
8743
		var clear = !date,
8744
			origMonth = inst.selectedMonth,
8745
			origYear = inst.selectedYear,
8746
			newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
8747
8748
		inst.selectedDay = inst.currentDay = newDate.getDate();
8749
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
8750
		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
8751
		if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
8752
			this._notifyChange( inst );
8753
		}
8754
		this._adjustInstDate( inst );
8755
		if ( inst.input ) {
8756
			inst.input.val( clear ? "" : this._formatDate( inst ) );
8757
		}
8758
	},
8759
8760
	/* Retrieve the date(s) directly. */
8761
	_getDate: function( inst ) {
8762
		var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
8763
			this._daylightSavingAdjust( new Date(
8764
			inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
8765
			return startDate;
8766
	},
8767
8768
	/* Attach the onxxx handlers.  These are declared statically so
8769
	 * they work with static code transformers like Caja.
8770
	 */
8771
	_attachHandlers: function( inst ) {
8772
		var stepMonths = this._get( inst, "stepMonths" ),
8773
			id = "#" + inst.id.replace( /\\\\/g, "\\" );
8774
		inst.dpDiv.find( "[data-handler]" ).map( function() {
8775
			var handler = {
8776
				prev: function() {
8777
					$.datepicker._adjustDate( id, -stepMonths, "M" );
8778
				},
8779
				next: function() {
8780
					$.datepicker._adjustDate( id, +stepMonths, "M" );
8781
				},
8782
				hide: function() {
8783
					$.datepicker._hideDatepicker();
8784
				},
8785
				today: function() {
8786
					$.datepicker._gotoToday( id );
8787
				},
8788
				selectDay: function() {
8789
					$.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
8790
					return false;
8791
				},
8792
				selectMonth: function() {
8793
					$.datepicker._selectMonthYear( id, this, "M" );
8794
					return false;
8795
				},
8796
				selectYear: function() {
8797
					$.datepicker._selectMonthYear( id, this, "Y" );
8798
					return false;
8799
				}
8800
			};
8801
			$( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
8802
		} );
8803
	},
8804
8805
	/* Generate the HTML for the current state of the date picker. */
8806
	_generateHTML: function( inst ) {
8807
		var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
8808
			controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
8809
			monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
8810
			selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
8811
			cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
8812
			printDate, dRow, tbody, daySettings, otherMonth, unselectable,
8813
			tempDate = new Date(),
8814
			today = this._daylightSavingAdjust(
8815
				new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
8816
			isRTL = this._get( inst, "isRTL" ),
8817
			showButtonPanel = this._get( inst, "showButtonPanel" ),
8818
			hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
8819
			navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
8820
			numMonths = this._getNumberOfMonths( inst ),
8821
			showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
8822
			stepMonths = this._get( inst, "stepMonths" ),
8823
			isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
8824
			currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
8825
				new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
8826
			minDate = this._getMinMaxDate( inst, "min" ),
8827
			maxDate = this._getMinMaxDate( inst, "max" ),
8828
			drawMonth = inst.drawMonth - showCurrentAtPos,
8829
			drawYear = inst.drawYear;
8830
8831
		if ( drawMonth < 0 ) {
8832
			drawMonth += 12;
8833
			drawYear--;
8834
		}
8835
		if ( maxDate ) {
8836
			maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
8837
				maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
8838
			maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
8839
			while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
8840
				drawMonth--;
8841
				if ( drawMonth < 0 ) {
8842
					drawMonth = 11;
8843
					drawYear--;
8844
				}
8845
			}
8846
		}
8847
		inst.drawMonth = drawMonth;
8848
		inst.drawYear = drawYear;
8849
8850
		prevText = this._get( inst, "prevText" );
8851
		prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
8852
			this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
8853
			this._getFormatConfig( inst ) ) );
8854
8855
		prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
8856
			"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
8857
			" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
8858
			( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) );
8859
8860
		nextText = this._get( inst, "nextText" );
8861
		nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
8862
			this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
8863
			this._getFormatConfig( inst ) ) );
8864
8865
		next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
8866
			"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
8867
			" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
8868
			( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) );
8869
8870
		currentText = this._get( inst, "currentText" );
8871
		gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
8872
		currentText = ( !navigationAsDateFormat ? currentText :
8873
			this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
8874
8875
		controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
8876
			this._get( inst, "closeText" ) + "</button>" : "" );
8877
8878
		buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
8879
			( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
8880
			">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
8881
8882
		firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
8883
		firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
8884
8885
		showWeek = this._get( inst, "showWeek" );
8886
		dayNames = this._get( inst, "dayNames" );
8887
		dayNamesMin = this._get( inst, "dayNamesMin" );
8888
		monthNames = this._get( inst, "monthNames" );
8889
		monthNamesShort = this._get( inst, "monthNamesShort" );
8890
		beforeShowDay = this._get( inst, "beforeShowDay" );
8891
		showOtherMonths = this._get( inst, "showOtherMonths" );
8892
		selectOtherMonths = this._get( inst, "selectOtherMonths" );
8893
		defaultDate = this._getDefaultDate( inst );
8894
		html = "";
8895
8896
		for ( row = 0; row < numMonths[ 0 ]; row++ ) {
8897
			group = "";
8898
			this.maxRows = 4;
8899
			for ( col = 0; col < numMonths[ 1 ]; col++ ) {
8900
				selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
8901
				cornerClass = " ui-corner-all";
8902
				calender = "";
8903
				if ( isMultiMonth ) {
8904
					calender += "<div class='ui-datepicker-group";
8905
					if ( numMonths[ 1 ] > 1 ) {
8906
						switch ( col ) {
8907
							case 0: calender += " ui-datepicker-group-first";
8908
								cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
8909
							case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
8910
								cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
8911
							default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
8912
						}
8913
					}
8914
					calender += "'>";
8915
				}
8916
				calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
8917
					( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
8918
					( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
8919
					this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
8920
					row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
8921
					"</div><table class='ui-datepicker-calendar'><thead>" +
8922
					"<tr>";
8923
				thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
8924
				for ( dow = 0; dow < 7; dow++ ) { // days of the week
8925
					day = ( dow + firstDay ) % 7;
8926
					thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
8927
						"<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
8928
				}
8929
				calender += thead + "</tr></thead><tbody>";
8930
				daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
8931
				if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
8932
					inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
8933
				}
8934
				leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
8935
				curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
8936
				numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
8937
				this.maxRows = numRows;
8938
				printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
8939
				for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
8940
					calender += "<tr>";
8941
					tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
8942
						this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
8943
					for ( dow = 0; dow < 7; dow++ ) { // create date picker days
8944
						daySettings = ( beforeShowDay ?
8945
							beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
8946
						otherMonth = ( printDate.getMonth() !== drawMonth );
8947
						unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
8948
							( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
8949
						tbody += "<td class='" +
8950
							( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
8951
							( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
8952
							( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
8953
							( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
8954
8955
							// or defaultDate is current printedDate and defaultDate is selectedDate
8956
							" " + this._dayOverClass : "" ) + // highlight selected day
8957
							( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) +  // highlight unselectable days
8958
							( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
8959
							( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
8960
							( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
8961
							( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
8962
							( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
8963
							( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
8964
							( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
8965
							( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
8966
							( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
8967
							( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
8968
							"' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
8969
						printDate.setDate( printDate.getDate() + 1 );
8970
						printDate = this._daylightSavingAdjust( printDate );
8971
					}
8972
					calender += tbody + "</tr>";
8973
				}
8974
				drawMonth++;
8975
				if ( drawMonth > 11 ) {
8976
					drawMonth = 0;
8977
					drawYear++;
8978
				}
8979
				calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
8980
							( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
8981
				group += calender;
8982
			}
8983
			html += group;
8984
		}
8985
		html += buttonPanel;
8986
		inst._keyEvent = false;
8987
		return html;
8988
	},
8989
8990
	/* Generate the month and year header. */
8991
	_generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
8992
			secondary, monthNames, monthNamesShort ) {
8993
8994
		var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
8995
			changeMonth = this._get( inst, "changeMonth" ),
8996
			changeYear = this._get( inst, "changeYear" ),
8997
			showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
8998
			html = "<div class='ui-datepicker-title'>",
8999
			monthHtml = "";
9000
9001
		// Month selection
9002
		if ( secondary || !changeMonth ) {
9003
			monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
9004
		} else {
9005
			inMinYear = ( minDate && minDate.getFullYear() === drawYear );
9006
			inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
9007
			monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
9008
			for ( month = 0; month < 12; month++ ) {
9009
				if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
9010
					monthHtml += "<option value='" + month + "'" +
9011
						( month === drawMonth ? " selected='selected'" : "" ) +
9012
						">" + monthNamesShort[ month ] + "</option>";
9013
				}
9014
			}
9015
			monthHtml += "</select>";
9016
		}
9017
9018
		if ( !showMonthAfterYear ) {
9019
			html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
9020
		}
9021
9022
		// Year selection
9023
		if ( !inst.yearshtml ) {
9024
			inst.yearshtml = "";
9025
			if ( secondary || !changeYear ) {
9026
				html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
9027
			} else {
9028
9029
				// determine range of years to display
9030
				years = this._get( inst, "yearRange" ).split( ":" );
9031
				thisYear = new Date().getFullYear();
9032
				determineYear = function( value ) {
9033
					var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
9034
						( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
9035
						parseInt( value, 10 ) ) );
9036
					return ( isNaN( year ) ? thisYear : year );
9037
				};
9038
				year = determineYear( years[ 0 ] );
9039
				endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
9040
				year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
9041
				endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
9042
				inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
9043
				for ( ; year <= endYear; year++ ) {
9044
					inst.yearshtml += "<option value='" + year + "'" +
9045
						( year === drawYear ? " selected='selected'" : "" ) +
9046
						">" + year + "</option>";
9047
				}
9048
				inst.yearshtml += "</select>";
9049
9050
				html += inst.yearshtml;
9051
				inst.yearshtml = null;
9052
			}
9053
		}
9054
9055
		html += this._get( inst, "yearSuffix" );
9056
		if ( showMonthAfterYear ) {
9057
			html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
9058
		}
9059
		html += "</div>"; // Close datepicker_header
9060
		return html;
9061
	},
9062
9063
	/* Adjust one of the date sub-fields. */
9064
	_adjustInstDate: function( inst, offset, period ) {
9065
		var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
9066
			month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
9067
			day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
9068
			date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
9069
9070
		inst.selectedDay = date.getDate();
9071
		inst.drawMonth = inst.selectedMonth = date.getMonth();
9072
		inst.drawYear = inst.selectedYear = date.getFullYear();
9073
		if ( period === "M" || period === "Y" ) {
9074
			this._notifyChange( inst );
9075
		}
9076
	},
9077
9078
	/* Ensure a date is within any min/max bounds. */
9079
	_restrictMinMax: function( inst, date ) {
9080
		var minDate = this._getMinMaxDate( inst, "min" ),
9081
			maxDate = this._getMinMaxDate( inst, "max" ),
9082
			newDate = ( minDate && date < minDate ? minDate : date );
9083
		return ( maxDate && newDate > maxDate ? maxDate : newDate );
9084
	},
9085
9086
	/* Notify change of month/year. */
9087
	_notifyChange: function( inst ) {
9088
		var onChange = this._get( inst, "onChangeMonthYear" );
9089
		if ( onChange ) {
9090
			onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
9091
				[ inst.selectedYear, inst.selectedMonth + 1, inst ] );
9092
		}
9093
	},
9094
9095
	/* Determine the number of months to show. */
9096
	_getNumberOfMonths: function( inst ) {
9097
		var numMonths = this._get( inst, "numberOfMonths" );
9098
		return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
0 ignored issues
show
Best Practice introduced by
Comparing numMonths to null using the == operator is not safe. Consider using === instead.
Loading history...
9099
	},
9100
9101
	/* Determine the current maximum date - ensure no time components are set. */
9102
	_getMinMaxDate: function( inst, minMax ) {
9103
		return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
9104
	},
9105
9106
	/* Find the number of days in a given month. */
9107
	_getDaysInMonth: function( year, month ) {
9108
		return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
9109
	},
9110
9111
	/* Find the day of the week of the first of a month. */
9112
	_getFirstDayOfMonth: function( year, month ) {
9113
		return new Date( year, month, 1 ).getDay();
9114
	},
9115
9116
	/* Determines if we should allow a "next/prev" month display change. */
9117
	_canAdjustMonth: function( inst, offset, curYear, curMonth ) {
9118
		var numMonths = this._getNumberOfMonths( inst ),
9119
			date = this._daylightSavingAdjust( new Date( curYear,
9120
			curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
9121
9122
		if ( offset < 0 ) {
9123
			date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
9124
		}
9125
		return this._isInRange( inst, date );
9126
	},
9127
9128
	/* Is the given date in the accepted range? */
9129
	_isInRange: function( inst, date ) {
9130
		var yearSplit, currentYear,
9131
			minDate = this._getMinMaxDate( inst, "min" ),
9132
			maxDate = this._getMinMaxDate( inst, "max" ),
9133
			minYear = null,
9134
			maxYear = null,
9135
			years = this._get( inst, "yearRange" );
9136
			if ( years ) {
9137
				yearSplit = years.split( ":" );
9138
				currentYear = new Date().getFullYear();
9139
				minYear = parseInt( yearSplit[ 0 ], 10 );
9140
				maxYear = parseInt( yearSplit[ 1 ], 10 );
9141
				if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
9142
					minYear += currentYear;
9143
				}
9144
				if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
9145
					maxYear += currentYear;
9146
				}
9147
			}
9148
9149
		return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
9150
			( !maxDate || date.getTime() <= maxDate.getTime() ) &&
9151
			( !minYear || date.getFullYear() >= minYear ) &&
9152
			( !maxYear || date.getFullYear() <= maxYear ) );
9153
	},
9154
9155
	/* Provide the configuration settings for formatting/parsing. */
9156
	_getFormatConfig: function( inst ) {
9157
		var shortYearCutoff = this._get( inst, "shortYearCutoff" );
9158
		shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
9159
			new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
9160
		return { shortYearCutoff: shortYearCutoff,
9161
			dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
9162
			monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
9163
	},
9164
9165
	/* Format the given date for display. */
9166
	_formatDate: function( inst, day, month, year ) {
9167
		if ( !day ) {
9168
			inst.currentDay = inst.selectedDay;
9169
			inst.currentMonth = inst.selectedMonth;
9170
			inst.currentYear = inst.selectedYear;
9171
		}
9172
		var date = ( day ? ( typeof day === "object" ? day :
9173
			this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
9174
			this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
9175
		return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
9176
	}
9177
} );
9178
9179
/*
9180
 * Bind hover events for datepicker elements.
9181
 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
9182
 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
9183
 */
9184
function datepicker_bindHover( dpDiv ) {
9185
	var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
9186
	return dpDiv.on( "mouseout", selector, function() {
9187
			$( this ).removeClass( "ui-state-hover" );
9188
			if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
9189
				$( this ).removeClass( "ui-datepicker-prev-hover" );
9190
			}
9191
			if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
9192
				$( this ).removeClass( "ui-datepicker-next-hover" );
9193
			}
9194
		} )
9195
		.on( "mouseover", selector, datepicker_handleMouseover );
9196
}
9197
9198
function datepicker_handleMouseover() {
9199
	if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
9200
		$( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
9201
		$( this ).addClass( "ui-state-hover" );
9202
		if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
9203
			$( this ).addClass( "ui-datepicker-prev-hover" );
9204
		}
9205
		if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
9206
			$( this ).addClass( "ui-datepicker-next-hover" );
9207
		}
9208
	}
9209
}
9210
9211
/* jQuery extend now ignores nulls! */
9212
function datepicker_extendRemove( target, props ) {
9213
	$.extend( target, props );
9214
	for ( var name in props ) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
9215
		if ( props[ name ] == null ) {
0 ignored issues
show
Best Practice introduced by
Comparing props.name to null using the == operator is not safe. Consider using === instead.
Loading history...
9216
			target[ name ] = props[ name ];
9217
		}
9218
	}
9219
	return target;
9220
}
9221
9222
/* Invoke the datepicker functionality.
9223
   @param  options  string - a command, optionally followed by additional parameters or
9224
					Object - settings for attaching new datepicker functionality
9225
   @return  jQuery object */
9226
$.fn.datepicker = function( options ) {
9227
9228
	/* Verify an empty collection wasn't passed - Fixes #6976 */
9229
	if ( !this.length ) {
9230
		return this;
9231
	}
9232
9233
	/* Initialise the date picker. */
9234
	if ( !$.datepicker.initialized ) {
9235
		$( document ).on( "mousedown", $.datepicker._checkExternalClick );
9236
		$.datepicker.initialized = true;
9237
	}
9238
9239
	/* Append datepicker main container to body if not exist. */
9240
	if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
9241
		$( "body" ).append( $.datepicker.dpDiv );
9242
	}
9243
9244
	var otherArgs = Array.prototype.slice.call( arguments, 1 );
9245
	if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
9246
		return $.datepicker[ "_" + options + "Datepicker" ].
9247
			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
9248
	}
9249
	if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
9250
		return $.datepicker[ "_" + options + "Datepicker" ].
9251
			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
9252
	}
9253
	return this.each( function() {
9254
		typeof options === "string" ?
9255
			$.datepicker[ "_" + options + "Datepicker" ].
9256
				apply( $.datepicker, [ this ].concat( otherArgs ) ) :
9257
			$.datepicker._attachDatepicker( this, options );
9258
	} );
9259
};
9260
9261
$.datepicker = new Datepicker(); // singleton instance
9262
$.datepicker.initialized = false;
9263
$.datepicker.uuid = new Date().getTime();
9264
$.datepicker.version = "1.12.1";
9265
9266
var widgetsDatepicker = $.datepicker;
0 ignored issues
show
Unused Code introduced by
The variable widgetsDatepicker seems to be never used. Consider removing it.
Loading history...
9267
9268
9269
9270
9271
// This file is deprecated
9272
var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
9273
9274
/*!
9275
 * jQuery UI Mouse 1.12.1
9276
 * http://jqueryui.com
9277
 *
9278
 * Copyright jQuery Foundation and other contributors
9279
 * Released under the MIT license.
9280
 * http://jquery.org/license
9281
 */
9282
9283
//>>label: Mouse
9284
//>>group: Widgets
9285
//>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
9286
//>>docs: http://api.jqueryui.com/mouse/
9287
9288
9289
9290
var mouseHandled = false;
9291
$( document ).on( "mouseup", function() {
9292
	mouseHandled = false;
9293
} );
9294
9295
var widgetsMouse = $.widget( "ui.mouse", {
0 ignored issues
show
Unused Code introduced by
The variable widgetsMouse seems to be never used. Consider removing it.
Loading history...
9296
	version: "1.12.1",
9297
	options: {
9298
		cancel: "input, textarea, button, select, option",
9299
		distance: 1,
9300
		delay: 0
9301
	},
9302
	_mouseInit: function() {
9303
		var that = this;
9304
9305
		this.element
9306
			.on( "mousedown." + this.widgetName, function( event ) {
9307
				return that._mouseDown( event );
9308
			} )
9309
			.on( "click." + this.widgetName, function( event ) {
9310
				if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if true === $.data(event.ta...+ ".preventClickEvent") 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...
9311
					$.removeData( event.target, that.widgetName + ".preventClickEvent" );
9312
					event.stopImmediatePropagation();
9313
					return false;
9314
				}
9315
			} );
9316
9317
		this.started = false;
9318
	},
9319
9320
	// TODO: make sure destroying one instance of mouse doesn't mess with
9321
	// other instances of mouse
9322
	_mouseDestroy: function() {
9323
		this.element.off( "." + this.widgetName );
9324
		if ( this._mouseMoveDelegate ) {
9325
			this.document
9326
				.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9327
				.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
9328
		}
9329
	},
9330
9331
	_mouseDown: function( event ) {
9332
9333
		// don't let more than one widget handle mouseStart
9334
		if ( mouseHandled ) {
9335
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
9336
		}
9337
9338
		this._mouseMoved = false;
9339
9340
		// We may have missed mouseup (out of window)
9341
		( this._mouseStarted && this._mouseUp( event ) );
9342
9343
		this._mouseDownEvent = event;
9344
9345
		var that = this,
9346
			btnIsLeft = ( event.which === 1 ),
9347
9348
			// event.target.nodeName works around a bug in IE 8 with
9349
			// disabled inputs (#7620)
9350
			elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
9351
				$( event.target ).closest( this.options.cancel ).length : false );
9352
		if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
9353
			return true;
9354
		}
9355
9356
		this.mouseDelayMet = !this.options.delay;
9357
		if ( !this.mouseDelayMet ) {
9358
			this._mouseDelayTimer = setTimeout( function() {
9359
				that.mouseDelayMet = true;
9360
			}, this.options.delay );
9361
		}
9362
9363
		if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
9364
			this._mouseStarted = ( this._mouseStart( event ) !== false );
9365
			if ( !this._mouseStarted ) {
9366
				event.preventDefault();
9367
				return true;
9368
			}
9369
		}
9370
9371
		// Click event may never have fired (Gecko & Opera)
9372
		if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
9373
			$.removeData( event.target, this.widgetName + ".preventClickEvent" );
9374
		}
9375
9376
		// These delegates are required to keep context
9377
		this._mouseMoveDelegate = function( event ) {
9378
			return that._mouseMove( event );
9379
		};
9380
		this._mouseUpDelegate = function( event ) {
9381
			return that._mouseUp( event );
9382
		};
9383
9384
		this.document
9385
			.on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9386
			.on( "mouseup." + this.widgetName, this._mouseUpDelegate );
9387
9388
		event.preventDefault();
9389
9390
		mouseHandled = true;
9391
		return true;
9392
	},
9393
9394
	_mouseMove: function( event ) {
9395
9396
		// Only check for mouseups outside the document if you've moved inside the document
9397
		// at least once. This prevents the firing of mouseup in the case of IE<9, which will
9398
		// fire a mousemove event if content is placed under the cursor. See #7778
9399
		// Support: IE <9
9400
		if ( this._mouseMoved ) {
9401
9402
			// IE mouseup check - mouseup happened when mouse was out of window
9403
			if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
9404
					!event.button ) {
9405
				return this._mouseUp( event );
9406
9407
			// Iframe mouseup check - mouseup occurred in another document
9408
			} else if ( !event.which ) {
9409
9410
				// Support: Safari <=8 - 9
9411
				// Safari sets which to 0 if you press any of the following keys
9412
				// during a drag (#14461)
9413
				if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
9414
						event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
9415
					this.ignoreMissingWhich = true;
9416
				} else if ( !this.ignoreMissingWhich ) {
9417
					return this._mouseUp( event );
9418
				}
9419
			}
9420
		}
9421
9422
		if ( event.which || event.button ) {
9423
			this._mouseMoved = true;
9424
		}
9425
9426
		if ( this._mouseStarted ) {
9427
			this._mouseDrag( event );
9428
			return event.preventDefault();
9429
		}
9430
9431
		if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
9432
			this._mouseStarted =
9433
				( this._mouseStart( this._mouseDownEvent, event ) !== false );
9434
			( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
9435
		}
9436
9437
		return !this._mouseStarted;
9438
	},
9439
9440
	_mouseUp: function( event ) {
9441
		this.document
9442
			.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9443
			.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
9444
9445
		if ( this._mouseStarted ) {
9446
			this._mouseStarted = false;
9447
9448
			if ( event.target === this._mouseDownEvent.target ) {
9449
				$.data( event.target, this.widgetName + ".preventClickEvent", true );
9450
			}
9451
9452
			this._mouseStop( event );
9453
		}
9454
9455
		if ( this._mouseDelayTimer ) {
9456
			clearTimeout( this._mouseDelayTimer );
9457
			delete this._mouseDelayTimer;
9458
		}
9459
9460
		this.ignoreMissingWhich = false;
9461
		mouseHandled = false;
9462
		event.preventDefault();
9463
	},
9464
9465
	_mouseDistanceMet: function( event ) {
9466
		return ( Math.max(
9467
				Math.abs( this._mouseDownEvent.pageX - event.pageX ),
9468
				Math.abs( this._mouseDownEvent.pageY - event.pageY )
9469
			) >= this.options.distance
9470
		);
9471
	},
9472
9473
	_mouseDelayMet: function( /* event */ ) {
9474
		return this.mouseDelayMet;
9475
	},
9476
9477
	// These are placeholder methods, to be overriden by extending plugin
9478
	_mouseStart: function( /* event */ ) {},
9479
	_mouseDrag: function( /* event */ ) {},
9480
	_mouseStop: function( /* event */ ) {},
9481
	_mouseCapture: function( /* event */ ) { return true; }
9482
} );
9483
9484
9485
9486
9487
// $.ui.plugin is deprecated. Use $.widget() extensions instead.
9488
var plugin = $.ui.plugin = {
9489
	add: function( module, option, set ) {
9490
		var i,
9491
			proto = $.ui[ module ].prototype;
9492
		for ( i in set ) {
9493
			proto.plugins[ i ] = proto.plugins[ i ] || [];
9494
			proto.plugins[ i ].push( [ option, set[ i ] ] );
9495
		}
9496
	},
9497
	call: function( instance, name, args, allowDisconnected ) {
9498
		var i,
9499
			set = instance.plugins[ name ];
9500
9501
		if ( !set ) {
9502
			return;
9503
		}
9504
9505
		if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
9506
				instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
9507
			return;
9508
		}
9509
9510
		for ( i = 0; i < set.length; i++ ) {
9511
			if ( instance.options[ set[ i ][ 0 ] ] ) {
9512
				set[ i ][ 1 ].apply( instance.element, args );
9513
			}
9514
		}
9515
	}
9516
};
9517
9518
9519
9520
var safeBlur = $.ui.safeBlur = function( element ) {
9521
9522
	// Support: IE9 - 10 only
9523
	// If the <body> is blurred, IE will switch windows, see #9420
9524
	if ( element && element.nodeName.toLowerCase() !== "body" ) {
9525
		$( element ).trigger( "blur" );
9526
	}
9527
};
9528
9529
9530
/*!
9531
 * jQuery UI Draggable 1.12.1
9532
 * http://jqueryui.com
9533
 *
9534
 * Copyright jQuery Foundation and other contributors
9535
 * Released under the MIT license.
9536
 * http://jquery.org/license
9537
 */
9538
9539
//>>label: Draggable
9540
//>>group: Interactions
9541
//>>description: Enables dragging functionality for any element.
9542
//>>docs: http://api.jqueryui.com/draggable/
9543
//>>demos: http://jqueryui.com/draggable/
9544
//>>css.structure: ../../themes/base/draggable.css
9545
9546
9547
9548
$.widget( "ui.draggable", $.ui.mouse, {
9549
	version: "1.12.1",
9550
	widgetEventPrefix: "drag",
9551
	options: {
9552
		addClasses: true,
9553
		appendTo: "parent",
9554
		axis: false,
9555
		connectToSortable: false,
9556
		containment: false,
9557
		cursor: "auto",
9558
		cursorAt: false,
9559
		grid: false,
9560
		handle: false,
9561
		helper: "original",
9562
		iframeFix: false,
9563
		opacity: false,
9564
		refreshPositions: false,
9565
		revert: false,
9566
		revertDuration: 500,
9567
		scope: "default",
9568
		scroll: true,
9569
		scrollSensitivity: 20,
9570
		scrollSpeed: 20,
9571
		snap: false,
9572
		snapMode: "both",
9573
		snapTolerance: 20,
9574
		stack: false,
9575
		zIndex: false,
9576
9577
		// Callbacks
9578
		drag: null,
9579
		start: null,
9580
		stop: null
9581
	},
9582
	_create: function() {
9583
9584
		if ( this.options.helper === "original" ) {
9585
			this._setPositionRelative();
9586
		}
9587
		if ( this.options.addClasses ) {
9588
			this._addClass( "ui-draggable" );
9589
		}
9590
		this._setHandleClassName();
9591
9592
		this._mouseInit();
9593
	},
9594
9595
	_setOption: function( key, value ) {
9596
		this._super( key, value );
9597
		if ( key === "handle" ) {
9598
			this._removeHandleClassName();
9599
			this._setHandleClassName();
9600
		}
9601
	},
9602
9603
	_destroy: function() {
9604
		if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
9605
			this.destroyOnClear = true;
9606
			return;
9607
		}
9608
		this._removeHandleClassName();
9609
		this._mouseDestroy();
9610
	},
9611
9612
	_mouseCapture: function( event ) {
9613
		var o = this.options;
9614
9615
		// Among others, prevent a drag on a resizable-handle
9616
		if ( this.helper || o.disabled ||
9617
				$( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
9618
			return false;
9619
		}
9620
9621
		//Quit if we're not on a valid handle
9622
		this.handle = this._getHandle( event );
9623
		if ( !this.handle ) {
9624
			return false;
9625
		}
9626
9627
		this._blurActiveElement( event );
9628
9629
		this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
9630
9631
		return true;
9632
9633
	},
9634
9635
	_blockFrames: function( selector ) {
9636
		this.iframeBlocks = this.document.find( selector ).map( function() {
9637
			var iframe = $( this );
9638
9639
			return $( "<div>" )
9640
				.css( "position", "absolute" )
9641
				.appendTo( iframe.parent() )
9642
				.outerWidth( iframe.outerWidth() )
9643
				.outerHeight( iframe.outerHeight() )
9644
				.offset( iframe.offset() )[ 0 ];
9645
		} );
9646
	},
9647
9648
	_unblockFrames: function() {
9649
		if ( this.iframeBlocks ) {
9650
			this.iframeBlocks.remove();
9651
			delete this.iframeBlocks;
9652
		}
9653
	},
9654
9655
	_blurActiveElement: function( event ) {
9656
		var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
9657
			target = $( event.target );
9658
9659
		// Don't blur if the event occurred on an element that is within
9660
		// the currently focused element
9661
		// See #10527, #12472
9662
		if ( target.closest( activeElement ).length ) {
9663
			return;
9664
		}
9665
9666
		// Blur any element that currently has focus, see #4261
9667
		$.ui.safeBlur( activeElement );
9668
	},
9669
9670
	_mouseStart: function( event ) {
9671
9672
		var o = this.options;
9673
9674
		//Create and append the visible helper
9675
		this.helper = this._createHelper( event );
9676
9677
		this._addClass( this.helper, "ui-draggable-dragging" );
9678
9679
		//Cache the helper size
9680
		this._cacheHelperProportions();
9681
9682
		//If ddmanager is used for droppables, set the global draggable
9683
		if ( $.ui.ddmanager ) {
9684
			$.ui.ddmanager.current = this;
9685
		}
9686
9687
		/*
9688
		 * - Position generation -
9689
		 * This block generates everything position related - it's the core of draggables.
9690
		 */
9691
9692
		//Cache the margins of the original element
9693
		this._cacheMargins();
9694
9695
		//Store the helper's css position
9696
		this.cssPosition = this.helper.css( "position" );
9697
		this.scrollParent = this.helper.scrollParent( true );
9698
		this.offsetParent = this.helper.offsetParent();
9699
		this.hasFixedAncestor = this.helper.parents().filter( function() {
9700
				return $( this ).css( "position" ) === "fixed";
9701
			} ).length > 0;
9702
9703
		//The element's absolute position on the page minus margins
9704
		this.positionAbs = this.element.offset();
9705
		this._refreshOffsets( event );
9706
9707
		//Generate the original position
9708
		this.originalPosition = this.position = this._generatePosition( event, false );
9709
		this.originalPageX = event.pageX;
9710
		this.originalPageY = event.pageY;
9711
9712
		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
9713
		( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
9714
9715
		//Set a containment if given in the options
9716
		this._setContainment();
9717
9718
		//Trigger event + callbacks
9719
		if ( this._trigger( "start", event ) === false ) {
9720
			this._clear();
9721
			return false;
9722
		}
9723
9724
		//Recache the helper size
9725
		this._cacheHelperProportions();
9726
9727
		//Prepare the droppable offsets
9728
		if ( $.ui.ddmanager && !o.dropBehaviour ) {
9729
			$.ui.ddmanager.prepareOffsets( this, event );
9730
		}
9731
9732
		// Execute the drag once - this causes the helper not to be visible before getting its
9733
		// correct position
9734
		this._mouseDrag( event, true );
9735
9736
		// If the ddmanager is used for droppables, inform the manager that dragging has started
9737
		// (see #5003)
9738
		if ( $.ui.ddmanager ) {
9739
			$.ui.ddmanager.dragStart( this, event );
9740
		}
9741
9742
		return true;
9743
	},
9744
9745
	_refreshOffsets: function( event ) {
9746
		this.offset = {
9747
			top: this.positionAbs.top - this.margins.top,
9748
			left: this.positionAbs.left - this.margins.left,
9749
			scroll: false,
9750
			parent: this._getParentOffset(),
9751
			relative: this._getRelativeOffset()
9752
		};
9753
9754
		this.offset.click = {
9755
			left: event.pageX - this.offset.left,
9756
			top: event.pageY - this.offset.top
9757
		};
9758
	},
9759
9760
	_mouseDrag: function( event, noPropagation ) {
9761
9762
		// reset any necessary cached properties (see #5009)
9763
		if ( this.hasFixedAncestor ) {
9764
			this.offset.parent = this._getParentOffset();
9765
		}
9766
9767
		//Compute the helpers position
9768
		this.position = this._generatePosition( event, true );
9769
		this.positionAbs = this._convertPositionTo( "absolute" );
9770
9771
		//Call plugins and callbacks and use the resulting position if something is returned
9772
		if ( !noPropagation ) {
9773
			var ui = this._uiHash();
9774
			if ( this._trigger( "drag", event, ui ) === false ) {
9775
				this._mouseUp( new $.Event( "mouseup", event ) );
9776
				return false;
9777
			}
9778
			this.position = ui.position;
9779
		}
9780
9781
		this.helper[ 0 ].style.left = this.position.left + "px";
9782
		this.helper[ 0 ].style.top = this.position.top + "px";
9783
9784
		if ( $.ui.ddmanager ) {
9785
			$.ui.ddmanager.drag( this, event );
9786
		}
9787
9788
		return false;
9789
	},
9790
9791
	_mouseStop: function( event ) {
9792
9793
		//If we are using droppables, inform the manager about the drop
9794
		var that = this,
9795
			dropped = false;
9796
		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
9797
			dropped = $.ui.ddmanager.drop( this, event );
9798
		}
9799
9800
		//if a drop comes from outside (a sortable)
9801
		if ( this.dropped ) {
9802
			dropped = this.dropped;
9803
			this.dropped = false;
9804
		}
9805
9806
		if ( ( this.options.revert === "invalid" && !dropped ) ||
9807
				( this.options.revert === "valid" && dropped ) ||
9808
				this.options.revert === true || ( $.isFunction( this.options.revert ) &&
9809
				this.options.revert.call( this.element, dropped ) )
9810
		) {
9811
			$( this.helper ).animate(
9812
				this.originalPosition,
9813
				parseInt( this.options.revertDuration, 10 ),
9814
				function() {
9815
					if ( that._trigger( "stop", event ) !== false ) {
9816
						that._clear();
9817
					}
9818
				}
9819
			);
9820
		} else {
9821
			if ( this._trigger( "stop", event ) !== false ) {
9822
				this._clear();
9823
			}
9824
		}
9825
9826
		return false;
9827
	},
9828
9829
	_mouseUp: function( event ) {
9830
		this._unblockFrames();
9831
9832
		// If the ddmanager is used for droppables, inform the manager that dragging has stopped
9833
		// (see #5003)
9834
		if ( $.ui.ddmanager ) {
9835
			$.ui.ddmanager.dragStop( this, event );
9836
		}
9837
9838
		// Only need to focus if the event occurred on the draggable itself, see #10527
9839
		if ( this.handleElement.is( event.target ) ) {
9840
9841
			// The interaction is over; whether or not the click resulted in a drag,
9842
			// focus the element
9843
			this.element.trigger( "focus" );
9844
		}
9845
9846
		return $.ui.mouse.prototype._mouseUp.call( this, event );
9847
	},
9848
9849
	cancel: function() {
9850
9851
		if ( this.helper.is( ".ui-draggable-dragging" ) ) {
9852
			this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
9853
		} else {
9854
			this._clear();
9855
		}
9856
9857
		return this;
9858
9859
	},
9860
9861
	_getHandle: function( event ) {
9862
		return this.options.handle ?
9863
			!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
9864
			true;
9865
	},
9866
9867
	_setHandleClassName: function() {
9868
		this.handleElement = this.options.handle ?
9869
			this.element.find( this.options.handle ) : this.element;
9870
		this._addClass( this.handleElement, "ui-draggable-handle" );
9871
	},
9872
9873
	_removeHandleClassName: function() {
9874
		this._removeClass( this.handleElement, "ui-draggable-handle" );
9875
	},
9876
9877
	_createHelper: function( event ) {
9878
9879
		var o = this.options,
9880
			helperIsFunction = $.isFunction( o.helper ),
9881
			helper = helperIsFunction ?
9882
				$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
9883
				( o.helper === "clone" ?
9884
					this.element.clone().removeAttr( "id" ) :
9885
					this.element );
9886
9887
		if ( !helper.parents( "body" ).length ) {
9888
			helper.appendTo( ( o.appendTo === "parent" ?
9889
				this.element[ 0 ].parentNode :
9890
				o.appendTo ) );
9891
		}
9892
9893
		// Http://bugs.jqueryui.com/ticket/9446
9894
		// a helper function can return the original element
9895
		// which wouldn't have been set to relative in _create
9896
		if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
9897
			this._setPositionRelative();
9898
		}
9899
9900
		if ( helper[ 0 ] !== this.element[ 0 ] &&
9901
				!( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
9902
			helper.css( "position", "absolute" );
9903
		}
9904
9905
		return helper;
9906
9907
	},
9908
9909
	_setPositionRelative: function() {
9910
		if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
9911
			this.element[ 0 ].style.position = "relative";
9912
		}
9913
	},
9914
9915 View Code Duplication
	_adjustOffsetFromHelper: function( obj ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
9916
		if ( typeof obj === "string" ) {
9917
			obj = obj.split( " " );
9918
		}
9919
		if ( $.isArray( obj ) ) {
9920
			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
9921
		}
9922
		if ( "left" in obj ) {
9923
			this.offset.click.left = obj.left + this.margins.left;
9924
		}
9925
		if ( "right" in obj ) {
9926
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
9927
		}
9928
		if ( "top" in obj ) {
9929
			this.offset.click.top = obj.top + this.margins.top;
9930
		}
9931
		if ( "bottom" in obj ) {
9932
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
9933
		}
9934
	},
9935
9936
	_isRootNode: function( element ) {
9937
		return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
9938
	},
9939
9940
	_getParentOffset: function() {
9941
9942
		//Get the offsetParent and cache its position
9943
		var po = this.offsetParent.offset(),
9944
			document = this.document[ 0 ];
9945
9946
		// This is a special case where we need to modify a offset calculated on start, since the
9947
		// following happened:
9948
		// 1. The position of the helper is absolute, so it's position is calculated based on the
9949
		// next positioned parent
9950
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
9951
		// the document, which means that the scroll is included in the initial calculation of the
9952
		// offset of the parent, and never recalculated upon drag
9953
		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
9954
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
9955
			po.left += this.scrollParent.scrollLeft();
9956
			po.top += this.scrollParent.scrollTop();
9957
		}
9958
9959
		if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
9960
			po = { top: 0, left: 0 };
9961
		}
9962
9963
		return {
9964
			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
9965
			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
9966
		};
9967
9968
	},
9969
9970
	_getRelativeOffset: function() {
9971
		if ( this.cssPosition !== "relative" ) {
9972
			return { top: 0, left: 0 };
9973
		}
9974
9975
		var p = this.element.position(),
9976
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
9977
9978
		return {
9979
			top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
9980
				( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
9981
			left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
9982
				( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
9983
		};
9984
9985
	},
9986
9987
	_cacheMargins: function() {
9988
		this.margins = {
9989
			left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
9990
			top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
9991
			right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
9992
			bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
9993
		};
9994
	},
9995
9996
	_cacheHelperProportions: function() {
9997
		this.helperProportions = {
9998
			width: this.helper.outerWidth(),
9999
			height: this.helper.outerHeight()
10000
		};
10001
	},
10002
10003
	_setContainment: function() {
10004
10005
		var isUserScrollable, c, ce,
10006
			o = this.options,
10007
			document = this.document[ 0 ];
10008
10009
		this.relativeContainer = null;
10010
10011
		if ( !o.containment ) {
10012
			this.containment = null;
10013
			return;
10014
		}
10015
10016
		if ( o.containment === "window" ) {
10017
			this.containment = [
10018
				$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
10019
				$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
10020
				$( window ).scrollLeft() + $( window ).width() -
10021
					this.helperProportions.width - this.margins.left,
10022
				$( window ).scrollTop() +
10023
					( $( window ).height() || document.body.parentNode.scrollHeight ) -
10024
					this.helperProportions.height - this.margins.top
10025
			];
10026
			return;
10027
		}
10028
10029
		if ( o.containment === "document" ) {
10030
			this.containment = [
10031
				0,
10032
				0,
10033
				$( document ).width() - this.helperProportions.width - this.margins.left,
10034
				( $( document ).height() || document.body.parentNode.scrollHeight ) -
10035
					this.helperProportions.height - this.margins.top
10036
			];
10037
			return;
10038
		}
10039
10040
		if ( o.containment.constructor === Array ) {
10041
			this.containment = o.containment;
10042
			return;
10043
		}
10044
10045
		if ( o.containment === "parent" ) {
10046
			o.containment = this.helper[ 0 ].parentNode;
10047
		}
10048
10049
		c = $( o.containment );
10050
		ce = c[ 0 ];
10051
10052
		if ( !ce ) {
10053
			return;
10054
		}
10055
10056
		isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
10057
10058
		this.containment = [
10059
			( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
10060
				( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
10061
			( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
10062
				( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
10063
			( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
10064
				( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
10065
				( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
10066
				this.helperProportions.width -
10067
				this.margins.left -
10068
				this.margins.right,
10069
			( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
10070
				( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
10071
				( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
10072
				this.helperProportions.height -
10073
				this.margins.top -
10074
				this.margins.bottom
10075
		];
10076
		this.relativeContainer = c;
10077
	},
10078
10079
	_convertPositionTo: function( d, pos ) {
10080
10081
		if ( !pos ) {
10082
			pos = this.position;
10083
		}
10084
10085
		var mod = d === "absolute" ? 1 : -1,
10086
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
10087
10088
		return {
10089
			top: (
10090
10091
				// The absolute mouse position
10092
				pos.top	+
10093
10094
				// Only for relative positioned nodes: Relative offset from element to offset parent
10095
				this.offset.relative.top * mod +
10096
10097
				// The offsetParent's offset without borders (offset + border)
10098
				this.offset.parent.top * mod -
10099
				( ( this.cssPosition === "fixed" ?
10100
					-this.offset.scroll.top :
10101
					( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
10102
			),
10103
			left: (
10104
10105
				// The absolute mouse position
10106
				pos.left +
10107
10108
				// Only for relative positioned nodes: Relative offset from element to offset parent
10109
				this.offset.relative.left * mod +
10110
10111
				// The offsetParent's offset without borders (offset + border)
10112
				this.offset.parent.left * mod	-
10113
				( ( this.cssPosition === "fixed" ?
10114
					-this.offset.scroll.left :
10115
					( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
10116
			)
10117
		};
10118
10119
	},
10120
10121
	_generatePosition: function( event, constrainPosition ) {
10122
10123
		var containment, co, top, left,
10124
			o = this.options,
10125
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
10126
			pageX = event.pageX,
10127
			pageY = event.pageY;
10128
10129
		// Cache the scroll
10130
		if ( !scrollIsRootNode || !this.offset.scroll ) {
10131
			this.offset.scroll = {
10132
				top: this.scrollParent.scrollTop(),
10133
				left: this.scrollParent.scrollLeft()
10134
			};
10135
		}
10136
10137
		/*
10138
		 * - Position constraining -
10139
		 * Constrain the position to a mix of grid, containment.
10140
		 */
10141
10142
		// If we are not dragging yet, we won't check for options
10143
		if ( constrainPosition ) {
10144
			if ( this.containment ) {
10145
				if ( this.relativeContainer ) {
10146
					co = this.relativeContainer.offset();
10147
					containment = [
10148
						this.containment[ 0 ] + co.left,
10149
						this.containment[ 1 ] + co.top,
10150
						this.containment[ 2 ] + co.left,
10151
						this.containment[ 3 ] + co.top
10152
					];
10153
				} else {
10154
					containment = this.containment;
10155
				}
10156
10157
				if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
10158
					pageX = containment[ 0 ] + this.offset.click.left;
10159
				}
10160
				if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
10161
					pageY = containment[ 1 ] + this.offset.click.top;
10162
				}
10163
				if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
10164
					pageX = containment[ 2 ] + this.offset.click.left;
10165
				}
10166
				if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
10167
					pageY = containment[ 3 ] + this.offset.click.top;
10168
				}
10169
			}
10170
10171 View Code Duplication
			if ( o.grid ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
10172
10173
				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid
10174
				// argument errors in IE (see ticket #6950)
10175
				top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
10176
					this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
10177
				pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
10178
					top - this.offset.click.top > containment[ 3 ] ) ?
10179
						top :
10180
						( ( top - this.offset.click.top >= containment[ 1 ] ) ?
10181
							top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
10182
10183
				left = o.grid[ 0 ] ? this.originalPageX +
10184
					Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
10185
					this.originalPageX;
10186
				pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
10187
					left - this.offset.click.left > containment[ 2 ] ) ?
10188
						left :
10189
						( ( left - this.offset.click.left >= containment[ 0 ] ) ?
10190
							left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
10191
			}
10192
10193
			if ( o.axis === "y" ) {
10194
				pageX = this.originalPageX;
10195
			}
10196
10197
			if ( o.axis === "x" ) {
10198
				pageY = this.originalPageY;
10199
			}
10200
		}
10201
10202
		return {
10203
			top: (
10204
10205
				// The absolute mouse position
10206
				pageY -
10207
10208
				// Click offset (relative to the element)
10209
				this.offset.click.top -
10210
10211
				// Only for relative positioned nodes: Relative offset from element to offset parent
10212
				this.offset.relative.top -
10213
10214
				// The offsetParent's offset without borders (offset + border)
10215
				this.offset.parent.top +
10216
				( this.cssPosition === "fixed" ?
10217
					-this.offset.scroll.top :
10218
					( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
10219
			),
10220
			left: (
10221
10222
				// The absolute mouse position
10223
				pageX -
10224
10225
				// Click offset (relative to the element)
10226
				this.offset.click.left -
10227
10228
				// Only for relative positioned nodes: Relative offset from element to offset parent
10229
				this.offset.relative.left -
10230
10231
				// The offsetParent's offset without borders (offset + border)
10232
				this.offset.parent.left +
10233
				( this.cssPosition === "fixed" ?
10234
					-this.offset.scroll.left :
10235
					( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
10236
			)
10237
		};
10238
10239
	},
10240
10241
	_clear: function() {
10242
		this._removeClass( this.helper, "ui-draggable-dragging" );
10243
		if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
10244
			this.helper.remove();
10245
		}
10246
		this.helper = null;
10247
		this.cancelHelperRemoval = false;
10248
		if ( this.destroyOnClear ) {
10249
			this.destroy();
10250
		}
10251
	},
10252
10253
	// From now on bulk stuff - mainly helpers
10254
10255
	_trigger: function( type, event, ui ) {
10256
		ui = ui || this._uiHash();
10257
		$.ui.plugin.call( this, type, [ event, ui, this ], true );
10258
10259
		// Absolute position and offset (see #6884 ) have to be recalculated after plugins
10260
		if ( /^(drag|start|stop)/.test( type ) ) {
10261
			this.positionAbs = this._convertPositionTo( "absolute" );
10262
			ui.offset = this.positionAbs;
10263
		}
10264
		return $.Widget.prototype._trigger.call( this, type, event, ui );
10265
	},
10266
10267
	plugins: {},
10268
10269
	_uiHash: function() {
10270
		return {
10271
			helper: this.helper,
10272
			position: this.position,
10273
			originalPosition: this.originalPosition,
10274
			offset: this.positionAbs
10275
		};
10276
	}
10277
10278
} );
10279
10280
$.ui.plugin.add( "draggable", "connectToSortable", {
10281
	start: function( event, ui, draggable ) {
10282
		var uiSortable = $.extend( {}, ui, {
10283
			item: draggable.element
10284
		} );
10285
10286
		draggable.sortables = [];
10287
		$( draggable.options.connectToSortable ).each( function() {
10288
			var sortable = $( this ).sortable( "instance" );
10289
10290
			if ( sortable && !sortable.options.disabled ) {
10291
				draggable.sortables.push( sortable );
10292
10293
				// RefreshPositions is called at drag start to refresh the containerCache
10294
				// which is used in drag. This ensures it's initialized and synchronized
10295
				// with any changes that might have happened on the page since initialization.
10296
				sortable.refreshPositions();
10297
				sortable._trigger( "activate", event, uiSortable );
10298
			}
10299
		} );
10300
	},
10301
	stop: function( event, ui, draggable ) {
10302
		var uiSortable = $.extend( {}, ui, {
10303
			item: draggable.element
10304
		} );
10305
10306
		draggable.cancelHelperRemoval = false;
10307
10308
		$.each( draggable.sortables, function() {
10309
			var sortable = this;
10310
10311
			if ( sortable.isOver ) {
10312
				sortable.isOver = 0;
10313
10314
				// Allow this sortable to handle removing the helper
10315
				draggable.cancelHelperRemoval = true;
10316
				sortable.cancelHelperRemoval = false;
10317
10318
				// Use _storedCSS To restore properties in the sortable,
10319
				// as this also handles revert (#9675) since the draggable
10320
				// may have modified them in unexpected ways (#8809)
10321
				sortable._storedCSS = {
10322
					position: sortable.placeholder.css( "position" ),
10323
					top: sortable.placeholder.css( "top" ),
10324
					left: sortable.placeholder.css( "left" )
10325
				};
10326
10327
				sortable._mouseStop( event );
10328
10329
				// Once drag has ended, the sortable should return to using
10330
				// its original helper, not the shared helper from draggable
10331
				sortable.options.helper = sortable.options._helper;
10332
			} else {
10333
10334
				// Prevent this Sortable from removing the helper.
10335
				// However, don't set the draggable to remove the helper
10336
				// either as another connected Sortable may yet handle the removal.
10337
				sortable.cancelHelperRemoval = true;
10338
10339
				sortable._trigger( "deactivate", event, uiSortable );
10340
			}
10341
		} );
10342
	},
10343
	drag: function( event, ui, draggable ) {
10344
		$.each( draggable.sortables, function() {
10345
			var innermostIntersecting = false,
10346
				sortable = this;
10347
10348
			// Copy over variables that sortable's _intersectsWith uses
10349
			sortable.positionAbs = draggable.positionAbs;
10350
			sortable.helperProportions = draggable.helperProportions;
10351
			sortable.offset.click = draggable.offset.click;
10352
10353
			if ( sortable._intersectsWith( sortable.containerCache ) ) {
10354
				innermostIntersecting = true;
10355
10356
				$.each( draggable.sortables, function() {
10357
10358
					// Copy over variables that sortable's _intersectsWith uses
10359
					this.positionAbs = draggable.positionAbs;
10360
					this.helperProportions = draggable.helperProportions;
10361
					this.offset.click = draggable.offset.click;
10362
10363
					if ( this !== sortable &&
10364
							this._intersectsWith( this.containerCache ) &&
10365
							$.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
10366
						innermostIntersecting = false;
10367
					}
10368
10369
					return innermostIntersecting;
10370
				} );
10371
			}
10372
10373
			if ( innermostIntersecting ) {
10374
10375
				// If it intersects, we use a little isOver variable and set it once,
10376
				// so that the move-in stuff gets fired only once.
10377
				if ( !sortable.isOver ) {
10378
					sortable.isOver = 1;
10379
10380
					// Store draggable's parent in case we need to reappend to it later.
10381
					draggable._parent = ui.helper.parent();
10382
10383
					sortable.currentItem = ui.helper
10384
						.appendTo( sortable.element )
10385
						.data( "ui-sortable-item", true );
10386
10387
					// Store helper option to later restore it
10388
					sortable.options._helper = sortable.options.helper;
10389
10390
					sortable.options.helper = function() {
10391
						return ui.helper[ 0 ];
10392
					};
10393
10394
					// Fire the start events of the sortable with our passed browser event,
10395
					// and our own helper (so it doesn't create a new one)
10396
					event.target = sortable.currentItem[ 0 ];
10397
					sortable._mouseCapture( event, true );
10398
					sortable._mouseStart( event, true, true );
10399
10400
					// Because the browser event is way off the new appended portlet,
10401
					// modify necessary variables to reflect the changes
10402
					sortable.offset.click.top = draggable.offset.click.top;
10403
					sortable.offset.click.left = draggable.offset.click.left;
10404
					sortable.offset.parent.left -= draggable.offset.parent.left -
10405
						sortable.offset.parent.left;
10406
					sortable.offset.parent.top -= draggable.offset.parent.top -
10407
						sortable.offset.parent.top;
10408
10409
					draggable._trigger( "toSortable", event );
10410
10411
					// Inform draggable that the helper is in a valid drop zone,
10412
					// used solely in the revert option to handle "valid/invalid".
10413
					draggable.dropped = sortable.element;
10414
10415
					// Need to refreshPositions of all sortables in the case that
10416
					// adding to one sortable changes the location of the other sortables (#9675)
10417
					$.each( draggable.sortables, function() {
10418
						this.refreshPositions();
10419
					} );
10420
10421
					// Hack so receive/update callbacks work (mostly)
10422
					draggable.currentItem = draggable.element;
10423
					sortable.fromOutside = draggable;
10424
				}
10425
10426
				if ( sortable.currentItem ) {
10427
					sortable._mouseDrag( event );
10428
10429
					// Copy the sortable's position because the draggable's can potentially reflect
10430
					// a relative position, while sortable is always absolute, which the dragged
10431
					// element has now become. (#8809)
10432
					ui.position = sortable.position;
10433
				}
10434
			} else {
10435
10436
				// If it doesn't intersect with the sortable, and it intersected before,
10437
				// we fake the drag stop of the sortable, but make sure it doesn't remove
10438
				// the helper by using cancelHelperRemoval.
10439
				if ( sortable.isOver ) {
10440
10441
					sortable.isOver = 0;
10442
					sortable.cancelHelperRemoval = true;
10443
10444
					// Calling sortable's mouseStop would trigger a revert,
10445
					// so revert must be temporarily false until after mouseStop is called.
10446
					sortable.options._revert = sortable.options.revert;
10447
					sortable.options.revert = false;
10448
10449
					sortable._trigger( "out", event, sortable._uiHash( sortable ) );
10450
					sortable._mouseStop( event, true );
10451
10452
					// Restore sortable behaviors that were modfied
10453
					// when the draggable entered the sortable area (#9481)
10454
					sortable.options.revert = sortable.options._revert;
10455
					sortable.options.helper = sortable.options._helper;
10456
10457
					if ( sortable.placeholder ) {
10458
						sortable.placeholder.remove();
10459
					}
10460
10461
					// Restore and recalculate the draggable's offset considering the sortable
10462
					// may have modified them in unexpected ways. (#8809, #10669)
10463
					ui.helper.appendTo( draggable._parent );
10464
					draggable._refreshOffsets( event );
10465
					ui.position = draggable._generatePosition( event, true );
10466
10467
					draggable._trigger( "fromSortable", event );
10468
10469
					// Inform draggable that the helper is no longer in a valid drop zone
10470
					draggable.dropped = false;
10471
10472
					// Need to refreshPositions of all sortables just in case removing
10473
					// from one sortable changes the location of other sortables (#9675)
10474
					$.each( draggable.sortables, function() {
10475
						this.refreshPositions();
10476
					} );
10477
				}
10478
			}
10479
		} );
10480
	}
10481
} );
10482
10483
$.ui.plugin.add( "draggable", "cursor", {
10484
	start: function( event, ui, instance ) {
10485
		var t = $( "body" ),
10486
			o = instance.options;
10487
10488
		if ( t.css( "cursor" ) ) {
10489
			o._cursor = t.css( "cursor" );
10490
		}
10491
		t.css( "cursor", o.cursor );
10492
	},
10493
	stop: function( event, ui, instance ) {
10494
		var o = instance.options;
10495
		if ( o._cursor ) {
10496
			$( "body" ).css( "cursor", o._cursor );
10497
		}
10498
	}
10499
} );
10500
10501
$.ui.plugin.add( "draggable", "opacity", {
10502
	start: function( event, ui, instance ) {
10503
		var t = $( ui.helper ),
10504
			o = instance.options;
10505
		if ( t.css( "opacity" ) ) {
10506
			o._opacity = t.css( "opacity" );
10507
		}
10508
		t.css( "opacity", o.opacity );
10509
	},
10510
	stop: function( event, ui, instance ) {
10511
		var o = instance.options;
10512
		if ( o._opacity ) {
10513
			$( ui.helper ).css( "opacity", o._opacity );
10514
		}
10515
	}
10516
} );
10517
10518
$.ui.plugin.add( "draggable", "scroll", {
10519
	start: function( event, ui, i ) {
10520
		if ( !i.scrollParentNotHidden ) {
10521
			i.scrollParentNotHidden = i.helper.scrollParent( false );
10522
		}
10523
10524
		if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
10525
				i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
10526
			i.overflowOffset = i.scrollParentNotHidden.offset();
10527
		}
10528
	},
10529
	drag: function( event, ui, i  ) {
10530
10531
		var o = i.options,
10532
			scrolled = false,
10533
			scrollParent = i.scrollParentNotHidden[ 0 ],
10534
			document = i.document[ 0 ];
10535
10536
		if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
10537
			if ( !o.axis || o.axis !== "x" ) {
10538
				if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
10539
						o.scrollSensitivity ) {
10540
					scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
10541
				} else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
10542
					scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
10543
				}
10544
			}
10545
10546
			if ( !o.axis || o.axis !== "y" ) {
10547
				if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
10548
						o.scrollSensitivity ) {
10549
					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
10550
				} else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
10551
					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
10552
				}
10553
			}
10554
10555
		} else {
10556
10557
			if ( !o.axis || o.axis !== "x" ) {
10558
				if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
10559
					scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
10560
				} else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
10561
						o.scrollSensitivity ) {
10562
					scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
10563
				}
10564
			}
10565
10566
			if ( !o.axis || o.axis !== "y" ) {
10567
				if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
10568
					scrolled = $( document ).scrollLeft(
10569
						$( document ).scrollLeft() - o.scrollSpeed
10570
					);
10571
				} else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
10572
						o.scrollSensitivity ) {
10573
					scrolled = $( document ).scrollLeft(
10574
						$( document ).scrollLeft() + o.scrollSpeed
10575
					);
10576
				}
10577
			}
10578
10579
		}
10580
10581
		if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
10582
			$.ui.ddmanager.prepareOffsets( i, event );
10583
		}
10584
10585
	}
10586
} );
10587
10588
$.ui.plugin.add( "draggable", "snap", {
10589
	start: function( event, ui, i ) {
10590
10591
		var o = i.options;
10592
10593
		i.snapElements = [];
10594
10595
		$( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
10596
			.each( function() {
10597
				var $t = $( this ),
10598
					$o = $t.offset();
10599
				if ( this !== i.element[ 0 ] ) {
10600
					i.snapElements.push( {
10601
						item: this,
10602
						width: $t.outerWidth(), height: $t.outerHeight(),
10603
						top: $o.top, left: $o.left
10604
					} );
10605
				}
10606
			} );
10607
10608
	},
10609
	drag: function( event, ui, inst ) {
10610
10611
		var ts, bs, ls, rs, l, r, t, b, i, first,
10612
			o = inst.options,
10613
			d = o.snapTolerance,
10614
			x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
10615
			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
10616
10617
		for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
10618
10619
			l = inst.snapElements[ i ].left - inst.margins.left;
10620
			r = l + inst.snapElements[ i ].width;
10621
			t = inst.snapElements[ i ].top - inst.margins.top;
10622
			b = t + inst.snapElements[ i ].height;
10623
10624
			if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
10625
					!$.contains( inst.snapElements[ i ].item.ownerDocument,
10626
					inst.snapElements[ i ].item ) ) {
10627
				if ( inst.snapElements[ i ].snapping ) {
10628
					( inst.options.snap.release &&
10629
						inst.options.snap.release.call(
10630
							inst.element,
10631
							event,
10632
							$.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
10633
						) );
10634
				}
10635
				inst.snapElements[ i ].snapping = false;
10636
				continue;
10637
			}
10638
10639 View Code Duplication
			if ( o.snapMode !== "inner" ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
10640
				ts = Math.abs( t - y2 ) <= d;
10641
				bs = Math.abs( b - y1 ) <= d;
10642
				ls = Math.abs( l - x2 ) <= d;
10643
				rs = Math.abs( r - x1 ) <= d;
10644
				if ( ts ) {
10645
					ui.position.top = inst._convertPositionTo( "relative", {
10646
						top: t - inst.helperProportions.height,
10647
						left: 0
10648
					} ).top;
10649
				}
10650
				if ( bs ) {
10651
					ui.position.top = inst._convertPositionTo( "relative", {
10652
						top: b,
10653
						left: 0
10654
					} ).top;
10655
				}
10656
				if ( ls ) {
10657
					ui.position.left = inst._convertPositionTo( "relative", {
10658
						top: 0,
10659
						left: l - inst.helperProportions.width
10660
					} ).left;
10661
				}
10662
				if ( rs ) {
10663
					ui.position.left = inst._convertPositionTo( "relative", {
10664
						top: 0,
10665
						left: r
10666
					} ).left;
10667
				}
10668
			}
10669
10670
			first = ( ts || bs || ls || rs );
10671
10672 View Code Duplication
			if ( o.snapMode !== "outer" ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
10673
				ts = Math.abs( t - y1 ) <= d;
10674
				bs = Math.abs( b - y2 ) <= d;
10675
				ls = Math.abs( l - x1 ) <= d;
10676
				rs = Math.abs( r - x2 ) <= d;
10677
				if ( ts ) {
10678
					ui.position.top = inst._convertPositionTo( "relative", {
10679
						top: t,
10680
						left: 0
10681
					} ).top;
10682
				}
10683
				if ( bs ) {
10684
					ui.position.top = inst._convertPositionTo( "relative", {
10685
						top: b - inst.helperProportions.height,
10686
						left: 0
10687
					} ).top;
10688
				}
10689
				if ( ls ) {
10690
					ui.position.left = inst._convertPositionTo( "relative", {
10691
						top: 0,
10692
						left: l
10693
					} ).left;
10694
				}
10695
				if ( rs ) {
10696
					ui.position.left = inst._convertPositionTo( "relative", {
10697
						top: 0,
10698
						left: r - inst.helperProportions.width
10699
					} ).left;
10700
				}
10701
			}
10702
10703
			if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
10704
				( inst.options.snap.snap &&
10705
					inst.options.snap.snap.call(
10706
						inst.element,
10707
						event,
10708
						$.extend( inst._uiHash(), {
10709
							snapItem: inst.snapElements[ i ].item
10710
						} ) ) );
10711
			}
10712
			inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
10713
10714
		}
10715
10716
	}
10717
} );
10718
10719
$.ui.plugin.add( "draggable", "stack", {
10720
	start: function( event, ui, instance ) {
10721
		var min,
10722
			o = instance.options,
10723
			group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
10724
				return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
10725
					( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
10726
			} );
10727
10728
		if ( !group.length ) { return; }
10729
10730
		min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
10731
		$( group ).each( function( i ) {
10732
			$( this ).css( "zIndex", min + i );
10733
		} );
10734
		this.css( "zIndex", ( min + group.length ) );
10735
	}
10736
} );
10737
10738
$.ui.plugin.add( "draggable", "zIndex", {
10739
	start: function( event, ui, instance ) {
10740
		var t = $( ui.helper ),
10741
			o = instance.options;
10742
10743
		if ( t.css( "zIndex" ) ) {
10744
			o._zIndex = t.css( "zIndex" );
10745
		}
10746
		t.css( "zIndex", o.zIndex );
10747
	},
10748
	stop: function( event, ui, instance ) {
10749
		var o = instance.options;
10750
10751
		if ( o._zIndex ) {
10752
			$( ui.helper ).css( "zIndex", o._zIndex );
10753
		}
10754
	}
10755
} );
10756
10757
var widgetsDraggable = $.ui.draggable;
0 ignored issues
show
Unused Code introduced by
The variable widgetsDraggable seems to be never used. Consider removing it.
Loading history...
10758
10759
10760
/*!
10761
 * jQuery UI Resizable 1.12.1
10762
 * http://jqueryui.com
10763
 *
10764
 * Copyright jQuery Foundation and other contributors
10765
 * Released under the MIT license.
10766
 * http://jquery.org/license
10767
 */
10768
10769
//>>label: Resizable
10770
//>>group: Interactions
10771
//>>description: Enables resize functionality for any element.
10772
//>>docs: http://api.jqueryui.com/resizable/
10773
//>>demos: http://jqueryui.com/resizable/
10774
//>>css.structure: ../../themes/base/core.css
10775
//>>css.structure: ../../themes/base/resizable.css
10776
//>>css.theme: ../../themes/base/theme.css
10777
10778
10779
10780
$.widget( "ui.resizable", $.ui.mouse, {
10781
	version: "1.12.1",
10782
	widgetEventPrefix: "resize",
10783
	options: {
10784
		alsoResize: false,
10785
		animate: false,
10786
		animateDuration: "slow",
10787
		animateEasing: "swing",
10788
		aspectRatio: false,
10789
		autoHide: false,
10790
		classes: {
10791
			"ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
10792
		},
10793
		containment: false,
10794
		ghost: false,
10795
		grid: false,
10796
		handles: "e,s,se",
10797
		helper: false,
10798
		maxHeight: null,
10799
		maxWidth: null,
10800
		minHeight: 10,
10801
		minWidth: 10,
10802
10803
		// See #7960
10804
		zIndex: 90,
10805
10806
		// Callbacks
10807
		resize: null,
10808
		start: null,
10809
		stop: null
10810
	},
10811
10812
	_num: function( value ) {
10813
		return parseFloat( value ) || 0;
10814
	},
10815
10816
	_isNumber: function( value ) {
10817
		return !isNaN( parseFloat( value ) );
10818
	},
10819
10820
	_hasScroll: function( el, a ) {
10821
10822
		if ( $( el ).css( "overflow" ) === "hidden" ) {
10823
			return false;
10824
		}
10825
10826
		var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
10827
			has = false;
0 ignored issues
show
Unused Code introduced by
The assignment to variable has seems to be never used. Consider removing it.
Loading history...
10828
10829
		if ( el[ scroll ] > 0 ) {
10830
			return true;
10831
		}
10832
10833
		// TODO: determine which cases actually cause this to happen
10834
		// if the element doesn't have the scroll set, see if it's possible to
10835
		// set the scroll
10836
		el[ scroll ] = 1;
10837
		has = ( el[ scroll ] > 0 );
10838
		el[ scroll ] = 0;
10839
		return has;
10840
	},
10841
10842
	_create: function() {
10843
10844
		var margins,
10845
			o = this.options,
10846
			that = this;
10847
		this._addClass( "ui-resizable" );
10848
10849
		$.extend( this, {
10850
			_aspectRatio: !!( o.aspectRatio ),
10851
			aspectRatio: o.aspectRatio,
10852
			originalElement: this.element,
10853
			_proportionallyResizeElements: [],
10854
			_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
10855
		} );
10856
10857
		// Wrap the element if it cannot hold child nodes
10858
		if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
10859
10860
			this.element.wrap(
10861
				$( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
10862
					position: this.element.css( "position" ),
10863
					width: this.element.outerWidth(),
10864
					height: this.element.outerHeight(),
10865
					top: this.element.css( "top" ),
10866
					left: this.element.css( "left" )
10867
				} )
10868
			);
10869
10870
			this.element = this.element.parent().data(
10871
				"ui-resizable", this.element.resizable( "instance" )
10872
			);
10873
10874
			this.elementIsWrapper = true;
10875
10876
			margins = {
10877
				marginTop: this.originalElement.css( "marginTop" ),
10878
				marginRight: this.originalElement.css( "marginRight" ),
10879
				marginBottom: this.originalElement.css( "marginBottom" ),
10880
				marginLeft: this.originalElement.css( "marginLeft" )
10881
			};
10882
10883
			this.element.css( margins );
10884
			this.originalElement.css( "margin", 0 );
10885
10886
			// support: Safari
10887
			// Prevent Safari textarea resize
10888
			this.originalResizeStyle = this.originalElement.css( "resize" );
10889
			this.originalElement.css( "resize", "none" );
10890
10891
			this._proportionallyResizeElements.push( this.originalElement.css( {
10892
				position: "static",
10893
				zoom: 1,
10894
				display: "block"
10895
			} ) );
10896
10897
			// Support: IE9
10898
			// avoid IE jump (hard set the margin)
10899
			this.originalElement.css( margins );
10900
10901
			this._proportionallyResize();
10902
		}
10903
10904
		this._setupHandles();
10905
10906
		if ( o.autoHide ) {
10907
			$( this.element )
10908
				.on( "mouseenter", function() {
10909
					if ( o.disabled ) {
10910
						return;
10911
					}
10912
					that._removeClass( "ui-resizable-autohide" );
10913
					that._handles.show();
10914
				} )
10915
				.on( "mouseleave", function() {
10916
					if ( o.disabled ) {
10917
						return;
10918
					}
10919
					if ( !that.resizing ) {
10920
						that._addClass( "ui-resizable-autohide" );
10921
						that._handles.hide();
10922
					}
10923
				} );
10924
		}
10925
10926
		this._mouseInit();
10927
	},
10928
10929
	_destroy: function() {
10930
10931
		this._mouseDestroy();
10932
10933
		var wrapper,
10934
			_destroy = function( exp ) {
10935
				$( exp )
10936
					.removeData( "resizable" )
10937
					.removeData( "ui-resizable" )
10938
					.off( ".resizable" )
10939
					.find( ".ui-resizable-handle" )
10940
						.remove();
10941
			};
10942
10943
		// TODO: Unwrap at same DOM position
10944
		if ( this.elementIsWrapper ) {
10945
			_destroy( this.element );
10946
			wrapper = this.element;
10947
			this.originalElement.css( {
10948
				position: wrapper.css( "position" ),
10949
				width: wrapper.outerWidth(),
10950
				height: wrapper.outerHeight(),
10951
				top: wrapper.css( "top" ),
10952
				left: wrapper.css( "left" )
10953
			} ).insertAfter( wrapper );
10954
			wrapper.remove();
10955
		}
10956
10957
		this.originalElement.css( "resize", this.originalResizeStyle );
10958
		_destroy( this.originalElement );
10959
10960
		return this;
10961
	},
10962
10963
	_setOption: function( key, value ) {
10964
		this._super( key, value );
10965
10966
		switch ( key ) {
10967
		case "handles":
10968
			this._removeHandles();
10969
			this._setupHandles();
10970
			break;
10971
		default:
10972
			break;
10973
		}
10974
	},
10975
10976
	_setupHandles: function() {
10977
		var o = this.options, handle, i, n, hname, axis, that = this;
10978
		this.handles = o.handles ||
10979
			( !$( ".ui-resizable-handle", this.element ).length ?
10980
				"e,s,se" : {
10981
					n: ".ui-resizable-n",
10982
					e: ".ui-resizable-e",
10983
					s: ".ui-resizable-s",
10984
					w: ".ui-resizable-w",
10985
					se: ".ui-resizable-se",
10986
					sw: ".ui-resizable-sw",
10987
					ne: ".ui-resizable-ne",
10988
					nw: ".ui-resizable-nw"
10989
				} );
10990
10991
		this._handles = $();
10992
		if ( this.handles.constructor === String ) {
10993
10994
			if ( this.handles === "all" ) {
10995
				this.handles = "n,e,s,w,se,sw,ne,nw";
10996
			}
10997
10998
			n = this.handles.split( "," );
10999
			this.handles = {};
11000
11001
			for ( i = 0; i < n.length; i++ ) {
11002
11003
				handle = $.trim( n[ i ] );
11004
				hname = "ui-resizable-" + handle;
11005
				axis = $( "<div>" );
11006
				this._addClass( axis, "ui-resizable-handle " + hname );
11007
11008
				axis.css( { zIndex: o.zIndex } );
11009
11010
				this.handles[ handle ] = ".ui-resizable-" + handle;
11011
				this.element.append( axis );
11012
			}
11013
11014
		}
11015
11016
		this._renderAxis = function( target ) {
11017
11018
			var i, axis, padPos, padWrapper;
11019
11020
			target = target || this.element;
11021
11022
			for ( i in this.handles ) {
11023
11024
				if ( this.handles[ i ].constructor === String ) {
11025
					this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
11026
				} else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
11027
					this.handles[ i ] = $( this.handles[ i ] );
11028
					this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
11029
				}
11030
11031
				if ( this.elementIsWrapper &&
11032
						this.originalElement[ 0 ]
11033
							.nodeName
11034
							.match( /^(textarea|input|select|button)$/i ) ) {
11035
					axis = $( this.handles[ i ], this.element );
11036
11037
					padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
11038
						axis.outerHeight() :
11039
						axis.outerWidth();
11040
11041
					padPos = [ "padding",
11042
						/ne|nw|n/.test( i ) ? "Top" :
11043
						/se|sw|s/.test( i ) ? "Bottom" :
11044
						/^e$/.test( i ) ? "Right" : "Left" ].join( "" );
11045
11046
					target.css( padPos, padWrapper );
11047
11048
					this._proportionallyResize();
11049
				}
11050
11051
				this._handles = this._handles.add( this.handles[ i ] );
11052
			}
11053
		};
11054
11055
		// TODO: make renderAxis a prototype function
11056
		this._renderAxis( this.element );
11057
11058
		this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
11059
		this._handles.disableSelection();
11060
11061
		this._handles.on( "mouseover", function() {
11062
			if ( !that.resizing ) {
11063
				if ( this.className ) {
11064
					axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
11065
				}
11066
				that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
0 ignored issues
show
Bug introduced by
The variable axis seems to not be initialized for all possible execution paths.
Loading history...
11067
			}
11068
		} );
11069
11070
		if ( o.autoHide ) {
11071
			this._handles.hide();
11072
			this._addClass( "ui-resizable-autohide" );
11073
		}
11074
	},
11075
11076
	_removeHandles: function() {
11077
		this._handles.remove();
11078
	},
11079
11080
	_mouseCapture: function( event ) {
11081
		var i, handle,
11082
			capture = false;
11083
11084
		for ( i in this.handles ) {
11085
			handle = $( this.handles[ i ] )[ 0 ];
11086
			if ( handle === event.target || $.contains( handle, event.target ) ) {
11087
				capture = true;
11088
			}
11089
		}
11090
11091
		return !this.options.disabled && capture;
11092
	},
11093
11094
	_mouseStart: function( event ) {
11095
11096
		var curleft, curtop, cursor,
11097
			o = this.options,
11098
			el = this.element;
11099
11100
		this.resizing = true;
11101
11102
		this._renderProxy();
11103
11104
		curleft = this._num( this.helper.css( "left" ) );
11105
		curtop = this._num( this.helper.css( "top" ) );
11106
11107
		if ( o.containment ) {
11108
			curleft += $( o.containment ).scrollLeft() || 0;
11109
			curtop += $( o.containment ).scrollTop() || 0;
11110
		}
11111
11112
		this.offset = this.helper.offset();
11113
		this.position = { left: curleft, top: curtop };
11114
11115
		this.size = this._helper ? {
11116
				width: this.helper.width(),
11117
				height: this.helper.height()
11118
			} : {
11119
				width: el.width(),
11120
				height: el.height()
11121
			};
11122
11123
		this.originalSize = this._helper ? {
11124
				width: el.outerWidth(),
11125
				height: el.outerHeight()
11126
			} : {
11127
				width: el.width(),
11128
				height: el.height()
11129
			};
11130
11131
		this.sizeDiff = {
11132
			width: el.outerWidth() - el.width(),
11133
			height: el.outerHeight() - el.height()
11134
		};
11135
11136
		this.originalPosition = { left: curleft, top: curtop };
11137
		this.originalMousePosition = { left: event.pageX, top: event.pageY };
11138
11139
		this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
11140
			o.aspectRatio :
11141
			( ( this.originalSize.width / this.originalSize.height ) || 1 );
11142
11143
		cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
11144
		$( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
11145
11146
		this._addClass( "ui-resizable-resizing" );
11147
		this._propagate( "start", event );
11148
		return true;
11149
	},
11150
11151
	_mouseDrag: function( event ) {
11152
11153
		var data, props,
11154
			smp = this.originalMousePosition,
11155
			a = this.axis,
11156
			dx = ( event.pageX - smp.left ) || 0,
11157
			dy = ( event.pageY - smp.top ) || 0,
11158
			trigger = this._change[ a ];
11159
11160
		this._updatePrevProperties();
11161
11162
		if ( !trigger ) {
11163
			return false;
11164
		}
11165
11166
		data = trigger.apply( this, [ event, dx, dy ] );
11167
11168
		this._updateVirtualBoundaries( event.shiftKey );
11169
		if ( this._aspectRatio || event.shiftKey ) {
11170
			data = this._updateRatio( data, event );
11171
		}
11172
11173
		data = this._respectSize( data, event );
11174
11175
		this._updateCache( data );
11176
11177
		this._propagate( "resize", event );
11178
11179
		props = this._applyChanges();
11180
11181
		if ( !this._helper && this._proportionallyResizeElements.length ) {
11182
			this._proportionallyResize();
11183
		}
11184
11185
		if ( !$.isEmptyObject( props ) ) {
11186
			this._updatePrevProperties();
11187
			this._trigger( "resize", event, this.ui() );
11188
			this._applyChanges();
11189
		}
11190
11191
		return false;
11192
	},
11193
11194
	_mouseStop: function( event ) {
11195
11196
		this.resizing = false;
11197
		var pr, ista, soffseth, soffsetw, s, left, top,
11198
			o = this.options, that = this;
11199
11200
		if ( this._helper ) {
11201
11202
			pr = this._proportionallyResizeElements;
11203
			ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
11204
			soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
11205
			soffsetw = ista ? 0 : that.sizeDiff.width;
11206
11207
			s = {
11208
				width: ( that.helper.width()  - soffsetw ),
11209
				height: ( that.helper.height() - soffseth )
11210
			};
11211
			left = ( parseFloat( that.element.css( "left" ) ) +
11212
				( that.position.left - that.originalPosition.left ) ) || null;
11213
			top = ( parseFloat( that.element.css( "top" ) ) +
11214
				( that.position.top - that.originalPosition.top ) ) || null;
11215
11216
			if ( !o.animate ) {
11217
				this.element.css( $.extend( s, { top: top, left: left } ) );
11218
			}
11219
11220
			that.helper.height( that.size.height );
11221
			that.helper.width( that.size.width );
11222
11223
			if ( this._helper && !o.animate ) {
11224
				this._proportionallyResize();
11225
			}
11226
		}
11227
11228
		$( "body" ).css( "cursor", "auto" );
11229
11230
		this._removeClass( "ui-resizable-resizing" );
11231
11232
		this._propagate( "stop", event );
11233
11234
		if ( this._helper ) {
11235
			this.helper.remove();
11236
		}
11237
11238
		return false;
11239
11240
	},
11241
11242
	_updatePrevProperties: function() {
11243
		this.prevPosition = {
11244
			top: this.position.top,
11245
			left: this.position.left
11246
		};
11247
		this.prevSize = {
11248
			width: this.size.width,
11249
			height: this.size.height
11250
		};
11251
	},
11252
11253
	_applyChanges: function() {
11254
		var props = {};
11255
11256
		if ( this.position.top !== this.prevPosition.top ) {
11257
			props.top = this.position.top + "px";
11258
		}
11259
		if ( this.position.left !== this.prevPosition.left ) {
11260
			props.left = this.position.left + "px";
11261
		}
11262
		if ( this.size.width !== this.prevSize.width ) {
11263
			props.width = this.size.width + "px";
11264
		}
11265
		if ( this.size.height !== this.prevSize.height ) {
11266
			props.height = this.size.height + "px";
11267
		}
11268
11269
		this.helper.css( props );
11270
11271
		return props;
11272
	},
11273
11274
	_updateVirtualBoundaries: function( forceAspectRatio ) {
11275
		var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
11276
			o = this.options;
11277
11278
		b = {
11279
			minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
11280
			maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
11281
			minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
11282
			maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
11283
		};
11284
11285
		if ( this._aspectRatio || forceAspectRatio ) {
11286
			pMinWidth = b.minHeight * this.aspectRatio;
11287
			pMinHeight = b.minWidth / this.aspectRatio;
11288
			pMaxWidth = b.maxHeight * this.aspectRatio;
11289
			pMaxHeight = b.maxWidth / this.aspectRatio;
11290
11291
			if ( pMinWidth > b.minWidth ) {
11292
				b.minWidth = pMinWidth;
11293
			}
11294
			if ( pMinHeight > b.minHeight ) {
11295
				b.minHeight = pMinHeight;
11296
			}
11297
			if ( pMaxWidth < b.maxWidth ) {
11298
				b.maxWidth = pMaxWidth;
11299
			}
11300
			if ( pMaxHeight < b.maxHeight ) {
11301
				b.maxHeight = pMaxHeight;
11302
			}
11303
		}
11304
		this._vBoundaries = b;
11305
	},
11306
11307
	_updateCache: function( data ) {
11308
		this.offset = this.helper.offset();
11309
		if ( this._isNumber( data.left ) ) {
11310
			this.position.left = data.left;
11311
		}
11312
		if ( this._isNumber( data.top ) ) {
11313
			this.position.top = data.top;
11314
		}
11315
		if ( this._isNumber( data.height ) ) {
11316
			this.size.height = data.height;
11317
		}
11318
		if ( this._isNumber( data.width ) ) {
11319
			this.size.width = data.width;
11320
		}
11321
	},
11322
11323
	_updateRatio: function( data ) {
11324
11325
		var cpos = this.position,
11326
			csize = this.size,
11327
			a = this.axis;
11328
11329
		if ( this._isNumber( data.height ) ) {
11330
			data.width = ( data.height * this.aspectRatio );
11331
		} else if ( this._isNumber( data.width ) ) {
11332
			data.height = ( data.width / this.aspectRatio );
11333
		}
11334
11335
		if ( a === "sw" ) {
11336
			data.left = cpos.left + ( csize.width - data.width );
11337
			data.top = null;
11338
		}
11339
		if ( a === "nw" ) {
11340
			data.top = cpos.top + ( csize.height - data.height );
11341
			data.left = cpos.left + ( csize.width - data.width );
11342
		}
11343
11344
		return data;
11345
	},
11346
11347
	_respectSize: function( data ) {
11348
11349
		var o = this._vBoundaries,
11350
			a = this.axis,
11351
			ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
11352
			ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
11353
			isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
11354
			isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
11355
			dw = this.originalPosition.left + this.originalSize.width,
11356
			dh = this.originalPosition.top + this.originalSize.height,
11357
			cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
11358
		if ( isminw ) {
11359
			data.width = o.minWidth;
11360
		}
11361
		if ( isminh ) {
11362
			data.height = o.minHeight;
11363
		}
11364
		if ( ismaxw ) {
11365
			data.width = o.maxWidth;
11366
		}
11367
		if ( ismaxh ) {
11368
			data.height = o.maxHeight;
11369
		}
11370
11371
		if ( isminw && cw ) {
11372
			data.left = dw - o.minWidth;
11373
		}
11374
		if ( ismaxw && cw ) {
11375
			data.left = dw - o.maxWidth;
11376
		}
11377
		if ( isminh && ch ) {
11378
			data.top = dh - o.minHeight;
11379
		}
11380
		if ( ismaxh && ch ) {
11381
			data.top = dh - o.maxHeight;
11382
		}
11383
11384
		// Fixing jump error on top/left - bug #2330
11385
		if ( !data.width && !data.height && !data.left && data.top ) {
11386
			data.top = null;
11387
		} else if ( !data.width && !data.height && !data.top && data.left ) {
11388
			data.left = null;
11389
		}
11390
11391
		return data;
11392
	},
11393
11394
	_getPaddingPlusBorderDimensions: function( element ) {
11395
		var i = 0,
11396
			widths = [],
11397
			borders = [
11398
				element.css( "borderTopWidth" ),
11399
				element.css( "borderRightWidth" ),
11400
				element.css( "borderBottomWidth" ),
11401
				element.css( "borderLeftWidth" )
11402
			],
11403
			paddings = [
11404
				element.css( "paddingTop" ),
11405
				element.css( "paddingRight" ),
11406
				element.css( "paddingBottom" ),
11407
				element.css( "paddingLeft" )
11408
			];
11409
11410
		for ( ; i < 4; i++ ) {
11411
			widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
11412
			widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
11413
		}
11414
11415
		return {
11416
			height: widths[ 0 ] + widths[ 2 ],
11417
			width: widths[ 1 ] + widths[ 3 ]
11418
		};
11419
	},
11420
11421
	_proportionallyResize: function() {
11422
11423
		if ( !this._proportionallyResizeElements.length ) {
11424
			return;
11425
		}
11426
11427
		var prel,
11428
			i = 0,
11429
			element = this.helper || this.element;
11430
11431
		for ( ; i < this._proportionallyResizeElements.length; i++ ) {
11432
11433
			prel = this._proportionallyResizeElements[ i ];
11434
11435
			// TODO: Seems like a bug to cache this.outerDimensions
11436
			// considering that we are in a loop.
11437
			if ( !this.outerDimensions ) {
11438
				this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
11439
			}
11440
11441
			prel.css( {
11442
				height: ( element.height() - this.outerDimensions.height ) || 0,
11443
				width: ( element.width() - this.outerDimensions.width ) || 0
11444
			} );
11445
11446
		}
11447
11448
	},
11449
11450
	_renderProxy: function() {
11451
11452
		var el = this.element, o = this.options;
11453
		this.elementOffset = el.offset();
11454
11455
		if ( this._helper ) {
11456
11457
			this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );
11458
11459
			this._addClass( this.helper, this._helper );
11460
			this.helper.css( {
11461
				width: this.element.outerWidth(),
11462
				height: this.element.outerHeight(),
11463
				position: "absolute",
11464
				left: this.elementOffset.left + "px",
11465
				top: this.elementOffset.top + "px",
11466
				zIndex: ++o.zIndex //TODO: Don't modify option
11467
			} );
11468
11469
			this.helper
11470
				.appendTo( "body" )
11471
				.disableSelection();
11472
11473
		} else {
11474
			this.helper = this.element;
11475
		}
11476
11477
	},
11478
11479
	_change: {
11480
		e: function( event, dx ) {
11481
			return { width: this.originalSize.width + dx };
11482
		},
11483
		w: function( event, dx ) {
11484
			var cs = this.originalSize, sp = this.originalPosition;
11485
			return { left: sp.left + dx, width: cs.width - dx };
11486
		},
11487
		n: function( event, dx, dy ) {
11488
			var cs = this.originalSize, sp = this.originalPosition;
11489
			return { top: sp.top + dy, height: cs.height - dy };
11490
		},
11491
		s: function( event, dx, dy ) {
11492
			return { height: this.originalSize.height + dy };
11493
		},
11494
		se: function( event, dx, dy ) {
11495
			return $.extend( this._change.s.apply( this, arguments ),
11496
				this._change.e.apply( this, [ event, dx, dy ] ) );
11497
		},
11498
		sw: function( event, dx, dy ) {
11499
			return $.extend( this._change.s.apply( this, arguments ),
11500
				this._change.w.apply( this, [ event, dx, dy ] ) );
11501
		},
11502
		ne: function( event, dx, dy ) {
11503
			return $.extend( this._change.n.apply( this, arguments ),
11504
				this._change.e.apply( this, [ event, dx, dy ] ) );
11505
		},
11506
		nw: function( event, dx, dy ) {
11507
			return $.extend( this._change.n.apply( this, arguments ),
11508
				this._change.w.apply( this, [ event, dx, dy ] ) );
11509
		}
11510
	},
11511
11512
	_propagate: function( n, event ) {
11513
		$.ui.plugin.call( this, n, [ event, this.ui() ] );
11514
		( n !== "resize" && this._trigger( n, event, this.ui() ) );
11515
	},
11516
11517
	plugins: {},
11518
11519
	ui: function() {
11520
		return {
11521
			originalElement: this.originalElement,
11522
			element: this.element,
11523
			helper: this.helper,
11524
			position: this.position,
11525
			size: this.size,
11526
			originalSize: this.originalSize,
11527
			originalPosition: this.originalPosition
11528
		};
11529
	}
11530
11531
} );
11532
11533
/*
11534
 * Resizable Extensions
11535
 */
11536
11537
$.ui.plugin.add( "resizable", "animate", {
11538
11539
	stop: function( event ) {
11540
		var that = $( this ).resizable( "instance" ),
11541
			o = that.options,
11542
			pr = that._proportionallyResizeElements,
11543
			ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
11544
			soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
11545
			soffsetw = ista ? 0 : that.sizeDiff.width,
11546
			style = {
11547
				width: ( that.size.width - soffsetw ),
11548
				height: ( that.size.height - soffseth )
11549
			},
11550
			left = ( parseFloat( that.element.css( "left" ) ) +
11551
				( that.position.left - that.originalPosition.left ) ) || null,
11552
			top = ( parseFloat( that.element.css( "top" ) ) +
11553
				( that.position.top - that.originalPosition.top ) ) || null;
11554
11555
		that.element.animate(
11556
			$.extend( style, top && left ? { top: top, left: left } : {} ), {
11557
				duration: o.animateDuration,
11558
				easing: o.animateEasing,
11559
				step: function() {
11560
11561
					var data = {
11562
						width: parseFloat( that.element.css( "width" ) ),
11563
						height: parseFloat( that.element.css( "height" ) ),
11564
						top: parseFloat( that.element.css( "top" ) ),
11565
						left: parseFloat( that.element.css( "left" ) )
11566
					};
11567
11568
					if ( pr && pr.length ) {
11569
						$( pr[ 0 ] ).css( { width: data.width, height: data.height } );
11570
					}
11571
11572
					// Propagating resize, and updating values for each animation step
11573
					that._updateCache( data );
11574
					that._propagate( "resize", event );
11575
11576
				}
11577
			}
11578
		);
11579
	}
11580
11581
} );
11582
11583
$.ui.plugin.add( "resizable", "containment", {
11584
11585
	start: function() {
11586
		var element, p, co, ch, cw, width, height,
11587
			that = $( this ).resizable( "instance" ),
11588
			o = that.options,
11589
			el = that.element,
11590
			oc = o.containment,
11591
			ce = ( oc instanceof $ ) ?
11592
				oc.get( 0 ) :
11593
				( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
11594
11595
		if ( !ce ) {
11596
			return;
11597
		}
11598
11599
		that.containerElement = $( ce );
11600
11601
		if ( /document/.test( oc ) || oc === document ) {
11602
			that.containerOffset = {
11603
				left: 0,
11604
				top: 0
11605
			};
11606
			that.containerPosition = {
11607
				left: 0,
11608
				top: 0
11609
			};
11610
11611
			that.parentData = {
11612
				element: $( document ),
11613
				left: 0,
11614
				top: 0,
11615
				width: $( document ).width(),
11616
				height: $( document ).height() || document.body.parentNode.scrollHeight
11617
			};
11618
		} else {
11619
			element = $( ce );
11620
			p = [];
11621
			$( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
11622
				p[ i ] = that._num( element.css( "padding" + name ) );
11623
			} );
11624
11625
			that.containerOffset = element.offset();
11626
			that.containerPosition = element.position();
11627
			that.containerSize = {
11628
				height: ( element.innerHeight() - p[ 3 ] ),
11629
				width: ( element.innerWidth() - p[ 1 ] )
11630
			};
11631
11632
			co = that.containerOffset;
11633
			ch = that.containerSize.height;
11634
			cw = that.containerSize.width;
11635
			width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
11636
			height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
11637
11638
			that.parentData = {
11639
				element: ce,
11640
				left: co.left,
11641
				top: co.top,
11642
				width: width,
11643
				height: height
11644
			};
11645
		}
11646
	},
11647
11648
	resize: function( event ) {
11649
		var woset, hoset, isParent, isOffsetRelative,
11650
			that = $( this ).resizable( "instance" ),
11651
			o = that.options,
11652
			co = that.containerOffset,
11653
			cp = that.position,
11654
			pRatio = that._aspectRatio || event.shiftKey,
11655
			cop = {
11656
				top: 0,
11657
				left: 0
11658
			},
11659
			ce = that.containerElement,
11660
			continueResize = true;
11661
11662
		if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
11663
			cop = co;
11664
		}
11665
11666
		if ( cp.left < ( that._helper ? co.left : 0 ) ) {
11667
			that.size.width = that.size.width +
11668
				( that._helper ?
11669
					( that.position.left - co.left ) :
11670
					( that.position.left - cop.left ) );
11671
11672
			if ( pRatio ) {
11673
				that.size.height = that.size.width / that.aspectRatio;
11674
				continueResize = false;
11675
			}
11676
			that.position.left = o.helper ? co.left : 0;
11677
		}
11678
11679
		if ( cp.top < ( that._helper ? co.top : 0 ) ) {
11680
			that.size.height = that.size.height +
11681
				( that._helper ?
11682
					( that.position.top - co.top ) :
11683
					that.position.top );
11684
11685
			if ( pRatio ) {
11686
				that.size.width = that.size.height * that.aspectRatio;
11687
				continueResize = false;
11688
			}
11689
			that.position.top = that._helper ? co.top : 0;
11690
		}
11691
11692
		isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
11693
		isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
11694
11695
		if ( isParent && isOffsetRelative ) {
11696
			that.offset.left = that.parentData.left + that.position.left;
11697
			that.offset.top = that.parentData.top + that.position.top;
11698
		} else {
11699
			that.offset.left = that.element.offset().left;
11700
			that.offset.top = that.element.offset().top;
11701
		}
11702
11703
		woset = Math.abs( that.sizeDiff.width +
11704
			( that._helper ?
11705
				that.offset.left - cop.left :
11706
				( that.offset.left - co.left ) ) );
11707
11708
		hoset = Math.abs( that.sizeDiff.height +
11709
			( that._helper ?
11710
				that.offset.top - cop.top :
11711
				( that.offset.top - co.top ) ) );
11712
11713
		if ( woset + that.size.width >= that.parentData.width ) {
11714
			that.size.width = that.parentData.width - woset;
11715
			if ( pRatio ) {
11716
				that.size.height = that.size.width / that.aspectRatio;
11717
				continueResize = false;
11718
			}
11719
		}
11720
11721
		if ( hoset + that.size.height >= that.parentData.height ) {
11722
			that.size.height = that.parentData.height - hoset;
11723
			if ( pRatio ) {
11724
				that.size.width = that.size.height * that.aspectRatio;
11725
				continueResize = false;
11726
			}
11727
		}
11728
11729
		if ( !continueResize ) {
11730
			that.position.left = that.prevPosition.left;
11731
			that.position.top = that.prevPosition.top;
11732
			that.size.width = that.prevSize.width;
11733
			that.size.height = that.prevSize.height;
11734
		}
11735
	},
11736
11737
	stop: function() {
11738
		var that = $( this ).resizable( "instance" ),
11739
			o = that.options,
11740
			co = that.containerOffset,
11741
			cop = that.containerPosition,
11742
			ce = that.containerElement,
11743
			helper = $( that.helper ),
11744
			ho = helper.offset(),
11745
			w = helper.outerWidth() - that.sizeDiff.width,
11746
			h = helper.outerHeight() - that.sizeDiff.height;
11747
11748
		if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
11749
			$( this ).css( {
11750
				left: ho.left - cop.left - co.left,
11751
				width: w,
11752
				height: h
11753
			} );
11754
		}
11755
11756
		if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
11757
			$( this ).css( {
11758
				left: ho.left - cop.left - co.left,
11759
				width: w,
11760
				height: h
11761
			} );
11762
		}
11763
	}
11764
} );
11765
11766
$.ui.plugin.add( "resizable", "alsoResize", {
11767
11768
	start: function() {
11769
		var that = $( this ).resizable( "instance" ),
11770
			o = that.options;
11771
11772
		$( o.alsoResize ).each( function() {
11773
			var el = $( this );
11774
			el.data( "ui-resizable-alsoresize", {
11775
				width: parseFloat( el.width() ), height: parseFloat( el.height() ),
11776
				left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
11777
			} );
11778
		} );
11779
	},
11780
11781
	resize: function( event, ui ) {
11782
		var that = $( this ).resizable( "instance" ),
11783
			o = that.options,
11784
			os = that.originalSize,
11785
			op = that.originalPosition,
11786
			delta = {
11787
				height: ( that.size.height - os.height ) || 0,
11788
				width: ( that.size.width - os.width ) || 0,
11789
				top: ( that.position.top - op.top ) || 0,
11790
				left: ( that.position.left - op.left ) || 0
11791
			};
11792
11793
			$( o.alsoResize ).each( function() {
11794
				var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
11795
					css = el.parents( ui.originalElement[ 0 ] ).length ?
11796
							[ "width", "height" ] :
11797
							[ "width", "height", "top", "left" ];
11798
11799
				$.each( css, function( i, prop ) {
11800
					var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
11801
					if ( sum && sum >= 0 ) {
11802
						style[ prop ] = sum || null;
11803
					}
11804
				} );
11805
11806
				el.css( style );
11807
			} );
11808
	},
11809
11810
	stop: function() {
11811
		$( this ).removeData( "ui-resizable-alsoresize" );
11812
	}
11813
} );
11814
11815
$.ui.plugin.add( "resizable", "ghost", {
11816
11817
	start: function() {
11818
11819
		var that = $( this ).resizable( "instance" ), cs = that.size;
11820
11821
		that.ghost = that.originalElement.clone();
11822
		that.ghost.css( {
11823
			opacity: 0.25,
11824
			display: "block",
11825
			position: "relative",
11826
			height: cs.height,
11827
			width: cs.width,
11828
			margin: 0,
11829
			left: 0,
11830
			top: 0
11831
		} );
11832
11833
		that._addClass( that.ghost, "ui-resizable-ghost" );
11834
11835
		// DEPRECATED
11836
		// TODO: remove after 1.12
11837
		if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
11838
11839
			// Ghost option
11840
			that.ghost.addClass( this.options.ghost );
11841
		}
11842
11843
		that.ghost.appendTo( that.helper );
11844
11845
	},
11846
11847
	resize: function() {
11848
		var that = $( this ).resizable( "instance" );
11849
		if ( that.ghost ) {
11850
			that.ghost.css( {
11851
				position: "relative",
11852
				height: that.size.height,
11853
				width: that.size.width
11854
			} );
11855
		}
11856
	},
11857
11858
	stop: function() {
11859
		var that = $( this ).resizable( "instance" );
11860
		if ( that.ghost && that.helper ) {
11861
			that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
11862
		}
11863
	}
11864
11865
} );
11866
11867
$.ui.plugin.add( "resizable", "grid", {
11868
11869
	resize: function() {
11870
		var outerDimensions,
11871
			that = $( this ).resizable( "instance" ),
11872
			o = that.options,
11873
			cs = that.size,
11874
			os = that.originalSize,
11875
			op = that.originalPosition,
11876
			a = that.axis,
11877
			grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
11878
			gridX = ( grid[ 0 ] || 1 ),
11879
			gridY = ( grid[ 1 ] || 1 ),
11880
			ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
11881
			oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
11882
			newWidth = os.width + ox,
11883
			newHeight = os.height + oy,
11884
			isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
11885
			isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
11886
			isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
11887
			isMinHeight = o.minHeight && ( o.minHeight > newHeight );
11888
11889
		o.grid = grid;
11890
11891
		if ( isMinWidth ) {
11892
			newWidth += gridX;
11893
		}
11894
		if ( isMinHeight ) {
11895
			newHeight += gridY;
11896
		}
11897
		if ( isMaxWidth ) {
11898
			newWidth -= gridX;
11899
		}
11900
		if ( isMaxHeight ) {
11901
			newHeight -= gridY;
11902
		}
11903
11904
		if ( /^(se|s|e)$/.test( a ) ) {
11905
			that.size.width = newWidth;
11906
			that.size.height = newHeight;
11907
		} else if ( /^(ne)$/.test( a ) ) {
11908
			that.size.width = newWidth;
11909
			that.size.height = newHeight;
11910
			that.position.top = op.top - oy;
11911
		} else if ( /^(sw)$/.test( a ) ) {
11912
			that.size.width = newWidth;
11913
			that.size.height = newHeight;
11914
			that.position.left = op.left - ox;
11915
		} else {
11916
			if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
11917
				outerDimensions = that._getPaddingPlusBorderDimensions( this );
11918
			}
11919
11920
			if ( newHeight - gridY > 0 ) {
11921
				that.size.height = newHeight;
11922
				that.position.top = op.top - oy;
11923
			} else {
11924
				newHeight = gridY - outerDimensions.height;
0 ignored issues
show
Bug introduced by
The variable outerDimensions does not seem to be initialized in case newHeight - gridY <= 0 || newWidth - gridX <= 0 on line 11916 is false. Are you sure this can never be the case?
Loading history...
11925
				that.size.height = newHeight;
11926
				that.position.top = op.top + os.height - newHeight;
11927
			}
11928
			if ( newWidth - gridX > 0 ) {
11929
				that.size.width = newWidth;
11930
				that.position.left = op.left - ox;
11931
			} else {
11932
				newWidth = gridX - outerDimensions.width;
11933
				that.size.width = newWidth;
11934
				that.position.left = op.left + os.width - newWidth;
11935
			}
11936
		}
11937
	}
11938
11939
} );
11940
11941
var widgetsResizable = $.ui.resizable;
0 ignored issues
show
Unused Code introduced by
The variable widgetsResizable seems to be never used. Consider removing it.
Loading history...
11942
11943
11944
/*!
11945
 * jQuery UI Dialog 1.12.1
11946
 * http://jqueryui.com
11947
 *
11948
 * Copyright jQuery Foundation and other contributors
11949
 * Released under the MIT license.
11950
 * http://jquery.org/license
11951
 */
11952
11953
//>>label: Dialog
11954
//>>group: Widgets
11955
//>>description: Displays customizable dialog windows.
11956
//>>docs: http://api.jqueryui.com/dialog/
11957
//>>demos: http://jqueryui.com/dialog/
11958
//>>css.structure: ../../themes/base/core.css
11959
//>>css.structure: ../../themes/base/dialog.css
11960
//>>css.theme: ../../themes/base/theme.css
11961
11962
11963
11964
$.widget( "ui.dialog", {
11965
	version: "1.12.1",
11966
	options: {
11967
		appendTo: "body",
11968
		autoOpen: true,
11969
		buttons: [],
11970
		classes: {
11971
			"ui-dialog": "ui-corner-all",
11972
			"ui-dialog-titlebar": "ui-corner-all"
11973
		},
11974
		closeOnEscape: true,
11975
		closeText: "Close",
11976
		draggable: true,
11977
		hide: null,
11978
		height: "auto",
11979
		maxHeight: null,
11980
		maxWidth: null,
11981
		minHeight: 150,
11982
		minWidth: 150,
11983
		modal: false,
11984
		position: {
11985
			my: "center",
11986
			at: "center",
11987
			of: window,
11988
			collision: "fit",
11989
11990
			// Ensure the titlebar is always visible
11991
			using: function( pos ) {
11992
				var topOffset = $( this ).css( pos ).offset().top;
11993
				if ( topOffset < 0 ) {
11994
					$( this ).css( "top", pos.top - topOffset );
11995
				}
11996
			}
11997
		},
11998
		resizable: true,
11999
		show: null,
12000
		title: null,
12001
		width: 300,
12002
12003
		// Callbacks
12004
		beforeClose: null,
12005
		close: null,
12006
		drag: null,
12007
		dragStart: null,
12008
		dragStop: null,
12009
		focus: null,
12010
		open: null,
12011
		resize: null,
12012
		resizeStart: null,
12013
		resizeStop: null
12014
	},
12015
12016
	sizeRelatedOptions: {
12017
		buttons: true,
12018
		height: true,
12019
		maxHeight: true,
12020
		maxWidth: true,
12021
		minHeight: true,
12022
		minWidth: true,
12023
		width: true
12024
	},
12025
12026
	resizableRelatedOptions: {
12027
		maxHeight: true,
12028
		maxWidth: true,
12029
		minHeight: true,
12030
		minWidth: true
12031
	},
12032
12033
	_create: function() {
12034
		this.originalCss = {
12035
			display: this.element[ 0 ].style.display,
12036
			width: this.element[ 0 ].style.width,
12037
			minHeight: this.element[ 0 ].style.minHeight,
12038
			maxHeight: this.element[ 0 ].style.maxHeight,
12039
			height: this.element[ 0 ].style.height
12040
		};
12041
		this.originalPosition = {
12042
			parent: this.element.parent(),
12043
			index: this.element.parent().children().index( this.element )
12044
		};
12045
		this.originalTitle = this.element.attr( "title" );
12046
		if ( this.options.title == null && this.originalTitle != null ) {
0 ignored issues
show
Best Practice introduced by
Comparing this.originalTitle to null using the != operator is not safe. Consider using !== instead.
Loading history...
Best Practice introduced by
Comparing this.options.title to null using the == operator is not safe. Consider using === instead.
Loading history...
12047
			this.options.title = this.originalTitle;
12048
		}
12049
12050
		// Dialogs can't be disabled
12051
		if ( this.options.disabled ) {
12052
			this.options.disabled = false;
12053
		}
12054
12055
		this._createWrapper();
12056
12057
		this.element
12058
			.show()
12059
			.removeAttr( "title" )
12060
			.appendTo( this.uiDialog );
12061
12062
		this._addClass( "ui-dialog-content", "ui-widget-content" );
12063
12064
		this._createTitlebar();
12065
		this._createButtonPane();
12066
12067
		if ( this.options.draggable && $.fn.draggable ) {
12068
			this._makeDraggable();
12069
		}
12070
		if ( this.options.resizable && $.fn.resizable ) {
12071
			this._makeResizable();
12072
		}
12073
12074
		this._isOpen = false;
12075
12076
		this._trackFocus();
12077
	},
12078
12079
	_init: function() {
12080
		if ( this.options.autoOpen ) {
12081
			this.open();
12082
		}
12083
	},
12084
12085
	_appendTo: function() {
12086
		var element = this.options.appendTo;
12087
		if ( element && ( element.jquery || element.nodeType ) ) {
12088
			return $( element );
12089
		}
12090
		return this.document.find( element || "body" ).eq( 0 );
12091
	},
12092
12093
	_destroy: function() {
12094
		var next,
12095
			originalPosition = this.originalPosition;
12096
12097
		this._untrackInstance();
12098
		this._destroyOverlay();
12099
12100
		this.element
12101
			.removeUniqueId()
12102
			.css( this.originalCss )
12103
12104
			// Without detaching first, the following becomes really slow
12105
			.detach();
12106
12107
		this.uiDialog.remove();
12108
12109
		if ( this.originalTitle ) {
12110
			this.element.attr( "title", this.originalTitle );
12111
		}
12112
12113
		next = originalPosition.parent.children().eq( originalPosition.index );
12114
12115
		// Don't try to place the dialog next to itself (#8613)
12116
		if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
12117
			next.before( this.element );
12118
		} else {
12119
			originalPosition.parent.append( this.element );
12120
		}
12121
	},
12122
12123
	widget: function() {
12124
		return this.uiDialog;
12125
	},
12126
12127
	disable: $.noop,
12128
	enable: $.noop,
12129
12130
	close: function( event ) {
12131
		var that = this;
12132
12133
		if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
12134
			return;
12135
		}
12136
12137
		this._isOpen = false;
12138
		this._focusedElement = null;
12139
		this._destroyOverlay();
12140
		this._untrackInstance();
12141
12142
		if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
12143
12144
			// Hiding a focused element doesn't trigger blur in WebKit
12145
			// so in case we have nothing to focus on, explicitly blur the active element
12146
			// https://bugs.webkit.org/show_bug.cgi?id=47182
12147
			$.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
12148
		}
12149
12150
		this._hide( this.uiDialog, this.options.hide, function() {
12151
			that._trigger( "close", event );
12152
		} );
12153
	},
12154
12155
	isOpen: function() {
12156
		return this._isOpen;
12157
	},
12158
12159
	moveToTop: function() {
12160
		this._moveToTop();
12161
	},
12162
12163
	_moveToTop: function( event, silent ) {
12164
		var moved = false,
12165
			zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
12166
				return +$( this ).css( "z-index" );
12167
			} ).get(),
12168
			zIndexMax = Math.max.apply( null, zIndices );
12169
12170
		if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
12171
			this.uiDialog.css( "z-index", zIndexMax + 1 );
12172
			moved = true;
12173
		}
12174
12175
		if ( moved && !silent ) {
12176
			this._trigger( "focus", event );
12177
		}
12178
		return moved;
12179
	},
12180
12181
	open: function() {
12182
		var that = this;
12183
		if ( this._isOpen ) {
12184
			if ( this._moveToTop() ) {
12185
				this._focusTabbable();
12186
			}
12187
			return;
12188
		}
12189
12190
		this._isOpen = true;
12191
		this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
12192
12193
		this._size();
12194
		this._position();
12195
		this._createOverlay();
12196
		this._moveToTop( null, true );
12197
12198
		// Ensure the overlay is moved to the top with the dialog, but only when
12199
		// opening. The overlay shouldn't move after the dialog is open so that
12200
		// modeless dialogs opened after the modal dialog stack properly.
12201
		if ( this.overlay ) {
12202
			this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
12203
		}
12204
12205
		this._show( this.uiDialog, this.options.show, function() {
12206
			that._focusTabbable();
12207
			that._trigger( "focus" );
12208
		} );
12209
12210
		// Track the dialog immediately upon openening in case a focus event
12211
		// somehow occurs outside of the dialog before an element inside the
12212
		// dialog is focused (#10152)
12213
		this._makeFocusTarget();
12214
12215
		this._trigger( "open" );
12216
	},
12217
12218
	_focusTabbable: function() {
12219
12220
		// Set focus to the first match:
12221
		// 1. An element that was focused previously
12222
		// 2. First element inside the dialog matching [autofocus]
12223
		// 3. Tabbable element inside the content element
12224
		// 4. Tabbable element inside the buttonpane
12225
		// 5. The close button
12226
		// 6. The dialog itself
12227
		var hasFocus = this._focusedElement;
12228
		if ( !hasFocus ) {
12229
			hasFocus = this.element.find( "[autofocus]" );
12230
		}
12231
		if ( !hasFocus.length ) {
12232
			hasFocus = this.element.find( ":tabbable" );
12233
		}
12234
		if ( !hasFocus.length ) {
12235
			hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
12236
		}
12237
		if ( !hasFocus.length ) {
12238
			hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
12239
		}
12240
		if ( !hasFocus.length ) {
12241
			hasFocus = this.uiDialog;
12242
		}
12243
		hasFocus.eq( 0 ).trigger( "focus" );
12244
	},
12245
12246
	_keepFocus: function( event ) {
12247
		function checkFocus() {
12248
			var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
12249
				isActive = this.uiDialog[ 0 ] === activeElement ||
12250
					$.contains( this.uiDialog[ 0 ], activeElement );
12251
			if ( !isActive ) {
12252
				this._focusTabbable();
12253
			}
12254
		}
12255
		event.preventDefault();
12256
		checkFocus.call( this );
12257
12258
		// support: IE
12259
		// IE <= 8 doesn't prevent moving focus even with event.preventDefault()
12260
		// so we check again later
12261
		this._delay( checkFocus );
12262
	},
12263
12264
	_createWrapper: function() {
12265
		this.uiDialog = $( "<div>" )
12266
			.hide()
12267
			.attr( {
12268
12269
				// Setting tabIndex makes the div focusable
12270
				tabIndex: -1,
12271
				role: "dialog"
12272
			} )
12273
			.appendTo( this._appendTo() );
12274
12275
		this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
12276
		this._on( this.uiDialog, {
12277
			keydown: function( event ) {
12278
				if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
12279
						event.keyCode === $.ui.keyCode.ESCAPE ) {
12280
					event.preventDefault();
12281
					this.close( event );
12282
					return;
12283
				}
12284
12285
				// Prevent tabbing out of dialogs
12286
				if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
12287
					return;
12288
				}
12289
				var tabbables = this.uiDialog.find( ":tabbable" ),
12290
					first = tabbables.filter( ":first" ),
12291
					last = tabbables.filter( ":last" );
12292
12293
				if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
12294
						!event.shiftKey ) {
12295
					this._delay( function() {
12296
						first.trigger( "focus" );
12297
					} );
12298
					event.preventDefault();
12299
				} else if ( ( event.target === first[ 0 ] ||
12300
						event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
12301
					this._delay( function() {
12302
						last.trigger( "focus" );
12303
					} );
12304
					event.preventDefault();
12305
				}
12306
			},
12307
			mousedown: function( event ) {
12308
				if ( this._moveToTop( event ) ) {
12309
					this._focusTabbable();
12310
				}
12311
			}
12312
		} );
12313
12314
		// We assume that any existing aria-describedby attribute means
12315
		// that the dialog content is marked up properly
12316
		// otherwise we brute force the content as the description
12317
		if ( !this.element.find( "[aria-describedby]" ).length ) {
12318
			this.uiDialog.attr( {
12319
				"aria-describedby": this.element.uniqueId().attr( "id" )
12320
			} );
12321
		}
12322
	},
12323
12324
	_createTitlebar: function() {
12325
		var uiDialogTitle;
12326
12327
		this.uiDialogTitlebar = $( "<div>" );
12328
		this._addClass( this.uiDialogTitlebar,
12329
			"ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
12330
		this._on( this.uiDialogTitlebar, {
12331
			mousedown: function( event ) {
12332
12333
				// Don't prevent click on close button (#8838)
12334
				// Focusing a dialog that is partially scrolled out of view
12335
				// causes the browser to scroll it into view, preventing the click event
12336
				if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
12337
12338
					// Dialog isn't getting focus when dragging (#8063)
12339
					this.uiDialog.trigger( "focus" );
12340
				}
12341
			}
12342
		} );
12343
12344
		// Support: IE
12345
		// Use type="button" to prevent enter keypresses in textboxes from closing the
12346
		// dialog in IE (#9312)
12347
		this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
12348
			.button( {
12349
				label: $( "<a>" ).text( this.options.closeText ).html(),
12350
				icon: "ui-icon-closethick",
12351
				showLabel: false
12352
			} )
12353
			.appendTo( this.uiDialogTitlebar );
12354
12355
		this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
12356
		this._on( this.uiDialogTitlebarClose, {
12357
			click: function( event ) {
12358
				event.preventDefault();
12359
				this.close( event );
12360
			}
12361
		} );
12362
12363
		uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
12364
		this._addClass( uiDialogTitle, "ui-dialog-title" );
12365
		this._title( uiDialogTitle );
12366
12367
		this.uiDialogTitlebar.prependTo( this.uiDialog );
12368
12369
		this.uiDialog.attr( {
12370
			"aria-labelledby": uiDialogTitle.attr( "id" )
12371
		} );
12372
	},
12373
12374
	_title: function( title ) {
12375
		if ( this.options.title ) {
12376
			title.text( this.options.title );
12377
		} else {
12378
			title.html( "&#160;" );
12379
		}
12380
	},
12381
12382
	_createButtonPane: function() {
12383
		this.uiDialogButtonPane = $( "<div>" );
12384
		this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
12385
			"ui-widget-content ui-helper-clearfix" );
12386
12387
		this.uiButtonSet = $( "<div>" )
12388
			.appendTo( this.uiDialogButtonPane );
12389
		this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
12390
12391
		this._createButtons();
12392
	},
12393
12394
	_createButtons: function() {
12395
		var that = this,
12396
			buttons = this.options.buttons;
12397
12398
		// If we already have a button pane, remove it
12399
		this.uiDialogButtonPane.remove();
12400
		this.uiButtonSet.empty();
12401
12402
		if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
12403
			this._removeClass( this.uiDialog, "ui-dialog-buttons" );
12404
			return;
12405
		}
12406
12407
		$.each( buttons, function( name, props ) {
12408
			var click, buttonOptions;
12409
			props = $.isFunction( props ) ?
12410
				{ click: props, text: name } :
12411
				props;
12412
12413
			// Default to a non-submitting button
12414
			props = $.extend( { type: "button" }, props );
12415
12416
			// Change the context for the click callback to be the main element
12417
			click = props.click;
12418
			buttonOptions = {
12419
				icon: props.icon,
12420
				iconPosition: props.iconPosition,
12421
				showLabel: props.showLabel,
12422
12423
				// Deprecated options
12424
				icons: props.icons,
12425
				text: props.text
12426
			};
12427
12428
			delete props.click;
12429
			delete props.icon;
12430
			delete props.iconPosition;
12431
			delete props.showLabel;
12432
12433
			// Deprecated options
12434
			delete props.icons;
12435
			if ( typeof props.text === "boolean" ) {
12436
				delete props.text;
12437
			}
12438
12439
			$( "<button></button>", props )
12440
				.button( buttonOptions )
12441
				.appendTo( that.uiButtonSet )
12442
				.on( "click", function() {
12443
					click.apply( that.element[ 0 ], arguments );
12444
				} );
12445
		} );
12446
		this._addClass( this.uiDialog, "ui-dialog-buttons" );
12447
		this.uiDialogButtonPane.appendTo( this.uiDialog );
12448
	},
12449
12450
	_makeDraggable: function() {
12451
		var that = this,
12452
			options = this.options;
12453
12454
		function filteredUi( ui ) {
12455
			return {
12456
				position: ui.position,
12457
				offset: ui.offset
12458
			};
12459
		}
12460
12461
		this.uiDialog.draggable( {
12462
			cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
12463
			handle: ".ui-dialog-titlebar",
12464
			containment: "document",
12465
			start: function( event, ui ) {
12466
				that._addClass( $( this ), "ui-dialog-dragging" );
12467
				that._blockFrames();
12468
				that._trigger( "dragStart", event, filteredUi( ui ) );
12469
			},
12470
			drag: function( event, ui ) {
12471
				that._trigger( "drag", event, filteredUi( ui ) );
12472
			},
12473
			stop: function( event, ui ) {
12474
				var left = ui.offset.left - that.document.scrollLeft(),
12475
					top = ui.offset.top - that.document.scrollTop();
12476
12477
				options.position = {
12478
					my: "left top",
12479
					at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12480
						"top" + ( top >= 0 ? "+" : "" ) + top,
12481
					of: that.window
12482
				};
12483
				that._removeClass( $( this ), "ui-dialog-dragging" );
12484
				that._unblockFrames();
12485
				that._trigger( "dragStop", event, filteredUi( ui ) );
12486
			}
12487
		} );
12488
	},
12489
12490
	_makeResizable: function() {
12491
		var that = this,
12492
			options = this.options,
12493
			handles = options.resizable,
12494
12495
			// .ui-resizable has position: relative defined in the stylesheet
12496
			// but dialogs have to use absolute or fixed positioning
12497
			position = this.uiDialog.css( "position" ),
12498
			resizeHandles = typeof handles === "string" ?
12499
				handles :
12500
				"n,e,s,w,se,sw,ne,nw";
12501
12502
		function filteredUi( ui ) {
12503
			return {
12504
				originalPosition: ui.originalPosition,
12505
				originalSize: ui.originalSize,
12506
				position: ui.position,
12507
				size: ui.size
12508
			};
12509
		}
12510
12511
		this.uiDialog.resizable( {
12512
			cancel: ".ui-dialog-content",
12513
			containment: "document",
12514
			alsoResize: this.element,
12515
			maxWidth: options.maxWidth,
12516
			maxHeight: options.maxHeight,
12517
			minWidth: options.minWidth,
12518
			minHeight: this._minHeight(),
12519
			handles: resizeHandles,
12520
			start: function( event, ui ) {
12521
				that._addClass( $( this ), "ui-dialog-resizing" );
12522
				that._blockFrames();
12523
				that._trigger( "resizeStart", event, filteredUi( ui ) );
12524
			},
12525
			resize: function( event, ui ) {
12526
				that._trigger( "resize", event, filteredUi( ui ) );
12527
			},
12528
			stop: function( event, ui ) {
12529
				var offset = that.uiDialog.offset(),
12530
					left = offset.left - that.document.scrollLeft(),
12531
					top = offset.top - that.document.scrollTop();
12532
12533
				options.height = that.uiDialog.height();
12534
				options.width = that.uiDialog.width();
12535
				options.position = {
12536
					my: "left top",
12537
					at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12538
						"top" + ( top >= 0 ? "+" : "" ) + top,
12539
					of: that.window
12540
				};
12541
				that._removeClass( $( this ), "ui-dialog-resizing" );
12542
				that._unblockFrames();
12543
				that._trigger( "resizeStop", event, filteredUi( ui ) );
12544
			}
12545
		} )
12546
			.css( "position", position );
12547
	},
12548
12549
	_trackFocus: function() {
12550
		this._on( this.widget(), {
12551
			focusin: function( event ) {
12552
				this._makeFocusTarget();
12553
				this._focusedElement = $( event.target );
12554
			}
12555
		} );
12556
	},
12557
12558
	_makeFocusTarget: function() {
12559
		this._untrackInstance();
12560
		this._trackingInstances().unshift( this );
12561
	},
12562
12563
	_untrackInstance: function() {
12564
		var instances = this._trackingInstances(),
12565
			exists = $.inArray( this, instances );
12566
		if ( exists !== -1 ) {
12567
			instances.splice( exists, 1 );
12568
		}
12569
	},
12570
12571
	_trackingInstances: function() {
12572
		var instances = this.document.data( "ui-dialog-instances" );
12573
		if ( !instances ) {
12574
			instances = [];
12575
			this.document.data( "ui-dialog-instances", instances );
12576
		}
12577
		return instances;
12578
	},
12579
12580
	_minHeight: function() {
12581
		var options = this.options;
12582
12583
		return options.height === "auto" ?
12584
			options.minHeight :
12585
			Math.min( options.minHeight, options.height );
12586
	},
12587
12588
	_position: function() {
12589
12590
		// Need to show the dialog to get the actual offset in the position plugin
12591
		var isVisible = this.uiDialog.is( ":visible" );
12592
		if ( !isVisible ) {
12593
			this.uiDialog.show();
12594
		}
12595
		this.uiDialog.position( this.options.position );
12596
		if ( !isVisible ) {
12597
			this.uiDialog.hide();
12598
		}
12599
	},
12600
12601
	_setOptions: function( options ) {
12602
		var that = this,
12603
			resize = false,
12604
			resizableOptions = {};
12605
12606
		$.each( options, function( key, value ) {
12607
			that._setOption( key, value );
12608
12609
			if ( key in that.sizeRelatedOptions ) {
12610
				resize = true;
12611
			}
12612
			if ( key in that.resizableRelatedOptions ) {
12613
				resizableOptions[ key ] = value;
12614
			}
12615
		} );
12616
12617
		if ( resize ) {
12618
			this._size();
12619
			this._position();
12620
		}
12621
		if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12622
			this.uiDialog.resizable( "option", resizableOptions );
12623
		}
12624
	},
12625
12626
	_setOption: function( key, value ) {
12627
		var isDraggable, isResizable,
12628
			uiDialog = this.uiDialog;
12629
12630
		if ( key === "disabled" ) {
12631
			return;
12632
		}
12633
12634
		this._super( key, value );
12635
12636
		if ( key === "appendTo" ) {
12637
			this.uiDialog.appendTo( this._appendTo() );
12638
		}
12639
12640
		if ( key === "buttons" ) {
12641
			this._createButtons();
12642
		}
12643
12644
		if ( key === "closeText" ) {
12645
			this.uiDialogTitlebarClose.button( {
12646
12647
				// Ensure that we always pass a string
12648
				label: $( "<a>" ).text( "" + this.options.closeText ).html()
12649
			} );
12650
		}
12651
12652
		if ( key === "draggable" ) {
12653
			isDraggable = uiDialog.is( ":data(ui-draggable)" );
12654
			if ( isDraggable && !value ) {
12655
				uiDialog.draggable( "destroy" );
12656
			}
12657
12658
			if ( !isDraggable && value ) {
12659
				this._makeDraggable();
12660
			}
12661
		}
12662
12663
		if ( key === "position" ) {
12664
			this._position();
12665
		}
12666
12667
		if ( key === "resizable" ) {
12668
12669
			// currently resizable, becoming non-resizable
12670
			isResizable = uiDialog.is( ":data(ui-resizable)" );
12671
			if ( isResizable && !value ) {
12672
				uiDialog.resizable( "destroy" );
12673
			}
12674
12675
			// Currently resizable, changing handles
12676
			if ( isResizable && typeof value === "string" ) {
12677
				uiDialog.resizable( "option", "handles", value );
12678
			}
12679
12680
			// Currently non-resizable, becoming resizable
12681
			if ( !isResizable && value !== false ) {
12682
				this._makeResizable();
12683
			}
12684
		}
12685
12686
		if ( key === "title" ) {
12687
			this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
12688
		}
12689
	},
12690
12691 View Code Duplication
	_size: function() {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
12692
12693
		// If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
12694
		// divs will both have width and height set, so we need to reset them
12695
		var nonContentHeight, minContentHeight, maxContentHeight,
12696
			options = this.options;
12697
12698
		// Reset content sizing
12699
		this.element.show().css( {
12700
			width: "auto",
12701
			minHeight: 0,
12702
			maxHeight: "none",
12703
			height: 0
12704
		} );
12705
12706
		if ( options.minWidth > options.width ) {
12707
			options.width = options.minWidth;
12708
		}
12709
12710
		// Reset wrapper sizing
12711
		// determine the height of all the non-content elements
12712
		nonContentHeight = this.uiDialog.css( {
12713
			height: "auto",
12714
			width: options.width
12715
		} )
12716
			.outerHeight();
12717
		minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
12718
		maxContentHeight = typeof options.maxHeight === "number" ?
12719
			Math.max( 0, options.maxHeight - nonContentHeight ) :
12720
			"none";
12721
12722
		if ( options.height === "auto" ) {
12723
			this.element.css( {
12724
				minHeight: minContentHeight,
12725
				maxHeight: maxContentHeight,
12726
				height: "auto"
12727
			} );
12728
		} else {
12729
			this.element.height( Math.max( 0, options.height - nonContentHeight ) );
12730
		}
12731
12732
		if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12733
			this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
12734
		}
12735
	},
12736
12737
	_blockFrames: function() {
12738
		this.iframeBlocks = this.document.find( "iframe" ).map( function() {
12739
			var iframe = $( this );
12740
12741
			return $( "<div>" )
12742
				.css( {
12743
					position: "absolute",
12744
					width: iframe.outerWidth(),
12745
					height: iframe.outerHeight()
12746
				} )
12747
				.appendTo( iframe.parent() )
12748
				.offset( iframe.offset() )[ 0 ];
12749
		} );
12750
	},
12751
12752
	_unblockFrames: function() {
12753
		if ( this.iframeBlocks ) {
12754
			this.iframeBlocks.remove();
12755
			delete this.iframeBlocks;
12756
		}
12757
	},
12758
12759
	_allowInteraction: function( event ) {
12760
		if ( $( event.target ).closest( ".ui-dialog" ).length ) {
12761
			return true;
12762
		}
12763
12764
		// TODO: Remove hack when datepicker implements
12765
		// the .ui-front logic (#8989)
12766
		return !!$( event.target ).closest( ".ui-datepicker" ).length;
12767
	},
12768
12769
	_createOverlay: function() {
12770
		if ( !this.options.modal ) {
12771
			return;
12772
		}
12773
12774
		// We use a delay in case the overlay is created from an
12775
		// event that we're going to be cancelling (#2804)
12776
		var isOpening = true;
12777
		this._delay( function() {
12778
			isOpening = false;
12779
		} );
12780
12781
		if ( !this.document.data( "ui-dialog-overlays" ) ) {
12782
12783
			// Prevent use of anchors and inputs
12784
			// Using _on() for an event handler shared across many instances is
12785
			// safe because the dialogs stack and must be closed in reverse order
12786
			this._on( this.document, {
12787
				focusin: function( event ) {
12788
					if ( isOpening ) {
12789
						return;
12790
					}
12791
12792
					if ( !this._allowInteraction( event ) ) {
12793
						event.preventDefault();
12794
						this._trackingInstances()[ 0 ]._focusTabbable();
12795
					}
12796
				}
12797
			} );
12798
		}
12799
12800
		this.overlay = $( "<div>" )
12801
			.appendTo( this._appendTo() );
12802
12803
		this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
12804
		this._on( this.overlay, {
12805
			mousedown: "_keepFocus"
12806
		} );
12807
		this.document.data( "ui-dialog-overlays",
12808
			( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
12809
	},
12810
12811
	_destroyOverlay: function() {
12812
		if ( !this.options.modal ) {
12813
			return;
12814
		}
12815
12816
		if ( this.overlay ) {
12817
			var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
12818
12819
			if ( !overlays ) {
12820
				this._off( this.document, "focusin" );
12821
				this.document.removeData( "ui-dialog-overlays" );
12822
			} else {
12823
				this.document.data( "ui-dialog-overlays", overlays );
12824
			}
12825
12826
			this.overlay.remove();
12827
			this.overlay = null;
12828
		}
12829
	}
12830
} );
12831
12832
// DEPRECATED
12833
// TODO: switch return back to widget declaration at top of file when this is removed
12834
if ( $.uiBackCompat !== false ) {
12835
12836
	// Backcompat for dialogClass option
12837
	$.widget( "ui.dialog", $.ui.dialog, {
12838
		options: {
12839
			dialogClass: ""
12840
		},
12841
		_createWrapper: function() {
12842
			this._super();
12843
			this.uiDialog.addClass( this.options.dialogClass );
12844
		},
12845
		_setOption: function( key, value ) {
12846
			if ( key === "dialogClass" ) {
12847
				this.uiDialog
12848
					.removeClass( this.options.dialogClass )
12849
					.addClass( value );
12850
			}
12851
			this._superApply( arguments );
12852
		}
12853
	} );
12854
}
12855
12856
var widgetsDialog = $.ui.dialog;
0 ignored issues
show
Unused Code introduced by
The variable widgetsDialog seems to be never used. Consider removing it.
Loading history...
12857
12858
12859
/*!
12860
 * jQuery UI Droppable 1.12.1
12861
 * http://jqueryui.com
12862
 *
12863
 * Copyright jQuery Foundation and other contributors
12864
 * Released under the MIT license.
12865
 * http://jquery.org/license
12866
 */
12867
12868
//>>label: Droppable
12869
//>>group: Interactions
12870
//>>description: Enables drop targets for draggable elements.
12871
//>>docs: http://api.jqueryui.com/droppable/
12872
//>>demos: http://jqueryui.com/droppable/
12873
12874
12875
12876
$.widget( "ui.droppable", {
12877
	version: "1.12.1",
12878
	widgetEventPrefix: "drop",
12879
	options: {
12880
		accept: "*",
12881
		addClasses: true,
12882
		greedy: false,
12883
		scope: "default",
12884
		tolerance: "intersect",
12885
12886
		// Callbacks
12887
		activate: null,
12888
		deactivate: null,
12889
		drop: null,
12890
		out: null,
12891
		over: null
12892
	},
12893
	_create: function() {
12894
12895
		var proportions,
12896
			o = this.options,
12897
			accept = o.accept;
12898
12899
		this.isover = false;
12900
		this.isout = true;
12901
12902
		this.accept = $.isFunction( accept ) ? accept : function( d ) {
12903
			return d.is( accept );
12904
		};
12905
12906
		this.proportions = function( /* valueToWrite */ ) {
12907
			if ( arguments.length ) {
12908
12909
				// Store the droppable's proportions
12910
				proportions = arguments[ 0 ];
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
12911
			} else {
12912
12913
				// Retrieve or derive the droppable's proportions
12914
				return proportions ?
12915
					proportions :
12916
					proportions = {
12917
						width: this.element[ 0 ].offsetWidth,
12918
						height: this.element[ 0 ].offsetHeight
12919
					};
12920
			}
12921
		};
12922
12923
		this._addToManager( o.scope );
12924
12925
		o.addClasses && this._addClass( "ui-droppable" );
12926
12927
	},
12928
12929
	_addToManager: function( scope ) {
12930
12931
		// Add the reference and positions to the manager
12932
		$.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
12933
		$.ui.ddmanager.droppables[ scope ].push( this );
12934
	},
12935
12936
	_splice: function( drop ) {
12937
		var i = 0;
12938
		for ( ; i < drop.length; i++ ) {
12939
			if ( drop[ i ] === this ) {
12940
				drop.splice( i, 1 );
12941
			}
12942
		}
12943
	},
12944
12945
	_destroy: function() {
12946
		var drop = $.ui.ddmanager.droppables[ this.options.scope ];
12947
12948
		this._splice( drop );
12949
	},
12950
12951
	_setOption: function( key, value ) {
12952
12953
		if ( key === "accept" ) {
12954
			this.accept = $.isFunction( value ) ? value : function( d ) {
12955
				return d.is( value );
12956
			};
12957
		} else if ( key === "scope" ) {
12958
			var drop = $.ui.ddmanager.droppables[ this.options.scope ];
12959
12960
			this._splice( drop );
12961
			this._addToManager( value );
12962
		}
12963
12964
		this._super( key, value );
12965
	},
12966
12967
	_activate: function( event ) {
12968
		var draggable = $.ui.ddmanager.current;
12969
12970
		this._addActiveClass();
12971
		if ( draggable ) {
12972
			this._trigger( "activate", event, this.ui( draggable ) );
12973
		}
12974
	},
12975
12976
	_deactivate: function( event ) {
12977
		var draggable = $.ui.ddmanager.current;
12978
12979
		this._removeActiveClass();
12980
		if ( draggable ) {
12981
			this._trigger( "deactivate", event, this.ui( draggable ) );
12982
		}
12983
	},
12984
12985
	_over: function( event ) {
12986
12987
		var draggable = $.ui.ddmanager.current;
12988
12989
		// Bail if draggable and droppable are same element
12990
		if ( !draggable || ( draggable.currentItem ||
12991
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
12992
			return;
12993
		}
12994
12995
		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
12996
				draggable.element ) ) ) {
12997
			this._addHoverClass();
12998
			this._trigger( "over", event, this.ui( draggable ) );
12999
		}
13000
13001
	},
13002
13003
	_out: function( event ) {
13004
13005
		var draggable = $.ui.ddmanager.current;
13006
13007
		// Bail if draggable and droppable are same element
13008
		if ( !draggable || ( draggable.currentItem ||
13009
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
13010
			return;
13011
		}
13012
13013
		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
13014
				draggable.element ) ) ) {
13015
			this._removeHoverClass();
13016
			this._trigger( "out", event, this.ui( draggable ) );
13017
		}
13018
13019
	},
13020
13021
	_drop: function( event, custom ) {
13022
13023
		var draggable = custom || $.ui.ddmanager.current,
13024
			childrenIntersection = false;
13025
13026
		// Bail if draggable and droppable are same element
13027
		if ( !draggable || ( draggable.currentItem ||
13028
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
13029
			return false;
13030
		}
13031
13032
		this.element
13033
			.find( ":data(ui-droppable)" )
13034
			.not( ".ui-draggable-dragging" )
13035
			.each( function() {
13036
				var inst = $( this ).droppable( "instance" );
13037
				if (
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if inst.options.greedy && !...tions.tolerance, event) 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...
13038
					inst.options.greedy &&
13039
					!inst.options.disabled &&
13040
					inst.options.scope === draggable.options.scope &&
13041
					inst.accept.call(
13042
						inst.element[ 0 ], ( draggable.currentItem || draggable.element )
13043
					) &&
13044
					intersect(
13045
						draggable,
13046
						$.extend( inst, { offset: inst.element.offset() } ),
13047
						inst.options.tolerance, event
13048
					)
13049
				) {
13050
					childrenIntersection = true;
13051
					return false; }
13052
			} );
13053
		if ( childrenIntersection ) {
13054
			return false;
13055
		}
13056
13057
		if ( this.accept.call( this.element[ 0 ],
13058
				( draggable.currentItem || draggable.element ) ) ) {
13059
			this._removeActiveClass();
13060
			this._removeHoverClass();
13061
13062
			this._trigger( "drop", event, this.ui( draggable ) );
13063
			return this.element;
13064
		}
13065
13066
		return false;
13067
13068
	},
13069
13070
	ui: function( c ) {
13071
		return {
13072
			draggable: ( c.currentItem || c.element ),
13073
			helper: c.helper,
13074
			position: c.position,
13075
			offset: c.positionAbs
13076
		};
13077
	},
13078
13079
	// Extension points just to make backcompat sane and avoid duplicating logic
13080
	// TODO: Remove in 1.13 along with call to it below
13081
	_addHoverClass: function() {
13082
		this._addClass( "ui-droppable-hover" );
13083
	},
13084
13085
	_removeHoverClass: function() {
13086
		this._removeClass( "ui-droppable-hover" );
13087
	},
13088
13089
	_addActiveClass: function() {
13090
		this._addClass( "ui-droppable-active" );
13091
	},
13092
13093
	_removeActiveClass: function() {
13094
		this._removeClass( "ui-droppable-active" );
13095
	}
13096
} );
13097
13098
var intersect = $.ui.intersect = ( function() {
13099
	function isOverAxis( x, reference, size ) {
13100
		return ( x >= reference ) && ( x < ( reference + size ) );
13101
	}
13102
13103
	return function( draggable, droppable, toleranceMode, event ) {
13104
13105
		if ( !droppable.offset ) {
13106
			return false;
13107
		}
13108
13109
		var x1 = ( draggable.positionAbs ||
13110
				draggable.position.absolute ).left + draggable.margins.left,
13111
			y1 = ( draggable.positionAbs ||
13112
				draggable.position.absolute ).top + draggable.margins.top,
13113
			x2 = x1 + draggable.helperProportions.width,
13114
			y2 = y1 + draggable.helperProportions.height,
13115
			l = droppable.offset.left,
13116
			t = droppable.offset.top,
13117
			r = l + droppable.proportions().width,
13118
			b = t + droppable.proportions().height;
13119
13120
		switch ( toleranceMode ) {
13121
		case "fit":
13122
			return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
13123
		case "intersect":
13124
			return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
13125
				x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
13126
				t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
13127
				y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
13128
		case "pointer":
13129
			return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
13130
				isOverAxis( event.pageX, l, droppable.proportions().width );
13131
		case "touch":
13132
			return (
13133
				( y1 >= t && y1 <= b ) || // Top edge touching
13134
				( y2 >= t && y2 <= b ) || // Bottom edge touching
13135
				( y1 < t && y2 > b ) // Surrounded vertically
13136
			) && (
13137
				( x1 >= l && x1 <= r ) || // Left edge touching
13138
				( x2 >= l && x2 <= r ) || // Right edge touching
13139
				( x1 < l && x2 > r ) // Surrounded horizontally
13140
			);
13141
		default:
13142
			return false;
13143
		}
13144
	};
13145
} )();
13146
13147
/*
13148
	This manager tracks offsets of draggables and droppables
13149
*/
13150
$.ui.ddmanager = {
13151
	current: null,
13152
	droppables: { "default": [] },
13153
	prepareOffsets: function( t, event ) {
13154
13155
		var i, j,
13156
			m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
13157
			type = event ? event.type : null, // workaround for #2317
13158
			list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
13159
13160
		droppablesLoop: for ( i = 0; i < m.length; i++ ) {
13161
13162
			// No disabled and non-accepted
13163
			if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
13164
					( t.currentItem || t.element ) ) ) ) {
13165
				continue;
13166
			}
13167
13168
			// Filter out elements in the current dragged item
13169
			for ( j = 0; j < list.length; j++ ) {
13170
				if ( list[ j ] === m[ i ].element[ 0 ] ) {
13171
					m[ i ].proportions().height = 0;
13172
					continue droppablesLoop;
13173
				}
13174
			}
13175
13176
			m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
13177
			if ( !m[ i ].visible ) {
13178
				continue;
13179
			}
13180
13181
			// Activate the droppable if used directly from draggables
13182
			if ( type === "mousedown" ) {
13183
				m[ i ]._activate.call( m[ i ], event );
13184
			}
13185
13186
			m[ i ].offset = m[ i ].element.offset();
13187
			m[ i ].proportions( {
13188
				width: m[ i ].element[ 0 ].offsetWidth,
13189
				height: m[ i ].element[ 0 ].offsetHeight
13190
			} );
13191
13192
		}
13193
13194
	},
13195
	drop: function( draggable, event ) {
13196
13197
		var dropped = false;
13198
13199
		// Create a copy of the droppables in case the list changes during the drop (#9116)
13200
		$.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
13201
13202
			if ( !this.options ) {
13203
				return;
13204
			}
13205
			if ( !this.options.disabled && this.visible &&
13206
					intersect( draggable, this, this.options.tolerance, event ) ) {
13207
				dropped = this._drop.call( this, event ) || dropped;
13208
			}
13209
13210
			if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
13211
					( draggable.currentItem || draggable.element ) ) ) {
13212
				this.isout = true;
13213
				this.isover = false;
13214
				this._deactivate.call( this, event );
13215
			}
13216
13217
		} );
13218
		return dropped;
13219
13220
	},
13221
	dragStart: function( draggable, event ) {
13222
13223
		// Listen for scrolling so that if the dragging causes scrolling the position of the
13224
		// droppables can be recalculated (see #5003)
13225
		draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
13226
			if ( !draggable.options.refreshPositions ) {
13227
				$.ui.ddmanager.prepareOffsets( draggable, event );
13228
			}
13229
		} );
13230
	},
13231
	drag: function( draggable, event ) {
13232
13233
		// If you have a highly dynamic page, you might try this option. It renders positions
13234
		// every time you move the mouse.
13235
		if ( draggable.options.refreshPositions ) {
13236
			$.ui.ddmanager.prepareOffsets( draggable, event );
13237
		}
13238
13239
		// Run through all droppables and check their positions based on specific tolerance options
13240
		$.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
13241
13242
			if ( this.options.disabled || this.greedyChild || !this.visible ) {
13243
				return;
13244
			}
13245
13246
			var parentInstance, scope, parent,
13247
				intersects = intersect( draggable, this, this.options.tolerance, event ),
13248
				c = !intersects && this.isover ?
13249
					"isout" :
13250
					( intersects && !this.isover ? "isover" : null );
13251
			if ( !c ) {
13252
				return;
13253
			}
13254
13255
			if ( this.options.greedy ) {
13256
13257
				// find droppable parents with same scope
13258
				scope = this.options.scope;
13259
				parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
13260
					return $( this ).droppable( "instance" ).options.scope === scope;
13261
				} );
13262
13263
				if ( parent.length ) {
13264
					parentInstance = $( parent[ 0 ] ).droppable( "instance" );
13265
					parentInstance.greedyChild = ( c === "isover" );
13266
				}
13267
			}
13268
13269
			// We just moved into a greedy child
13270
			if ( parentInstance && c === "isover" ) {
13271
				parentInstance.isover = false;
13272
				parentInstance.isout = true;
13273
				parentInstance._out.call( parentInstance, event );
13274
			}
13275
13276
			this[ c ] = true;
13277
			this[ c === "isout" ? "isover" : "isout" ] = false;
13278
			this[ c === "isover" ? "_over" : "_out" ].call( this, event );
13279
13280
			// We just moved out of a greedy child
13281
			if ( parentInstance && c === "isout" ) {
13282
				parentInstance.isout = false;
13283
				parentInstance.isover = true;
13284
				parentInstance._over.call( parentInstance, event );
13285
			}
13286
		} );
13287
13288
	},
13289
	dragStop: function( draggable, event ) {
13290
		draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
13291
13292
		// Call prepareOffsets one final time since IE does not fire return scroll events when
13293
		// overflow was caused by drag (see #5003)
13294
		if ( !draggable.options.refreshPositions ) {
13295
			$.ui.ddmanager.prepareOffsets( draggable, event );
13296
		}
13297
	}
13298
};
13299
13300
// DEPRECATED
13301
// TODO: switch return back to widget declaration at top of file when this is removed
13302
if ( $.uiBackCompat !== false ) {
13303
13304
	// Backcompat for activeClass and hoverClass options
13305
	$.widget( "ui.droppable", $.ui.droppable, {
13306
		options: {
13307
			hoverClass: false,
13308
			activeClass: false
13309
		},
13310
		_addActiveClass: function() {
13311
			this._super();
13312
			if ( this.options.activeClass ) {
13313
				this.element.addClass( this.options.activeClass );
13314
			}
13315
		},
13316
		_removeActiveClass: function() {
13317
			this._super();
13318
			if ( this.options.activeClass ) {
13319
				this.element.removeClass( this.options.activeClass );
13320
			}
13321
		},
13322
		_addHoverClass: function() {
13323
			this._super();
13324
			if ( this.options.hoverClass ) {
13325
				this.element.addClass( this.options.hoverClass );
13326
			}
13327
		},
13328
		_removeHoverClass: function() {
13329
			this._super();
13330
			if ( this.options.hoverClass ) {
13331
				this.element.removeClass( this.options.hoverClass );
13332
			}
13333
		}
13334
	} );
13335
}
13336
13337
var widgetsDroppable = $.ui.droppable;
0 ignored issues
show
Unused Code introduced by
The variable widgetsDroppable seems to be never used. Consider removing it.
Loading history...
13338
13339
13340
/*!
13341
 * jQuery UI Progressbar 1.12.1
13342
 * http://jqueryui.com
13343
 *
13344
 * Copyright jQuery Foundation and other contributors
13345
 * Released under the MIT license.
13346
 * http://jquery.org/license
13347
 */
13348
13349
//>>label: Progressbar
13350
//>>group: Widgets
13351
// jscs:disable maximumLineLength
13352
//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
13353
// jscs:enable maximumLineLength
13354
//>>docs: http://api.jqueryui.com/progressbar/
13355
//>>demos: http://jqueryui.com/progressbar/
13356
//>>css.structure: ../../themes/base/core.css
13357
//>>css.structure: ../../themes/base/progressbar.css
13358
//>>css.theme: ../../themes/base/theme.css
13359
13360
13361
13362
var widgetsProgressbar = $.widget( "ui.progressbar", {
0 ignored issues
show
Unused Code introduced by
The variable widgetsProgressbar seems to be never used. Consider removing it.
Loading history...
13363
	version: "1.12.1",
13364
	options: {
13365
		classes: {
13366
			"ui-progressbar": "ui-corner-all",
13367
			"ui-progressbar-value": "ui-corner-left",
13368
			"ui-progressbar-complete": "ui-corner-right"
13369
		},
13370
		max: 100,
13371
		value: 0,
13372
13373
		change: null,
13374
		complete: null
13375
	},
13376
13377
	min: 0,
13378
13379
	_create: function() {
13380
13381
		// Constrain initial value
13382
		this.oldValue = this.options.value = this._constrainedValue();
13383
13384
		this.element.attr( {
13385
13386
			// Only set static values; aria-valuenow and aria-valuemax are
13387
			// set inside _refreshValue()
13388
			role: "progressbar",
13389
			"aria-valuemin": this.min
13390
		} );
13391
		this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
13392
13393
		this.valueDiv = $( "<div>" ).appendTo( this.element );
13394
		this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
13395
		this._refreshValue();
13396
	},
13397
13398
	_destroy: function() {
13399
		this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
13400
13401
		this.valueDiv.remove();
13402
	},
13403
13404
	value: function( newValue ) {
13405
		if ( newValue === undefined ) {
13406
			return this.options.value;
13407
		}
13408
13409
		this.options.value = this._constrainedValue( newValue );
13410
		this._refreshValue();
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
13411
	},
13412
13413
	_constrainedValue: function( newValue ) {
13414
		if ( newValue === undefined ) {
13415
			newValue = this.options.value;
13416
		}
13417
13418
		this.indeterminate = newValue === false;
13419
13420
		// Sanitize value
13421
		if ( typeof newValue !== "number" ) {
13422
			newValue = 0;
13423
		}
13424
13425
		return this.indeterminate ? false :
13426
			Math.min( this.options.max, Math.max( this.min, newValue ) );
13427
	},
13428
13429
	_setOptions: function( options ) {
13430
13431
		// Ensure "value" option is set after other values (like max)
13432
		var value = options.value;
13433
		delete options.value;
13434
13435
		this._super( options );
13436
13437
		this.options.value = this._constrainedValue( value );
13438
		this._refreshValue();
13439
	},
13440
13441
	_setOption: function( key, value ) {
13442
		if ( key === "max" ) {
13443
13444
			// Don't allow a max less than min
13445
			value = Math.max( this.min, value );
13446
		}
13447
		this._super( key, value );
13448
	},
13449
13450
	_setOptionDisabled: function( value ) {
13451
		this._super( value );
13452
13453
		this.element.attr( "aria-disabled", value );
13454
		this._toggleClass( null, "ui-state-disabled", !!value );
13455
	},
13456
13457
	_percentage: function() {
13458
		return this.indeterminate ?
13459
			100 :
13460
			100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
13461
	},
13462
13463
	_refreshValue: function() {
13464
		var value = this.options.value,
13465
			percentage = this._percentage();
13466
13467
		this.valueDiv
13468
			.toggle( this.indeterminate || value > this.min )
13469
			.width( percentage.toFixed( 0 ) + "%" );
13470
13471
		this
13472
			._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
13473
				value === this.options.max )
13474
			._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
13475
13476
		if ( this.indeterminate ) {
13477
			this.element.removeAttr( "aria-valuenow" );
13478
			if ( !this.overlayDiv ) {
13479
				this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
13480
				this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
13481
			}
13482
		} else {
13483
			this.element.attr( {
13484
				"aria-valuemax": this.options.max,
13485
				"aria-valuenow": value
13486
			} );
13487
			if ( this.overlayDiv ) {
13488
				this.overlayDiv.remove();
13489
				this.overlayDiv = null;
13490
			}
13491
		}
13492
13493
		if ( this.oldValue !== value ) {
13494
			this.oldValue = value;
13495
			this._trigger( "change" );
13496
		}
13497
		if ( value === this.options.max ) {
13498
			this._trigger( "complete" );
13499
		}
13500
	}
13501
} );
13502
13503
13504
/*!
13505
 * jQuery UI Selectable 1.12.1
13506
 * http://jqueryui.com
13507
 *
13508
 * Copyright jQuery Foundation and other contributors
13509
 * Released under the MIT license.
13510
 * http://jquery.org/license
13511
 */
13512
13513
//>>label: Selectable
13514
//>>group: Interactions
13515
//>>description: Allows groups of elements to be selected with the mouse.
13516
//>>docs: http://api.jqueryui.com/selectable/
13517
//>>demos: http://jqueryui.com/selectable/
13518
//>>css.structure: ../../themes/base/selectable.css
13519
13520
13521
13522
var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
0 ignored issues
show
Unused Code introduced by
The variable widgetsSelectable seems to be never used. Consider removing it.
Loading history...
13523
	version: "1.12.1",
13524
	options: {
13525
		appendTo: "body",
13526
		autoRefresh: true,
13527
		distance: 0,
13528
		filter: "*",
13529
		tolerance: "touch",
13530
13531
		// Callbacks
13532
		selected: null,
13533
		selecting: null,
13534
		start: null,
13535
		stop: null,
13536
		unselected: null,
13537
		unselecting: null
13538
	},
13539
	_create: function() {
13540
		var that = this;
13541
13542
		this._addClass( "ui-selectable" );
13543
13544
		this.dragged = false;
13545
13546
		// Cache selectee children based on filter
13547
		this.refresh = function() {
13548
			that.elementPos = $( that.element[ 0 ] ).offset();
13549
			that.selectees = $( that.options.filter, that.element[ 0 ] );
13550
			that._addClass( that.selectees, "ui-selectee" );
13551
			that.selectees.each( function() {
13552
				var $this = $( this ),
13553
					selecteeOffset = $this.offset(),
13554
					pos = {
13555
						left: selecteeOffset.left - that.elementPos.left,
13556
						top: selecteeOffset.top - that.elementPos.top
13557
					};
13558
				$.data( this, "selectable-item", {
13559
					element: this,
13560
					$element: $this,
13561
					left: pos.left,
13562
					top: pos.top,
13563
					right: pos.left + $this.outerWidth(),
13564
					bottom: pos.top + $this.outerHeight(),
13565
					startselected: false,
13566
					selected: $this.hasClass( "ui-selected" ),
13567
					selecting: $this.hasClass( "ui-selecting" ),
13568
					unselecting: $this.hasClass( "ui-unselecting" )
13569
				} );
13570
			} );
13571
		};
13572
		this.refresh();
13573
13574
		this._mouseInit();
13575
13576
		this.helper = $( "<div>" );
13577
		this._addClass( this.helper, "ui-selectable-helper" );
13578
	},
13579
13580
	_destroy: function() {
13581
		this.selectees.removeData( "selectable-item" );
13582
		this._mouseDestroy();
13583
	},
13584
13585
	_mouseStart: function( event ) {
13586
		var that = this,
13587
			options = this.options;
13588
13589
		this.opos = [ event.pageX, event.pageY ];
13590
		this.elementPos = $( this.element[ 0 ] ).offset();
13591
13592
		if ( this.options.disabled ) {
13593
			return;
13594
		}
13595
13596
		this.selectees = $( options.filter, this.element[ 0 ] );
13597
13598
		this._trigger( "start", event );
13599
13600
		$( options.appendTo ).append( this.helper );
13601
13602
		// position helper (lasso)
13603
		this.helper.css( {
13604
			"left": event.pageX,
13605
			"top": event.pageY,
13606
			"width": 0,
13607
			"height": 0
13608
		} );
13609
13610
		if ( options.autoRefresh ) {
13611
			this.refresh();
13612
		}
13613
13614
		this.selectees.filter( ".ui-selected" ).each( function() {
13615
			var selectee = $.data( this, "selectable-item" );
13616
			selectee.startselected = true;
13617
			if ( !event.metaKey && !event.ctrlKey ) {
13618
				that._removeClass( selectee.$element, "ui-selected" );
13619
				selectee.selected = false;
13620
				that._addClass( selectee.$element, "ui-unselecting" );
13621
				selectee.unselecting = true;
13622
13623
				// selectable UNSELECTING callback
13624
				that._trigger( "unselecting", event, {
13625
					unselecting: selectee.element
13626
				} );
13627
			}
13628
		} );
13629
13630
		$( event.target ).parents().addBack().each( function() {
13631
			var doSelect,
13632
				selectee = $.data( this, "selectable-item" );
13633
			if ( selectee ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if selectee 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...
13634
				doSelect = ( !event.metaKey && !event.ctrlKey ) ||
13635
					!selectee.$element.hasClass( "ui-selected" );
13636
				that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
13637
					._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
13638
				selectee.unselecting = !doSelect;
13639
				selectee.selecting = doSelect;
13640
				selectee.selected = doSelect;
13641
13642
				// selectable (UN)SELECTING callback
13643
				if ( doSelect ) {
13644
					that._trigger( "selecting", event, {
13645
						selecting: selectee.element
13646
					} );
13647
				} else {
13648
					that._trigger( "unselecting", event, {
13649
						unselecting: selectee.element
13650
					} );
13651
				}
13652
				return false;
13653
			}
13654
		} );
13655
13656
	},
13657
13658
	_mouseDrag: function( event ) {
13659
13660
		this.dragged = true;
13661
13662
		if ( this.options.disabled ) {
13663
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
13664
		}
13665
13666
		var tmp,
13667
			that = this,
13668
			options = this.options,
13669
			x1 = this.opos[ 0 ],
13670
			y1 = this.opos[ 1 ],
13671
			x2 = event.pageX,
13672
			y2 = event.pageY;
13673
13674
		if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; }
13675
		if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; }
13676
		this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
13677
13678
		this.selectees.each( function() {
13679
			var selectee = $.data( this, "selectable-item" ),
13680
				hit = false,
13681
				offset = {};
13682
13683
			//prevent helper from being selected if appendTo: selectable
13684
			if ( !selectee || selectee.element === that.element[ 0 ] ) {
13685
				return;
13686
			}
13687
13688
			offset.left   = selectee.left   + that.elementPos.left;
13689
			offset.right  = selectee.right  + that.elementPos.left;
13690
			offset.top    = selectee.top    + that.elementPos.top;
13691
			offset.bottom = selectee.bottom + that.elementPos.top;
13692
13693
			if ( options.tolerance === "touch" ) {
13694
				hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
13695
                    offset.bottom < y1 ) );
13696
			} else if ( options.tolerance === "fit" ) {
13697
				hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
13698
                    offset.bottom < y2 );
13699
			}
13700
13701
			if ( hit ) {
13702
13703
				// SELECT
13704
				if ( selectee.selected ) {
13705
					that._removeClass( selectee.$element, "ui-selected" );
13706
					selectee.selected = false;
13707
				}
13708
				if ( selectee.unselecting ) {
13709
					that._removeClass( selectee.$element, "ui-unselecting" );
13710
					selectee.unselecting = false;
13711
				}
13712
				if ( !selectee.selecting ) {
13713
					that._addClass( selectee.$element, "ui-selecting" );
13714
					selectee.selecting = true;
13715
13716
					// selectable SELECTING callback
13717
					that._trigger( "selecting", event, {
13718
						selecting: selectee.element
13719
					} );
13720
				}
13721
			} else {
13722
13723
				// UNSELECT
13724
				if ( selectee.selecting ) {
13725
					if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
13726
						that._removeClass( selectee.$element, "ui-selecting" );
13727
						selectee.selecting = false;
13728
						that._addClass( selectee.$element, "ui-selected" );
13729
						selectee.selected = true;
13730
					} else {
13731
						that._removeClass( selectee.$element, "ui-selecting" );
13732
						selectee.selecting = false;
13733
						if ( selectee.startselected ) {
13734
							that._addClass( selectee.$element, "ui-unselecting" );
13735
							selectee.unselecting = true;
13736
						}
13737
13738
						// selectable UNSELECTING callback
13739
						that._trigger( "unselecting", event, {
13740
							unselecting: selectee.element
13741
						} );
13742
					}
13743
				}
13744
				if ( selectee.selected ) {
13745
					if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
13746
						that._removeClass( selectee.$element, "ui-selected" );
13747
						selectee.selected = false;
13748
13749
						that._addClass( selectee.$element, "ui-unselecting" );
13750
						selectee.unselecting = true;
13751
13752
						// selectable UNSELECTING callback
13753
						that._trigger( "unselecting", event, {
13754
							unselecting: selectee.element
13755
						} );
13756
					}
13757
				}
13758
			}
13759
		} );
13760
13761
		return false;
13762
	},
13763
13764
	_mouseStop: function( event ) {
13765
		var that = this;
13766
13767
		this.dragged = false;
13768
13769
		$( ".ui-unselecting", this.element[ 0 ] ).each( function() {
13770
			var selectee = $.data( this, "selectable-item" );
13771
			that._removeClass( selectee.$element, "ui-unselecting" );
13772
			selectee.unselecting = false;
13773
			selectee.startselected = false;
13774
			that._trigger( "unselected", event, {
13775
				unselected: selectee.element
13776
			} );
13777
		} );
13778
		$( ".ui-selecting", this.element[ 0 ] ).each( function() {
13779
			var selectee = $.data( this, "selectable-item" );
13780
			that._removeClass( selectee.$element, "ui-selecting" )
13781
				._addClass( selectee.$element, "ui-selected" );
13782
			selectee.selecting = false;
13783
			selectee.selected = true;
13784
			selectee.startselected = true;
13785
			that._trigger( "selected", event, {
13786
				selected: selectee.element
13787
			} );
13788
		} );
13789
		this._trigger( "stop", event );
13790
13791
		this.helper.remove();
13792
13793
		return false;
13794
	}
13795
13796
} );
13797
13798
13799
/*!
13800
 * jQuery UI Selectmenu 1.12.1
13801
 * http://jqueryui.com
13802
 *
13803
 * Copyright jQuery Foundation and other contributors
13804
 * Released under the MIT license.
13805
 * http://jquery.org/license
13806
 */
13807
13808
//>>label: Selectmenu
13809
//>>group: Widgets
13810
// jscs:disable maximumLineLength
13811
//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
13812
// jscs:enable maximumLineLength
13813
//>>docs: http://api.jqueryui.com/selectmenu/
13814
//>>demos: http://jqueryui.com/selectmenu/
13815
//>>css.structure: ../../themes/base/core.css
13816
//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
13817
//>>css.theme: ../../themes/base/theme.css
13818
13819
13820
13821
var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
0 ignored issues
show
Unused Code introduced by
The variable widgetsSelectmenu seems to be never used. Consider removing it.
Loading history...
13822
	version: "1.12.1",
13823
	defaultElement: "<select>",
13824
	options: {
13825
		appendTo: null,
13826
		classes: {
13827
			"ui-selectmenu-button-open": "ui-corner-top",
13828
			"ui-selectmenu-button-closed": "ui-corner-all"
13829
		},
13830
		disabled: null,
13831
		icons: {
13832
			button: "ui-icon-triangle-1-s"
13833
		},
13834
		position: {
13835
			my: "left top",
13836
			at: "left bottom",
13837
			collision: "none"
13838
		},
13839
		width: false,
13840
13841
		// Callbacks
13842
		change: null,
13843
		close: null,
13844
		focus: null,
13845
		open: null,
13846
		select: null
13847
	},
13848
13849
	_create: function() {
13850
		var selectmenuId = this.element.uniqueId().attr( "id" );
13851
		this.ids = {
13852
			element: selectmenuId,
13853
			button: selectmenuId + "-button",
13854
			menu: selectmenuId + "-menu"
13855
		};
13856
13857
		this._drawButton();
13858
		this._drawMenu();
13859
		this._bindFormResetHandler();
13860
13861
		this._rendered = false;
13862
		this.menuItems = $();
13863
	},
13864
13865
	_drawButton: function() {
13866
		var icon,
13867
			that = this,
13868
			item = this._parseOption(
13869
				this.element.find( "option:selected" ),
13870
				this.element[ 0 ].selectedIndex
13871
			);
13872
13873
		// Associate existing label with the new button
13874
		this.labels = this.element.labels().attr( "for", this.ids.button );
13875
		this._on( this.labels, {
13876
			click: function( event ) {
13877
				this.button.focus();
13878
				event.preventDefault();
13879
			}
13880
		} );
13881
13882
		// Hide original select element
13883
		this.element.hide();
13884
13885
		// Create button
13886
		this.button = $( "<span>", {
13887
			tabindex: this.options.disabled ? -1 : 0,
13888
			id: this.ids.button,
13889
			role: "combobox",
13890
			"aria-expanded": "false",
13891
			"aria-autocomplete": "list",
13892
			"aria-owns": this.ids.menu,
13893
			"aria-haspopup": "true",
13894
			title: this.element.attr( "title" )
13895
		} )
13896
			.insertAfter( this.element );
13897
13898
		this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
13899
			"ui-button ui-widget" );
13900
13901
		icon = $( "<span>" ).appendTo( this.button );
13902
		this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
13903
		this.buttonItem = this._renderButtonItem( item )
13904
			.appendTo( this.button );
13905
13906
		if ( this.options.width !== false ) {
13907
			this._resizeButton();
13908
		}
13909
13910
		this._on( this.button, this._buttonEvents );
13911
		this.button.one( "focusin", function() {
13912
13913
			// Delay rendering the menu items until the button receives focus.
13914
			// The menu may have already been rendered via a programmatic open.
13915
			if ( !that._rendered ) {
13916
				that._refreshMenu();
13917
			}
13918
		} );
13919
	},
13920
13921
	_drawMenu: function() {
13922
		var that = this;
13923
13924
		// Create menu
13925
		this.menu = $( "<ul>", {
13926
			"aria-hidden": "true",
13927
			"aria-labelledby": this.ids.button,
13928
			id: this.ids.menu
13929
		} );
13930
13931
		// Wrap menu
13932
		this.menuWrap = $( "<div>" ).append( this.menu );
13933
		this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
13934
		this.menuWrap.appendTo( this._appendTo() );
13935
13936
		// Initialize menu widget
13937
		this.menuInstance = this.menu
13938
			.menu( {
13939
				classes: {
13940
					"ui-menu": "ui-corner-bottom"
13941
				},
13942
				role: "listbox",
13943
				select: function( event, ui ) {
13944
					event.preventDefault();
13945
13946
					// Support: IE8
13947
					// If the item was selected via a click, the text selection
13948
					// will be destroyed in IE
13949
					that._setSelection();
13950
13951
					that._select( ui.item.data( "ui-selectmenu-item" ), event );
13952
				},
13953
				focus: function( event, ui ) {
13954
					var item = ui.item.data( "ui-selectmenu-item" );
13955
13956
					// Prevent inital focus from firing and check if its a newly focused item
13957
					if ( that.focusIndex != null && item.index !== that.focusIndex ) {
0 ignored issues
show
Best Practice introduced by
Comparing that.focusIndex to null using the != operator is not safe. Consider using !== instead.
Loading history...
13958
						that._trigger( "focus", event, { item: item } );
13959
						if ( !that.isOpen ) {
13960
							that._select( item, event );
13961
						}
13962
					}
13963
					that.focusIndex = item.index;
13964
13965
					that.button.attr( "aria-activedescendant",
13966
						that.menuItems.eq( item.index ).attr( "id" ) );
13967
				}
13968
			} )
13969
			.menu( "instance" );
13970
13971
		// Don't close the menu on mouseleave
13972
		this.menuInstance._off( this.menu, "mouseleave" );
13973
13974
		// Cancel the menu's collapseAll on document click
13975
		this.menuInstance._closeOnDocumentClick = function() {
13976
			return false;
13977
		};
13978
13979
		// Selects often contain empty items, but never contain dividers
13980
		this.menuInstance._isDivider = function() {
13981
			return false;
13982
		};
13983
	},
13984
13985
	refresh: function() {
13986
		this._refreshMenu();
13987
		this.buttonItem.replaceWith(
13988
			this.buttonItem = this._renderButtonItem(
13989
13990
				// Fall back to an empty object in case there are no options
13991
				this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
13992
			)
13993
		);
13994
		if ( this.options.width === null ) {
13995
			this._resizeButton();
13996
		}
13997
	},
13998
13999
	_refreshMenu: function() {
14000
		var item,
14001
			options = this.element.find( "option" );
14002
14003
		this.menu.empty();
14004
14005
		this._parseOptions( options );
14006
		this._renderMenu( this.menu, this.items );
14007
14008
		this.menuInstance.refresh();
14009
		this.menuItems = this.menu.find( "li" )
14010
			.not( ".ui-selectmenu-optgroup" )
14011
				.find( ".ui-menu-item-wrapper" );
14012
14013
		this._rendered = true;
14014
14015
		if ( !options.length ) {
14016
			return;
14017
		}
14018
14019
		item = this._getSelectedItem();
14020
14021
		// Update the menu to have the correct item focused
14022
		this.menuInstance.focus( null, item );
14023
		this._setAria( item.data( "ui-selectmenu-item" ) );
14024
14025
		// Set disabled state
14026
		this._setOption( "disabled", this.element.prop( "disabled" ) );
14027
	},
14028
14029
	open: function( event ) {
14030
		if ( this.options.disabled ) {
14031
			return;
14032
		}
14033
14034
		// If this is the first time the menu is being opened, render the items
14035
		if ( !this._rendered ) {
14036
			this._refreshMenu();
14037
		} else {
14038
14039
			// Menu clears focus on close, reset focus to selected item
14040
			this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
14041
			this.menuInstance.focus( null, this._getSelectedItem() );
14042
		}
14043
14044
		// If there are no options, don't open the menu
14045
		if ( !this.menuItems.length ) {
14046
			return;
14047
		}
14048
14049
		this.isOpen = true;
14050
		this._toggleAttr();
14051
		this._resizeMenu();
14052
		this._position();
14053
14054
		this._on( this.document, this._documentClick );
14055
14056
		this._trigger( "open", event );
14057
	},
14058
14059
	_position: function() {
14060
		this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
14061
	},
14062
14063
	close: function( event ) {
14064
		if ( !this.isOpen ) {
14065
			return;
14066
		}
14067
14068
		this.isOpen = false;
14069
		this._toggleAttr();
14070
14071
		this.range = null;
14072
		this._off( this.document );
14073
14074
		this._trigger( "close", event );
14075
	},
14076
14077
	widget: function() {
14078
		return this.button;
14079
	},
14080
14081
	menuWidget: function() {
14082
		return this.menu;
14083
	},
14084
14085
	_renderButtonItem: function( item ) {
14086
		var buttonItem = $( "<span>" );
14087
14088
		this._setText( buttonItem, item.label );
14089
		this._addClass( buttonItem, "ui-selectmenu-text" );
14090
14091
		return buttonItem;
14092
	},
14093
14094
	_renderMenu: function( ul, items ) {
14095
		var that = this,
14096
			currentOptgroup = "";
14097
14098
		$.each( items, function( index, item ) {
14099
			var li;
14100
14101
			if ( item.optgroup !== currentOptgroup ) {
14102
				li = $( "<li>", {
14103
					text: item.optgroup
14104
				} );
14105
				that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
14106
					( item.element.parent( "optgroup" ).prop( "disabled" ) ?
14107
						" ui-state-disabled" :
14108
						"" ) );
14109
14110
				li.appendTo( ul );
14111
14112
				currentOptgroup = item.optgroup;
14113
			}
14114
14115
			that._renderItemData( ul, item );
14116
		} );
14117
	},
14118
14119
	_renderItemData: function( ul, item ) {
14120
		return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
14121
	},
14122
14123
	_renderItem: function( ul, item ) {
14124
		var li = $( "<li>" ),
14125
			wrapper = $( "<div>", {
14126
				title: item.element.attr( "title" )
14127
			} );
14128
14129
		if ( item.disabled ) {
14130
			this._addClass( li, null, "ui-state-disabled" );
14131
		}
14132
		this._setText( wrapper, item.label );
14133
14134
		return li.append( wrapper ).appendTo( ul );
14135
	},
14136
14137
	_setText: function( element, value ) {
14138
		if ( value ) {
14139
			element.text( value );
14140
		} else {
14141
			element.html( "&#160;" );
14142
		}
14143
	},
14144
14145
	_move: function( direction, event ) {
14146
		var item, next,
14147
			filter = ".ui-menu-item";
14148
14149
		if ( this.isOpen ) {
14150
			item = this.menuItems.eq( this.focusIndex ).parent( "li" );
14151
		} else {
14152
			item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
14153
			filter += ":not(.ui-state-disabled)";
14154
		}
14155
14156
		if ( direction === "first" || direction === "last" ) {
14157
			next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
14158
		} else {
14159
			next = item[ direction + "All" ]( filter ).eq( 0 );
14160
		}
14161
14162
		if ( next.length ) {
14163
			this.menuInstance.focus( event, next );
14164
		}
14165
	},
14166
14167
	_getSelectedItem: function() {
14168
		return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
14169
	},
14170
14171
	_toggle: function( event ) {
14172
		this[ this.isOpen ? "close" : "open" ]( event );
14173
	},
14174
14175
	_setSelection: function() {
14176
		var selection;
14177
14178
		if ( !this.range ) {
14179
			return;
14180
		}
14181
14182
		if ( window.getSelection ) {
14183
			selection = window.getSelection();
14184
			selection.removeAllRanges();
14185
			selection.addRange( this.range );
14186
14187
		// Support: IE8
14188
		} else {
14189
			this.range.select();
14190
		}
14191
14192
		// Support: IE
14193
		// Setting the text selection kills the button focus in IE, but
14194
		// restoring the focus doesn't kill the selection.
14195
		this.button.focus();
14196
	},
14197
14198
	_documentClick: {
14199
		mousedown: function( event ) {
14200
			if ( !this.isOpen ) {
14201
				return;
14202
			}
14203
14204
			if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
14205
					$.ui.escapeSelector( this.ids.button ) ).length ) {
14206
				this.close( event );
14207
			}
14208
		}
14209
	},
14210
14211
	_buttonEvents: {
14212
14213
		// Prevent text selection from being reset when interacting with the selectmenu (#10144)
14214
		mousedown: function() {
14215
			var selection;
14216
14217
			if ( window.getSelection ) {
14218
				selection = window.getSelection();
14219
				if ( selection.rangeCount ) {
14220
					this.range = selection.getRangeAt( 0 );
14221
				}
14222
14223
			// Support: IE8
14224
			} else {
14225
				this.range = document.selection.createRange();
14226
			}
14227
		},
14228
14229
		click: function( event ) {
14230
			this._setSelection();
14231
			this._toggle( event );
14232
		},
14233
14234
		keydown: function( event ) {
14235
			var preventDefault = true;
14236
			switch ( event.keyCode ) {
14237
			case $.ui.keyCode.TAB:
14238
			case $.ui.keyCode.ESCAPE:
14239
				this.close( event );
14240
				preventDefault = false;
14241
				break;
14242
			case $.ui.keyCode.ENTER:
14243
				if ( this.isOpen ) {
14244
					this._selectFocusedItem( event );
14245
				}
14246
				break;
14247
			case $.ui.keyCode.UP:
14248
				if ( event.altKey ) {
14249
					this._toggle( event );
14250
				} else {
14251
					this._move( "prev", event );
14252
				}
14253
				break;
14254
			case $.ui.keyCode.DOWN:
14255
				if ( event.altKey ) {
14256
					this._toggle( event );
14257
				} else {
14258
					this._move( "next", event );
14259
				}
14260
				break;
14261
			case $.ui.keyCode.SPACE:
14262
				if ( this.isOpen ) {
14263
					this._selectFocusedItem( event );
14264
				} else {
14265
					this._toggle( event );
14266
				}
14267
				break;
14268
			case $.ui.keyCode.LEFT:
14269
				this._move( "prev", event );
14270
				break;
14271
			case $.ui.keyCode.RIGHT:
14272
				this._move( "next", event );
14273
				break;
14274
			case $.ui.keyCode.HOME:
14275
			case $.ui.keyCode.PAGE_UP:
14276
				this._move( "first", event );
14277
				break;
14278
			case $.ui.keyCode.END:
14279
			case $.ui.keyCode.PAGE_DOWN:
14280
				this._move( "last", event );
14281
				break;
14282
			default:
14283
				this.menu.trigger( event );
14284
				preventDefault = false;
14285
			}
14286
14287
			if ( preventDefault ) {
14288
				event.preventDefault();
14289
			}
14290
		}
14291
	},
14292
14293
	_selectFocusedItem: function( event ) {
14294
		var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
14295
		if ( !item.hasClass( "ui-state-disabled" ) ) {
14296
			this._select( item.data( "ui-selectmenu-item" ), event );
14297
		}
14298
	},
14299
14300
	_select: function( item, event ) {
14301
		var oldIndex = this.element[ 0 ].selectedIndex;
14302
14303
		// Change native select element
14304
		this.element[ 0 ].selectedIndex = item.index;
14305
		this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
14306
		this._setAria( item );
14307
		this._trigger( "select", event, { item: item } );
14308
14309
		if ( item.index !== oldIndex ) {
14310
			this._trigger( "change", event, { item: item } );
14311
		}
14312
14313
		this.close( event );
14314
	},
14315
14316
	_setAria: function( item ) {
14317
		var id = this.menuItems.eq( item.index ).attr( "id" );
14318
14319
		this.button.attr( {
14320
			"aria-labelledby": id,
14321
			"aria-activedescendant": id
14322
		} );
14323
		this.menu.attr( "aria-activedescendant", id );
14324
	},
14325
14326
	_setOption: function( key, value ) {
14327
		if ( key === "icons" ) {
14328
			var icon = this.button.find( "span.ui-icon" );
14329
			this._removeClass( icon, null, this.options.icons.button )
14330
				._addClass( icon, null, value.button );
14331
		}
14332
14333
		this._super( key, value );
14334
14335
		if ( key === "appendTo" ) {
14336
			this.menuWrap.appendTo( this._appendTo() );
14337
		}
14338
14339
		if ( key === "width" ) {
14340
			this._resizeButton();
14341
		}
14342
	},
14343
14344
	_setOptionDisabled: function( value ) {
14345
		this._super( value );
14346
14347
		this.menuInstance.option( "disabled", value );
14348
		this.button.attr( "aria-disabled", value );
14349
		this._toggleClass( this.button, null, "ui-state-disabled", value );
14350
14351
		this.element.prop( "disabled", value );
14352
		if ( value ) {
14353
			this.button.attr( "tabindex", -1 );
14354
			this.close();
14355
		} else {
14356
			this.button.attr( "tabindex", 0 );
14357
		}
14358
	},
14359
14360
	_appendTo: function() {
14361
		var element = this.options.appendTo;
14362
14363
		if ( element ) {
14364
			element = element.jquery || element.nodeType ?
14365
				$( element ) :
14366
				this.document.find( element ).eq( 0 );
14367
		}
14368
14369
		if ( !element || !element[ 0 ] ) {
14370
			element = this.element.closest( ".ui-front, dialog" );
14371
		}
14372
14373
		if ( !element.length ) {
14374
			element = this.document[ 0 ].body;
14375
		}
14376
14377
		return element;
14378
	},
14379
14380
	_toggleAttr: function() {
14381
		this.button.attr( "aria-expanded", this.isOpen );
14382
14383
		// We can't use two _toggleClass() calls here, because we need to make sure
14384
		// we always remove classes first and add them second, otherwise if both classes have the
14385
		// same theme class, it will be removed after we add it.
14386
		this._removeClass( this.button, "ui-selectmenu-button-" +
14387
			( this.isOpen ? "closed" : "open" ) )
14388
			._addClass( this.button, "ui-selectmenu-button-" +
14389
				( this.isOpen ? "open" : "closed" ) )
14390
			._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
14391
14392
		this.menu.attr( "aria-hidden", !this.isOpen );
14393
	},
14394
14395
	_resizeButton: function() {
14396
		var width = this.options.width;
14397
14398
		// For `width: false`, just remove inline style and stop
14399
		if ( width === false ) {
14400
			this.button.css( "width", "" );
14401
			return;
14402
		}
14403
14404
		// For `width: null`, match the width of the original element
14405
		if ( width === null ) {
14406
			width = this.element.show().outerWidth();
14407
			this.element.hide();
14408
		}
14409
14410
		this.button.outerWidth( width );
14411
	},
14412
14413
	_resizeMenu: function() {
14414
		this.menu.outerWidth( Math.max(
14415
			this.button.outerWidth(),
14416
14417
			// Support: IE10
14418
			// IE10 wraps long text (possibly a rounding bug)
14419
			// so we add 1px to avoid the wrapping
14420
			this.menu.width( "" ).outerWidth() + 1
14421
		) );
14422
	},
14423
14424
	_getCreateOptions: function() {
14425
		var options = this._super();
14426
14427
		options.disabled = this.element.prop( "disabled" );
14428
14429
		return options;
14430
	},
14431
14432
	_parseOptions: function( options ) {
14433
		var that = this,
14434
			data = [];
14435
		options.each( function( index, item ) {
14436
			data.push( that._parseOption( $( item ), index ) );
14437
		} );
14438
		this.items = data;
14439
	},
14440
14441
	_parseOption: function( option, index ) {
14442
		var optgroup = option.parent( "optgroup" );
14443
14444
		return {
14445
			element: option,
14446
			index: index,
14447
			value: option.val(),
14448
			label: option.text(),
14449
			optgroup: optgroup.attr( "label" ) || "",
14450
			disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
14451
		};
14452
	},
14453
14454
	_destroy: function() {
14455
		this._unbindFormResetHandler();
14456
		this.menuWrap.remove();
14457
		this.button.remove();
14458
		this.element.show();
14459
		this.element.removeUniqueId();
14460
		this.labels.attr( "for", this.ids.element );
14461
	}
14462
} ] );
14463
14464
14465
/*!
14466
 * jQuery UI Slider 1.12.1
14467
 * http://jqueryui.com
14468
 *
14469
 * Copyright jQuery Foundation and other contributors
14470
 * Released under the MIT license.
14471
 * http://jquery.org/license
14472
 */
14473
14474
//>>label: Slider
14475
//>>group: Widgets
14476
//>>description: Displays a flexible slider with ranges and accessibility via keyboard.
14477
//>>docs: http://api.jqueryui.com/slider/
14478
//>>demos: http://jqueryui.com/slider/
14479
//>>css.structure: ../../themes/base/core.css
14480
//>>css.structure: ../../themes/base/slider.css
14481
//>>css.theme: ../../themes/base/theme.css
14482
14483
14484
14485
var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
0 ignored issues
show
Unused Code introduced by
The variable widgetsSlider seems to be never used. Consider removing it.
Loading history...
14486
	version: "1.12.1",
14487
	widgetEventPrefix: "slide",
14488
14489
	options: {
14490
		animate: false,
14491
		classes: {
14492
			"ui-slider": "ui-corner-all",
14493
			"ui-slider-handle": "ui-corner-all",
14494
14495
			// Note: ui-widget-header isn't the most fittingly semantic framework class for this
14496
			// element, but worked best visually with a variety of themes
14497
			"ui-slider-range": "ui-corner-all ui-widget-header"
14498
		},
14499
		distance: 0,
14500
		max: 100,
14501
		min: 0,
14502
		orientation: "horizontal",
14503
		range: false,
14504
		step: 1,
14505
		value: 0,
14506
		values: null,
14507
14508
		// Callbacks
14509
		change: null,
14510
		slide: null,
14511
		start: null,
14512
		stop: null
14513
	},
14514
14515
	// Number of pages in a slider
14516
	// (how many times can you page up/down to go through the whole range)
14517
	numPages: 5,
14518
14519
	_create: function() {
14520
		this._keySliding = false;
14521
		this._mouseSliding = false;
14522
		this._animateOff = true;
14523
		this._handleIndex = null;
14524
		this._detectOrientation();
14525
		this._mouseInit();
14526
		this._calculateNewMax();
14527
14528
		this._addClass( "ui-slider ui-slider-" + this.orientation,
14529
			"ui-widget ui-widget-content" );
14530
14531
		this._refresh();
14532
14533
		this._animateOff = false;
14534
	},
14535
14536
	_refresh: function() {
14537
		this._createRange();
14538
		this._createHandles();
14539
		this._setupEvents();
14540
		this._refreshValue();
14541
	},
14542
14543
	_createHandles: function() {
14544
		var i, handleCount,
14545
			options = this.options,
14546
			existingHandles = this.element.find( ".ui-slider-handle" ),
14547
			handle = "<span tabindex='0'></span>",
14548
			handles = [];
14549
14550
		handleCount = ( options.values && options.values.length ) || 1;
14551
14552
		if ( existingHandles.length > handleCount ) {
14553
			existingHandles.slice( handleCount ).remove();
14554
			existingHandles = existingHandles.slice( 0, handleCount );
14555
		}
14556
14557
		for ( i = existingHandles.length; i < handleCount; i++ ) {
14558
			handles.push( handle );
14559
		}
14560
14561
		this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
14562
14563
		this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
14564
14565
		this.handle = this.handles.eq( 0 );
14566
14567
		this.handles.each( function( i ) {
14568
			$( this )
14569
				.data( "ui-slider-handle-index", i )
14570
				.attr( "tabIndex", 0 );
14571
		} );
14572
	},
14573
14574
	_createRange: function() {
14575
		var options = this.options;
14576
14577
		if ( options.range ) {
14578
			if ( options.range === true ) {
14579
				if ( !options.values ) {
14580
					options.values = [ this._valueMin(), this._valueMin() ];
14581
				} else if ( options.values.length && options.values.length !== 2 ) {
14582
					options.values = [ options.values[ 0 ], options.values[ 0 ] ];
14583
				} else if ( $.isArray( options.values ) ) {
14584
					options.values = options.values.slice( 0 );
14585
				}
14586
			}
14587
14588
			if ( !this.range || !this.range.length ) {
14589
				this.range = $( "<div>" )
14590
					.appendTo( this.element );
14591
14592
				this._addClass( this.range, "ui-slider-range" );
14593
			} else {
14594
				this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
14595
14596
				// Handle range switching from true to min/max
14597
				this.range.css( {
14598
					"left": "",
14599
					"bottom": ""
14600
				} );
14601
			}
14602
			if ( options.range === "min" || options.range === "max" ) {
14603
				this._addClass( this.range, "ui-slider-range-" + options.range );
14604
			}
14605
		} else {
14606
			if ( this.range ) {
14607
				this.range.remove();
14608
			}
14609
			this.range = null;
14610
		}
14611
	},
14612
14613
	_setupEvents: function() {
14614
		this._off( this.handles );
14615
		this._on( this.handles, this._handleEvents );
14616
		this._hoverable( this.handles );
14617
		this._focusable( this.handles );
14618
	},
14619
14620
	_destroy: function() {
14621
		this.handles.remove();
14622
		if ( this.range ) {
14623
			this.range.remove();
14624
		}
14625
14626
		this._mouseDestroy();
14627
	},
14628
14629
	_mouseCapture: function( event ) {
14630
		var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
14631
			that = this,
14632
			o = this.options;
14633
14634
		if ( o.disabled ) {
14635
			return false;
14636
		}
14637
14638
		this.elementSize = {
14639
			width: this.element.outerWidth(),
14640
			height: this.element.outerHeight()
14641
		};
14642
		this.elementOffset = this.element.offset();
14643
14644
		position = { x: event.pageX, y: event.pageY };
14645
		normValue = this._normValueFromMouse( position );
14646
		distance = this._valueMax() - this._valueMin() + 1;
14647
		this.handles.each( function( i ) {
14648
			var thisDistance = Math.abs( normValue - that.values( i ) );
14649
			if ( ( distance > thisDistance ) ||
14650
				( distance === thisDistance &&
14651
					( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
14652
				distance = thisDistance;
14653
				closestHandle = $( this );
14654
				index = i;
14655
			}
14656
		} );
14657
14658
		allowed = this._start( event, index );
14659
		if ( allowed === false ) {
14660
			return false;
14661
		}
14662
		this._mouseSliding = true;
14663
14664
		this._handleIndex = index;
14665
14666
		this._addClass( closestHandle, null, "ui-state-active" );
14667
		closestHandle.trigger( "focus" );
14668
14669
		offset = closestHandle.offset();
14670
		mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
14671
		this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
14672
			left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
14673
			top: event.pageY - offset.top -
14674
				( closestHandle.height() / 2 ) -
14675
				( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
14676
				( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
14677
				( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
14678
		};
14679
14680
		if ( !this.handles.hasClass( "ui-state-hover" ) ) {
14681
			this._slide( event, index, normValue );
14682
		}
14683
		this._animateOff = true;
14684
		return true;
14685
	},
14686
14687
	_mouseStart: function() {
14688
		return true;
14689
	},
14690
14691
	_mouseDrag: function( event ) {
14692
		var position = { x: event.pageX, y: event.pageY },
14693
			normValue = this._normValueFromMouse( position );
14694
14695
		this._slide( event, this._handleIndex, normValue );
14696
14697
		return false;
14698
	},
14699
14700
	_mouseStop: function( event ) {
14701
		this._removeClass( this.handles, null, "ui-state-active" );
14702
		this._mouseSliding = false;
14703
14704
		this._stop( event, this._handleIndex );
14705
		this._change( event, this._handleIndex );
14706
14707
		this._handleIndex = null;
14708
		this._clickOffset = null;
14709
		this._animateOff = false;
14710
14711
		return false;
14712
	},
14713
14714
	_detectOrientation: function() {
14715
		this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
14716
	},
14717
14718
	_normValueFromMouse: function( position ) {
14719
		var pixelTotal,
14720
			pixelMouse,
14721
			percentMouse,
14722
			valueTotal,
14723
			valueMouse;
14724
14725
		if ( this.orientation === "horizontal" ) {
14726
			pixelTotal = this.elementSize.width;
14727
			pixelMouse = position.x - this.elementOffset.left -
14728
				( this._clickOffset ? this._clickOffset.left : 0 );
14729
		} else {
14730
			pixelTotal = this.elementSize.height;
14731
			pixelMouse = position.y - this.elementOffset.top -
14732
				( this._clickOffset ? this._clickOffset.top : 0 );
14733
		}
14734
14735
		percentMouse = ( pixelMouse / pixelTotal );
14736
		if ( percentMouse > 1 ) {
14737
			percentMouse = 1;
14738
		}
14739
		if ( percentMouse < 0 ) {
14740
			percentMouse = 0;
14741
		}
14742
		if ( this.orientation === "vertical" ) {
14743
			percentMouse = 1 - percentMouse;
14744
		}
14745
14746
		valueTotal = this._valueMax() - this._valueMin();
14747
		valueMouse = this._valueMin() + percentMouse * valueTotal;
14748
14749
		return this._trimAlignValue( valueMouse );
14750
	},
14751
14752
	_uiHash: function( index, value, values ) {
14753
		var uiHash = {
14754
			handle: this.handles[ index ],
14755
			handleIndex: index,
14756
			value: value !== undefined ? value : this.value()
14757
		};
14758
14759
		if ( this._hasMultipleValues() ) {
14760
			uiHash.value = value !== undefined ? value : this.values( index );
14761
			uiHash.values = values || this.values();
14762
		}
14763
14764
		return uiHash;
14765
	},
14766
14767
	_hasMultipleValues: function() {
14768
		return this.options.values && this.options.values.length;
14769
	},
14770
14771
	_start: function( event, index ) {
14772
		return this._trigger( "start", event, this._uiHash( index ) );
14773
	},
14774
14775
	_slide: function( event, index, newVal ) {
14776
		var allowed, otherVal,
14777
			currentValue = this.value(),
14778
			newValues = this.values();
14779
14780
		if ( this._hasMultipleValues() ) {
14781
			otherVal = this.values( index ? 0 : 1 );
14782
			currentValue = this.values( index );
14783
14784
			if ( this.options.values.length === 2 && this.options.range === true ) {
14785
				newVal =  index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
14786
			}
14787
14788
			newValues[ index ] = newVal;
14789
		}
14790
14791
		if ( newVal === currentValue ) {
14792
			return;
14793
		}
14794
14795
		allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
14796
14797
		// A slide can be canceled by returning false from the slide callback
14798
		if ( allowed === false ) {
14799
			return;
14800
		}
14801
14802
		if ( this._hasMultipleValues() ) {
14803
			this.values( index, newVal );
14804
		} else {
14805
			this.value( newVal );
14806
		}
14807
	},
14808
14809
	_stop: function( event, index ) {
14810
		this._trigger( "stop", event, this._uiHash( index ) );
14811
	},
14812
14813
	_change: function( event, index ) {
14814
		if ( !this._keySliding && !this._mouseSliding ) {
14815
14816
			//store the last changed value index for reference when handles overlap
14817
			this._lastChangedValue = index;
14818
			this._trigger( "change", event, this._uiHash( index ) );
14819
		}
14820
	},
14821
14822
	value: function( newValue ) {
14823
		if ( arguments.length ) {
14824
			this.options.value = this._trimAlignValue( newValue );
14825
			this._refreshValue();
14826
			this._change( null, 0 );
14827
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
14828
		}
14829
14830
		return this._value();
14831
	},
14832
14833
	values: function( index, newValue ) {
14834
		var vals,
14835
			newValues,
14836
			i;
14837
14838
		if ( arguments.length > 1 ) {
14839
			this.options.values[ index ] = this._trimAlignValue( newValue );
14840
			this._refreshValue();
14841
			this._change( null, index );
14842
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
14843
		}
14844
14845
		if ( arguments.length ) {
14846
			if ( $.isArray( arguments[ 0 ] ) ) {
14847
				vals = this.options.values;
14848
				newValues = arguments[ 0 ];
14849
				for ( i = 0; i < vals.length; i += 1 ) {
14850
					vals[ i ] = this._trimAlignValue( newValues[ i ] );
14851
					this._change( null, i );
14852
				}
14853
				this._refreshValue();
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
14854
			} else {
14855
				if ( this._hasMultipleValues() ) {
14856
					return this._values( index );
14857
				} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
14858
					return this.value();
14859
				}
14860
			}
14861
		} else {
14862
			return this._values();
14863
		}
14864
	},
14865
14866
	_setOption: function( key, value ) {
14867
		var i,
14868
			valsLength = 0;
14869
14870
		if ( key === "range" && this.options.range === true ) {
14871
			if ( value === "min" ) {
14872
				this.options.value = this._values( 0 );
14873
				this.options.values = null;
14874
			} else if ( value === "max" ) {
14875
				this.options.value = this._values( this.options.values.length - 1 );
14876
				this.options.values = null;
14877
			}
14878
		}
14879
14880
		if ( $.isArray( this.options.values ) ) {
14881
			valsLength = this.options.values.length;
14882
		}
14883
14884
		this._super( key, value );
14885
14886
		switch ( key ) {
14887
			case "orientation":
14888
				this._detectOrientation();
14889
				this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
14890
					._addClass( "ui-slider-" + this.orientation );
14891
				this._refreshValue();
14892
				if ( this.options.range ) {
14893
					this._refreshRange( value );
14894
				}
14895
14896
				// Reset positioning from previous orientation
14897
				this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
14898
				break;
14899
			case "value":
14900
				this._animateOff = true;
14901
				this._refreshValue();
14902
				this._change( null, 0 );
14903
				this._animateOff = false;
14904
				break;
14905
			case "values":
14906
				this._animateOff = true;
14907
				this._refreshValue();
14908
14909
				// Start from the last handle to prevent unreachable handles (#9046)
14910
				for ( i = valsLength - 1; i >= 0; i-- ) {
14911
					this._change( null, i );
14912
				}
14913
				this._animateOff = false;
14914
				break;
14915
			case "step":
14916
			case "min":
14917
			case "max":
14918
				this._animateOff = true;
14919
				this._calculateNewMax();
14920
				this._refreshValue();
14921
				this._animateOff = false;
14922
				break;
14923
			case "range":
14924
				this._animateOff = true;
14925
				this._refresh();
14926
				this._animateOff = false;
14927
				break;
14928
		}
14929
	},
14930
14931
	_setOptionDisabled: function( value ) {
14932
		this._super( value );
14933
14934
		this._toggleClass( null, "ui-state-disabled", !!value );
14935
	},
14936
14937
	//internal value getter
14938
	// _value() returns value trimmed by min and max, aligned by step
14939
	_value: function() {
14940
		var val = this.options.value;
14941
		val = this._trimAlignValue( val );
14942
14943
		return val;
14944
	},
14945
14946
	//internal values getter
14947
	// _values() returns array of values trimmed by min and max, aligned by step
14948
	// _values( index ) returns single value trimmed by min and max, aligned by step
14949
	_values: function( index ) {
14950
		var val,
14951
			vals,
14952
			i;
14953
14954
		if ( arguments.length ) {
14955
			val = this.options.values[ index ];
14956
			val = this._trimAlignValue( val );
14957
14958
			return val;
14959
		} else if ( this._hasMultipleValues() ) {
14960
14961
			// .slice() creates a copy of the array
14962
			// this copy gets trimmed by min and max and then returned
14963
			vals = this.options.values.slice();
14964
			for ( i = 0; i < vals.length; i += 1 ) {
14965
				vals[ i ] = this._trimAlignValue( vals[ i ] );
14966
			}
14967
14968
			return vals;
14969
		} else {
14970
			return [];
14971
		}
14972
	},
14973
14974
	// Returns the step-aligned value that val is closest to, between (inclusive) min and max
14975
	_trimAlignValue: function( val ) {
14976
		if ( val <= this._valueMin() ) {
14977
			return this._valueMin();
14978
		}
14979
		if ( val >= this._valueMax() ) {
14980
			return this._valueMax();
14981
		}
14982
		var step = ( this.options.step > 0 ) ? this.options.step : 1,
14983
			valModStep = ( val - this._valueMin() ) % step,
14984
			alignValue = val - valModStep;
14985
14986
		if ( Math.abs( valModStep ) * 2 >= step ) {
14987
			alignValue += ( valModStep > 0 ) ? step : ( -step );
14988
		}
14989
14990
		// Since JavaScript has problems with large floats, round
14991
		// the final value to 5 digits after the decimal point (see #4124)
14992
		return parseFloat( alignValue.toFixed( 5 ) );
14993
	},
14994
14995
	_calculateNewMax: function() {
14996
		var max = this.options.max,
14997
			min = this._valueMin(),
14998
			step = this.options.step,
14999
			aboveMin = Math.round( ( max - min ) / step ) * step;
15000
		max = aboveMin + min;
15001
		if ( max > this.options.max ) {
15002
15003
			//If max is not divisible by step, rounding off may increase its value
15004
			max -= step;
15005
		}
15006
		this.max = parseFloat( max.toFixed( this._precision() ) );
15007
	},
15008
15009
	_precision: function() {
15010
		var precision = this._precisionOf( this.options.step );
15011
		if ( this.options.min !== null ) {
15012
			precision = Math.max( precision, this._precisionOf( this.options.min ) );
15013
		}
15014
		return precision;
15015
	},
15016
15017
	_precisionOf: function( num ) {
15018
		var str = num.toString(),
15019
			decimal = str.indexOf( "." );
15020
		return decimal === -1 ? 0 : str.length - decimal - 1;
15021
	},
15022
15023
	_valueMin: function() {
15024
		return this.options.min;
15025
	},
15026
15027
	_valueMax: function() {
15028
		return this.max;
15029
	},
15030
15031
	_refreshRange: function( orientation ) {
15032
		if ( orientation === "vertical" ) {
15033
			this.range.css( { "width": "", "left": "" } );
15034
		}
15035
		if ( orientation === "horizontal" ) {
15036
			this.range.css( { "height": "", "bottom": "" } );
15037
		}
15038
	},
15039
15040
	_refreshValue: function() {
15041
		var lastValPercent, valPercent, value, valueMin, valueMax,
15042
			oRange = this.options.range,
15043
			o = this.options,
15044
			that = this,
15045
			animate = ( !this._animateOff ) ? o.animate : false,
15046
			_set = {};
15047
15048
		if ( this._hasMultipleValues() ) {
15049
			this.handles.each( function( i ) {
15050
				valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
15051
					that._valueMin() ) * 100;
15052
				_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
15053
				$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
15054
				if ( that.options.range === true ) {
15055
					if ( that.orientation === "horizontal" ) {
15056
						if ( i === 0 ) {
15057
							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15058
								left: valPercent + "%"
15059
							}, o.animate );
15060
						}
15061
						if ( i === 1 ) {
15062
							that.range[ animate ? "animate" : "css" ]( {
15063
								width: ( valPercent - lastValPercent ) + "%"
15064
							}, {
15065
								queue: false,
15066
								duration: o.animate
15067
							} );
15068
						}
15069
					} else {
15070
						if ( i === 0 ) {
15071
							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15072
								bottom: ( valPercent ) + "%"
15073
							}, o.animate );
15074
						}
15075
						if ( i === 1 ) {
15076
							that.range[ animate ? "animate" : "css" ]( {
15077
								height: ( valPercent - lastValPercent ) + "%"
15078
							}, {
15079
								queue: false,
15080
								duration: o.animate
15081
							} );
15082
						}
15083
					}
15084
				}
15085
				lastValPercent = valPercent;
15086
			} );
15087
		} else {
15088
			value = this.value();
15089
			valueMin = this._valueMin();
15090
			valueMax = this._valueMax();
15091
			valPercent = ( valueMax !== valueMin ) ?
15092
					( value - valueMin ) / ( valueMax - valueMin ) * 100 :
15093
					0;
15094
			_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
15095
			this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
15096
15097
			if ( oRange === "min" && this.orientation === "horizontal" ) {
15098
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15099
					width: valPercent + "%"
15100
				}, o.animate );
15101
			}
15102
			if ( oRange === "max" && this.orientation === "horizontal" ) {
15103
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15104
					width: ( 100 - valPercent ) + "%"
15105
				}, o.animate );
15106
			}
15107
			if ( oRange === "min" && this.orientation === "vertical" ) {
15108
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15109
					height: valPercent + "%"
15110
				}, o.animate );
15111
			}
15112
			if ( oRange === "max" && this.orientation === "vertical" ) {
15113
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15114
					height: ( 100 - valPercent ) + "%"
15115
				}, o.animate );
15116
			}
15117
		}
15118
	},
15119
15120
	_handleEvents: {
15121 View Code Duplication
		keydown: function( event ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
15122
			var allowed, curVal, newVal, step,
15123
				index = $( event.target ).data( "ui-slider-handle-index" );
15124
15125
			switch ( event.keyCode ) {
15126
				case $.ui.keyCode.HOME:
15127
				case $.ui.keyCode.END:
15128
				case $.ui.keyCode.PAGE_UP:
15129
				case $.ui.keyCode.PAGE_DOWN:
15130
				case $.ui.keyCode.UP:
15131
				case $.ui.keyCode.RIGHT:
15132
				case $.ui.keyCode.DOWN:
15133
				case $.ui.keyCode.LEFT:
15134
					event.preventDefault();
15135
					if ( !this._keySliding ) {
15136
						this._keySliding = true;
15137
						this._addClass( $( event.target ), null, "ui-state-active" );
15138
						allowed = this._start( event, index );
15139
						if ( allowed === false ) {
15140
							return;
15141
						}
15142
					}
15143
					break;
15144
			}
15145
15146
			step = this.options.step;
15147
			if ( this._hasMultipleValues() ) {
15148
				curVal = newVal = this.values( index );
15149
			} else {
15150
				curVal = newVal = this.value();
15151
			}
15152
15153
			switch ( event.keyCode ) {
15154
				case $.ui.keyCode.HOME:
15155
					newVal = this._valueMin();
15156
					break;
15157
				case $.ui.keyCode.END:
15158
					newVal = this._valueMax();
15159
					break;
15160
				case $.ui.keyCode.PAGE_UP:
15161
					newVal = this._trimAlignValue(
15162
						curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
15163
					);
15164
					break;
15165
				case $.ui.keyCode.PAGE_DOWN:
15166
					newVal = this._trimAlignValue(
15167
						curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
15168
					break;
15169
				case $.ui.keyCode.UP:
15170
				case $.ui.keyCode.RIGHT:
15171
					if ( curVal === this._valueMax() ) {
15172
						return;
15173
					}
15174
					newVal = this._trimAlignValue( curVal + step );
15175
					break;
15176
				case $.ui.keyCode.DOWN:
15177
				case $.ui.keyCode.LEFT:
15178
					if ( curVal === this._valueMin() ) {
15179
						return;
15180
					}
15181
					newVal = this._trimAlignValue( curVal - step );
15182
					break;
15183
			}
15184
15185
			this._slide( event, index, newVal );
15186
		},
15187
		keyup: function( event ) {
15188
			var index = $( event.target ).data( "ui-slider-handle-index" );
15189
15190
			if ( this._keySliding ) {
15191
				this._keySliding = false;
15192
				this._stop( event, index );
15193
				this._change( event, index );
15194
				this._removeClass( $( event.target ), null, "ui-state-active" );
15195
			}
15196
		}
15197
	}
15198
} );
15199
15200
15201
/*!
15202
 * jQuery UI Sortable 1.12.1
15203
 * http://jqueryui.com
15204
 *
15205
 * Copyright jQuery Foundation and other contributors
15206
 * Released under the MIT license.
15207
 * http://jquery.org/license
15208
 */
15209
15210
//>>label: Sortable
15211
//>>group: Interactions
15212
//>>description: Enables items in a list to be sorted using the mouse.
15213
//>>docs: http://api.jqueryui.com/sortable/
15214
//>>demos: http://jqueryui.com/sortable/
15215
//>>css.structure: ../../themes/base/sortable.css
15216
15217
15218
15219
var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
0 ignored issues
show
Unused Code introduced by
The variable widgetsSortable seems to be never used. Consider removing it.
Loading history...
15220
	version: "1.12.1",
15221
	widgetEventPrefix: "sort",
15222
	ready: false,
15223
	options: {
15224
		appendTo: "parent",
15225
		axis: false,
15226
		connectWith: false,
15227
		containment: false,
15228
		cursor: "auto",
15229
		cursorAt: false,
15230
		dropOnEmpty: true,
15231
		forcePlaceholderSize: false,
15232
		forceHelperSize: false,
15233
		grid: false,
15234
		handle: false,
15235
		helper: "original",
15236
		items: "> *",
15237
		opacity: false,
15238
		placeholder: false,
15239
		revert: false,
15240
		scroll: true,
15241
		scrollSensitivity: 20,
15242
		scrollSpeed: 20,
15243
		scope: "default",
15244
		tolerance: "intersect",
15245
		zIndex: 1000,
15246
15247
		// Callbacks
15248
		activate: null,
15249
		beforeStop: null,
15250
		change: null,
15251
		deactivate: null,
15252
		out: null,
15253
		over: null,
15254
		receive: null,
15255
		remove: null,
15256
		sort: null,
15257
		start: null,
15258
		stop: null,
15259
		update: null
15260
	},
15261
15262
	_isOverAxis: function( x, reference, size ) {
15263
		return ( x >= reference ) && ( x < ( reference + size ) );
15264
	},
15265
15266
	_isFloating: function( item ) {
15267
		return ( /left|right/ ).test( item.css( "float" ) ) ||
15268
			( /inline|table-cell/ ).test( item.css( "display" ) );
15269
	},
15270
15271
	_create: function() {
15272
		this.containerCache = {};
15273
		this._addClass( "ui-sortable" );
15274
15275
		//Get the items
15276
		this.refresh();
15277
15278
		//Let's determine the parent's offset
15279
		this.offset = this.element.offset();
15280
15281
		//Initialize mouse events for interaction
15282
		this._mouseInit();
15283
15284
		this._setHandleClassName();
15285
15286
		//We're ready to go
15287
		this.ready = true;
15288
15289
	},
15290
15291
	_setOption: function( key, value ) {
15292
		this._super( key, value );
15293
15294
		if ( key === "handle" ) {
15295
			this._setHandleClassName();
15296
		}
15297
	},
15298
15299
	_setHandleClassName: function() {
15300
		var that = this;
15301
		this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
15302
		$.each( this.items, function() {
15303
			that._addClass(
15304
				this.instance.options.handle ?
15305
					this.item.find( this.instance.options.handle ) :
15306
					this.item,
15307
				"ui-sortable-handle"
15308
			);
15309
		} );
15310
	},
15311
15312
	_destroy: function() {
15313
		this._mouseDestroy();
15314
15315
		for ( var i = this.items.length - 1; i >= 0; i-- ) {
15316
			this.items[ i ].item.removeData( this.widgetName + "-item" );
15317
		}
15318
15319
		return this;
15320
	},
15321
15322
	_mouseCapture: function( event, overrideHandle ) {
15323
		var currentItem = null,
15324
			validHandle = false,
15325
			that = this;
15326
15327
		if ( this.reverting ) {
15328
			return false;
15329
		}
15330
15331
		if ( this.options.disabled || this.options.type === "static" ) {
15332
			return false;
15333
		}
15334
15335
		//We have to refresh the items data once first
15336
		this._refreshItems( event );
15337
15338
		//Find out if the clicked node (or one of its parents) is a actual item in this.items
15339
		$( event.target ).parents().each( function() {
15340
			if ( $.data( this, that.widgetName + "-item" ) === that ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $.data(this, that.widgetName + "-item") === that 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...
15341
				currentItem = $( this );
15342
				return false;
15343
			}
15344
		} );
15345
		if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
15346
			currentItem = $( event.target );
15347
		}
15348
15349
		if ( !currentItem ) {
15350
			return false;
15351
		}
15352
		if ( this.options.handle && !overrideHandle ) {
15353
			$( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
15354
				if ( this === event.target ) {
15355
					validHandle = true;
15356
				}
15357
			} );
15358
			if ( !validHandle ) {
15359
				return false;
15360
			}
15361
		}
15362
15363
		this.currentItem = currentItem;
15364
		this._removeCurrentsFromItems();
15365
		return true;
15366
15367
	},
15368
15369
	_mouseStart: function( event, overrideHandle, noActivation ) {
15370
15371
		var i, body,
15372
			o = this.options;
15373
15374
		this.currentContainer = this;
15375
15376
		//We only need to call refreshPositions, because the refreshItems call has been moved to
15377
		// mouseCapture
15378
		this.refreshPositions();
15379
15380
		//Create and append the visible helper
15381
		this.helper = this._createHelper( event );
15382
15383
		//Cache the helper size
15384
		this._cacheHelperProportions();
15385
15386
		/*
15387
		 * - Position generation -
15388
		 * This block generates everything position related - it's the core of draggables.
15389
		 */
15390
15391
		//Cache the margins of the original element
15392
		this._cacheMargins();
15393
15394
		//Get the next scrolling parent
15395
		this.scrollParent = this.helper.scrollParent();
15396
15397
		//The element's absolute position on the page minus margins
15398
		this.offset = this.currentItem.offset();
15399
		this.offset = {
15400
			top: this.offset.top - this.margins.top,
15401
			left: this.offset.left - this.margins.left
15402
		};
15403
15404
		$.extend( this.offset, {
15405
			click: { //Where the click happened, relative to the element
15406
				left: event.pageX - this.offset.left,
15407
				top: event.pageY - this.offset.top
15408
			},
15409
			parent: this._getParentOffset(),
15410
15411
			// This is a relative to absolute position minus the actual position calculation -
15412
			// only used for relative positioned helper
15413
			relative: this._getRelativeOffset()
15414
		} );
15415
15416
		// Only after we got the offset, we can change the helper's position to absolute
15417
		// TODO: Still need to figure out a way to make relative sorting possible
15418
		this.helper.css( "position", "absolute" );
15419
		this.cssPosition = this.helper.css( "position" );
15420
15421
		//Generate the original position
15422
		this.originalPosition = this._generatePosition( event );
15423
		this.originalPageX = event.pageX;
15424
		this.originalPageY = event.pageY;
15425
15426
		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
15427
		( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
15428
15429
		//Cache the former DOM position
15430
		this.domPosition = {
15431
			prev: this.currentItem.prev()[ 0 ],
15432
			parent: this.currentItem.parent()[ 0 ]
15433
		};
15434
15435
		// If the helper is not the original, hide the original so it's not playing any role during
15436
		// the drag, won't cause anything bad this way
15437
		if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
15438
			this.currentItem.hide();
15439
		}
15440
15441
		//Create the placeholder
15442
		this._createPlaceholder();
15443
15444
		//Set a containment if given in the options
15445
		if ( o.containment ) {
15446
			this._setContainment();
15447
		}
15448
15449
		if ( o.cursor && o.cursor !== "auto" ) { // cursor option
15450
			body = this.document.find( "body" );
15451
15452
			// Support: IE
15453
			this.storedCursor = body.css( "cursor" );
15454
			body.css( "cursor", o.cursor );
15455
15456
			this.storedStylesheet =
15457
				$( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
15458
		}
15459
15460
		if ( o.opacity ) { // opacity option
15461
			if ( this.helper.css( "opacity" ) ) {
15462
				this._storedOpacity = this.helper.css( "opacity" );
15463
			}
15464
			this.helper.css( "opacity", o.opacity );
15465
		}
15466
15467
		if ( o.zIndex ) { // zIndex option
15468
			if ( this.helper.css( "zIndex" ) ) {
15469
				this._storedZIndex = this.helper.css( "zIndex" );
15470
			}
15471
			this.helper.css( "zIndex", o.zIndex );
15472
		}
15473
15474
		//Prepare scrolling
15475
		if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
15476
				this.scrollParent[ 0 ].tagName !== "HTML" ) {
15477
			this.overflowOffset = this.scrollParent.offset();
15478
		}
15479
15480
		//Call callbacks
15481
		this._trigger( "start", event, this._uiHash() );
15482
15483
		//Recache the helper size
15484
		if ( !this._preserveHelperProportions ) {
15485
			this._cacheHelperProportions();
15486
		}
15487
15488
		//Post "activate" events to possible containers
15489
		if ( !noActivation ) {
15490
			for ( i = this.containers.length - 1; i >= 0; i-- ) {
15491
				this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
15492
			}
15493
		}
15494
15495
		//Prepare possible droppables
15496
		if ( $.ui.ddmanager ) {
15497
			$.ui.ddmanager.current = this;
15498
		}
15499
15500
		if ( $.ui.ddmanager && !o.dropBehaviour ) {
15501
			$.ui.ddmanager.prepareOffsets( this, event );
15502
		}
15503
15504
		this.dragging = true;
15505
15506
		this._addClass( this.helper, "ui-sortable-helper" );
15507
15508
		// Execute the drag once - this causes the helper not to be visiblebefore getting its
15509
		// correct position
15510
		this._mouseDrag( event );
15511
		return true;
15512
15513
	},
15514
15515
	_mouseDrag: function( event ) {
15516
		var i, item, itemElement, intersection,
15517
			o = this.options,
15518
			scrolled = false;
15519
15520
		//Compute the helpers position
15521
		this.position = this._generatePosition( event );
15522
		this.positionAbs = this._convertPositionTo( "absolute" );
15523
15524
		if ( !this.lastPositionAbs ) {
15525
			this.lastPositionAbs = this.positionAbs;
15526
		}
15527
15528
		//Do scrolling
15529
		if ( this.options.scroll ) {
15530
			if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
15531
					this.scrollParent[ 0 ].tagName !== "HTML" ) {
15532
15533
				if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
15534
						event.pageY < o.scrollSensitivity ) {
15535
					this.scrollParent[ 0 ].scrollTop =
15536
						scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
15537
				} else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
15538
					this.scrollParent[ 0 ].scrollTop =
15539
						scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
15540
				}
15541
15542
				if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
15543
						event.pageX < o.scrollSensitivity ) {
15544
					this.scrollParent[ 0 ].scrollLeft = scrolled =
15545
						this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
15546
				} else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
15547
					this.scrollParent[ 0 ].scrollLeft = scrolled =
15548
						this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
15549
				}
15550
15551
			} else {
15552
15553
				if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
15554
					scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
15555
				} else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
15556
						o.scrollSensitivity ) {
15557
					scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
15558
				}
15559
15560
				if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
15561
					scrolled = this.document.scrollLeft(
15562
						this.document.scrollLeft() - o.scrollSpeed
15563
					);
15564
				} else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
15565
						o.scrollSensitivity ) {
15566
					scrolled = this.document.scrollLeft(
15567
						this.document.scrollLeft() + o.scrollSpeed
15568
					);
15569
				}
15570
15571
			}
15572
15573
			if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
15574
				$.ui.ddmanager.prepareOffsets( this, event );
15575
			}
15576
		}
15577
15578
		//Regenerate the absolute position used for position checks
15579
		this.positionAbs = this._convertPositionTo( "absolute" );
15580
15581
		//Set the helper position
15582
		if ( !this.options.axis || this.options.axis !== "y" ) {
15583
			this.helper[ 0 ].style.left = this.position.left + "px";
15584
		}
15585
		if ( !this.options.axis || this.options.axis !== "x" ) {
15586
			this.helper[ 0 ].style.top = this.position.top + "px";
15587
		}
15588
15589
		//Rearrange
15590
		for ( i = this.items.length - 1; i >= 0; i-- ) {
15591
15592
			//Cache variables and intersection, continue if no intersection
15593
			item = this.items[ i ];
15594
			itemElement = item.item[ 0 ];
15595
			intersection = this._intersectsWithPointer( item );
15596
			if ( !intersection ) {
15597
				continue;
15598
			}
15599
15600
			// Only put the placeholder inside the current Container, skip all
15601
			// items from other containers. This works because when moving
15602
			// an item from one container to another the
15603
			// currentContainer is switched before the placeholder is moved.
15604
			//
15605
			// Without this, moving items in "sub-sortables" can cause
15606
			// the placeholder to jitter between the outer and inner container.
15607
			if ( item.instance !== this.currentContainer ) {
15608
				continue;
15609
			}
15610
15611
			// Cannot intersect with itself
15612
			// no useless actions that have been done before
15613
			// no action if the item moved is the parent of the item checked
15614
			if ( itemElement !== this.currentItem[ 0 ] &&
15615
				this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
15616
				!$.contains( this.placeholder[ 0 ], itemElement ) &&
15617
				( this.options.type === "semi-dynamic" ?
15618
					!$.contains( this.element[ 0 ], itemElement ) :
15619
					true
15620
				)
15621
			) {
15622
15623
				this.direction = intersection === 1 ? "down" : "up";
15624
15625
				if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
15626
					this._rearrange( event, item );
15627
				} else {
15628
					break;
15629
				}
15630
15631
				this._trigger( "change", event, this._uiHash() );
15632
				break;
15633
			}
15634
		}
15635
15636
		//Post events to containers
15637
		this._contactContainers( event );
15638
15639
		//Interconnect with droppables
15640
		if ( $.ui.ddmanager ) {
15641
			$.ui.ddmanager.drag( this, event );
15642
		}
15643
15644
		//Call callbacks
15645
		this._trigger( "sort", event, this._uiHash() );
15646
15647
		this.lastPositionAbs = this.positionAbs;
15648
		return false;
15649
15650
	},
15651
15652
	_mouseStop: function( event, noPropagation ) {
15653
15654
		if ( !event ) {
15655
			return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
15656
		}
15657
15658
		//If we are using droppables, inform the manager about the drop
15659
		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
15660
			$.ui.ddmanager.drop( this, event );
15661
		}
15662
15663
		if ( this.options.revert ) {
15664
			var that = this,
15665
				cur = this.placeholder.offset(),
15666
				axis = this.options.axis,
15667
				animation = {};
15668
15669
			if ( !axis || axis === "x" ) {
15670
				animation.left = cur.left - this.offset.parent.left - this.margins.left +
15671
					( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
15672
						0 :
15673
						this.offsetParent[ 0 ].scrollLeft
15674
					);
15675
			}
15676
			if ( !axis || axis === "y" ) {
15677
				animation.top = cur.top - this.offset.parent.top - this.margins.top +
15678
					( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
15679
						0 :
15680
						this.offsetParent[ 0 ].scrollTop
15681
					);
15682
			}
15683
			this.reverting = true;
15684
			$( this.helper ).animate(
15685
				animation,
15686
				parseInt( this.options.revert, 10 ) || 500,
15687
				function() {
15688
					that._clear( event );
15689
				}
15690
			);
15691
		} else {
15692
			this._clear( event, noPropagation );
15693
		}
15694
15695
		return false;
15696
15697
	},
15698
15699
	cancel: function() {
15700
15701
		if ( this.dragging ) {
15702
15703
			this._mouseUp( new $.Event( "mouseup", { target: null } ) );
15704
15705
			if ( this.options.helper === "original" ) {
15706
				this.currentItem.css( this._storedCSS );
15707
				this._removeClass( this.currentItem, "ui-sortable-helper" );
15708
			} else {
15709
				this.currentItem.show();
15710
			}
15711
15712
			//Post deactivating events to containers
15713
			for ( var i = this.containers.length - 1; i >= 0; i-- ) {
15714
				this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
15715
				if ( this.containers[ i ].containerCache.over ) {
15716
					this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
15717
					this.containers[ i ].containerCache.over = 0;
15718
				}
15719
			}
15720
15721
		}
15722
15723
		if ( this.placeholder ) {
15724
15725
			//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
15726
			// it unbinds ALL events from the original node!
15727
			if ( this.placeholder[ 0 ].parentNode ) {
15728
				this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
15729
			}
15730
			if ( this.options.helper !== "original" && this.helper &&
15731
					this.helper[ 0 ].parentNode ) {
15732
				this.helper.remove();
15733
			}
15734
15735
			$.extend( this, {
15736
				helper: null,
15737
				dragging: false,
15738
				reverting: false,
15739
				_noFinalSort: null
15740
			} );
15741
15742
			if ( this.domPosition.prev ) {
15743
				$( this.domPosition.prev ).after( this.currentItem );
15744
			} else {
15745
				$( this.domPosition.parent ).prepend( this.currentItem );
15746
			}
15747
		}
15748
15749
		return this;
15750
15751
	},
15752
15753
	serialize: function( o ) {
15754
15755
		var items = this._getItemsAsjQuery( o && o.connected ),
15756
			str = [];
15757
		o = o || {};
15758
15759
		$( items ).each( function() {
15760
			var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
15761
				.match( o.expression || ( /(.+)[\-=_](.+)/ ) );
15762
			if ( res ) {
15763
				str.push(
15764
					( o.key || res[ 1 ] + "[]" ) +
15765
					"=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
15766
			}
15767
		} );
15768
15769
		if ( !str.length && o.key ) {
15770
			str.push( o.key + "=" );
15771
		}
15772
15773
		return str.join( "&" );
15774
15775
	},
15776
15777
	toArray: function( o ) {
15778
15779
		var items = this._getItemsAsjQuery( o && o.connected ),
15780
			ret = [];
15781
15782
		o = o || {};
15783
15784
		items.each( function() {
15785
			ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
15786
		} );
15787
		return ret;
15788
15789
	},
15790
15791
	/* Be careful with the following core functions */
15792
	_intersectsWith: function( item ) {
15793
15794
		var x1 = this.positionAbs.left,
15795
			x2 = x1 + this.helperProportions.width,
15796
			y1 = this.positionAbs.top,
15797
			y2 = y1 + this.helperProportions.height,
15798
			l = item.left,
15799
			r = l + item.width,
15800
			t = item.top,
15801
			b = t + item.height,
15802
			dyClick = this.offset.click.top,
15803
			dxClick = this.offset.click.left,
15804
			isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
15805
				( y1 + dyClick ) < b ),
15806
			isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
15807
				( x1 + dxClick ) < r ),
15808
			isOverElement = isOverElementHeight && isOverElementWidth;
15809
15810
		if ( this.options.tolerance === "pointer" ||
15811
			this.options.forcePointerForContainers ||
15812
			( this.options.tolerance !== "pointer" &&
15813
				this.helperProportions[ this.floating ? "width" : "height" ] >
15814
				item[ this.floating ? "width" : "height" ] )
15815
		) {
15816
			return isOverElement;
15817
		} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
15818
15819
			return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
15820
				x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
15821
				t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
15822
				y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
15823
15824
		}
15825
	},
15826
15827
	_intersectsWithPointer: function( item ) {
15828
		var verticalDirection, horizontalDirection,
15829
			isOverElementHeight = ( this.options.axis === "x" ) ||
15830
				this._isOverAxis(
15831
					this.positionAbs.top + this.offset.click.top, item.top, item.height ),
15832
			isOverElementWidth = ( this.options.axis === "y" ) ||
15833
				this._isOverAxis(
15834
					this.positionAbs.left + this.offset.click.left, item.left, item.width ),
15835
			isOverElement = isOverElementHeight && isOverElementWidth;
15836
15837
		if ( !isOverElement ) {
15838
			return false;
15839
		}
15840
15841
		verticalDirection = this._getDragVerticalDirection();
15842
		horizontalDirection = this._getDragHorizontalDirection();
15843
15844
		return this.floating ?
15845
			( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
15846
			: ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
15847
15848
	},
15849
15850
	_intersectsWithSides: function( item ) {
15851
15852
		var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
15853
				this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
15854
			isOverRightHalf = this._isOverAxis( this.positionAbs.left +
15855
				this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
15856
			verticalDirection = this._getDragVerticalDirection(),
15857
			horizontalDirection = this._getDragHorizontalDirection();
15858
15859
		if ( this.floating && horizontalDirection ) {
15860
			return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
15861
				( horizontalDirection === "left" && !isOverRightHalf ) );
15862
		} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
15863
			return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
15864
				( verticalDirection === "up" && !isOverBottomHalf ) );
15865
		}
15866
15867
	},
15868
15869
	_getDragVerticalDirection: function() {
15870
		var delta = this.positionAbs.top - this.lastPositionAbs.top;
15871
		return delta !== 0 && ( delta > 0 ? "down" : "up" );
15872
	},
15873
15874
	_getDragHorizontalDirection: function() {
15875
		var delta = this.positionAbs.left - this.lastPositionAbs.left;
15876
		return delta !== 0 && ( delta > 0 ? "right" : "left" );
15877
	},
15878
15879
	refresh: function( event ) {
15880
		this._refreshItems( event );
15881
		this._setHandleClassName();
15882
		this.refreshPositions();
15883
		return this;
15884
	},
15885
15886
	_connectWith: function() {
15887
		var options = this.options;
15888
		return options.connectWith.constructor === String ?
15889
			[ options.connectWith ] :
15890
			options.connectWith;
15891
	},
15892
15893
	_getItemsAsjQuery: function( connected ) {
15894
15895
		var i, j, cur, inst,
15896
			items = [],
15897
			queries = [],
15898
			connectWith = this._connectWith();
15899
15900
		if ( connectWith && connected ) {
15901
			for ( i = connectWith.length - 1; i >= 0; i-- ) {
15902
				cur = $( connectWith[ i ], this.document[ 0 ] );
15903
				for ( j = cur.length - 1; j >= 0; j-- ) {
15904
					inst = $.data( cur[ j ], this.widgetFullName );
15905
					if ( inst && inst !== this && !inst.options.disabled ) {
15906
						queries.push( [ $.isFunction( inst.options.items ) ?
15907
							inst.options.items.call( inst.element ) :
15908
							$( inst.options.items, inst.element )
15909
								.not( ".ui-sortable-helper" )
15910
								.not( ".ui-sortable-placeholder" ), inst ] );
15911
					}
15912
				}
15913
			}
15914
		}
15915
15916
		queries.push( [ $.isFunction( this.options.items ) ?
15917
			this.options.items
15918
				.call( this.element, null, { options: this.options, item: this.currentItem } ) :
15919
			$( this.options.items, this.element )
15920
				.not( ".ui-sortable-helper" )
15921
				.not( ".ui-sortable-placeholder" ), this ] );
15922
15923
		function addItems() {
15924
			items.push( this );
15925
		}
15926
		for ( i = queries.length - 1; i >= 0; i-- ) {
15927
			queries[ i ][ 0 ].each( addItems );
15928
		}
15929
15930
		return $( items );
15931
15932
	},
15933
15934
	_removeCurrentsFromItems: function() {
15935
15936
		var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
15937
15938
		this.items = $.grep( this.items, function( item ) {
15939
			for ( var j = 0; j < list.length; j++ ) {
15940
				if ( list[ j ] === item.item[ 0 ] ) {
15941
					return false;
15942
				}
15943
			}
15944
			return true;
15945
		} );
15946
15947
	},
15948
15949
	_refreshItems: function( event ) {
15950
15951
		this.items = [];
15952
		this.containers = [ this ];
15953
15954
		var i, j, cur, inst, targetData, _queries, item, queriesLength,
15955
			items = this.items,
15956
			queries = [ [ $.isFunction( this.options.items ) ?
15957
				this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
15958
				$( this.options.items, this.element ), this ] ],
15959
			connectWith = this._connectWith();
15960
15961
		//Shouldn't be run the first time through due to massive slow-down
15962
		if ( connectWith && this.ready ) {
15963
			for ( i = connectWith.length - 1; i >= 0; i-- ) {
15964
				cur = $( connectWith[ i ], this.document[ 0 ] );
15965
				for ( j = cur.length - 1; j >= 0; j-- ) {
15966
					inst = $.data( cur[ j ], this.widgetFullName );
15967
					if ( inst && inst !== this && !inst.options.disabled ) {
15968
						queries.push( [ $.isFunction( inst.options.items ) ?
15969
							inst.options.items
15970
								.call( inst.element[ 0 ], event, { item: this.currentItem } ) :
15971
							$( inst.options.items, inst.element ), inst ] );
15972
						this.containers.push( inst );
15973
					}
15974
				}
15975
			}
15976
		}
15977
15978
		for ( i = queries.length - 1; i >= 0; i-- ) {
15979
			targetData = queries[ i ][ 1 ];
15980
			_queries = queries[ i ][ 0 ];
15981
15982
			for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
15983
				item = $( _queries[ j ] );
15984
15985
				// Data for target checking (mouse manager)
15986
				item.data( this.widgetName + "-item", targetData );
15987
15988
				items.push( {
15989
					item: item,
15990
					instance: targetData,
15991
					width: 0, height: 0,
15992
					left: 0, top: 0
15993
				} );
15994
			}
15995
		}
15996
15997
	},
15998
15999
	refreshPositions: function( fast ) {
16000
16001
		// Determine whether items are being displayed horizontally
16002
		this.floating = this.items.length ?
16003
			this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
16004
			false;
16005
16006
		//This has to be redone because due to the item being moved out/into the offsetParent,
16007
		// the offsetParent's position will change
16008
		if ( this.offsetParent && this.helper ) {
16009
			this.offset.parent = this._getParentOffset();
16010
		}
16011
16012
		var i, item, t, p;
16013
16014
		for ( i = this.items.length - 1; i >= 0; i-- ) {
16015
			item = this.items[ i ];
16016
16017
			//We ignore calculating positions of all connected containers when we're not over them
16018
			if ( item.instance !== this.currentContainer && this.currentContainer &&
16019
					item.item[ 0 ] !== this.currentItem[ 0 ] ) {
16020
				continue;
16021
			}
16022
16023
			t = this.options.toleranceElement ?
16024
				$( this.options.toleranceElement, item.item ) :
16025
				item.item;
16026
16027
			if ( !fast ) {
16028
				item.width = t.outerWidth();
16029
				item.height = t.outerHeight();
16030
			}
16031
16032
			p = t.offset();
16033
			item.left = p.left;
16034
			item.top = p.top;
16035
		}
16036
16037
		if ( this.options.custom && this.options.custom.refreshContainers ) {
16038
			this.options.custom.refreshContainers.call( this );
16039
		} else {
16040
			for ( i = this.containers.length - 1; i >= 0; i-- ) {
16041
				p = this.containers[ i ].element.offset();
16042
				this.containers[ i ].containerCache.left = p.left;
16043
				this.containers[ i ].containerCache.top = p.top;
16044
				this.containers[ i ].containerCache.width =
16045
					this.containers[ i ].element.outerWidth();
16046
				this.containers[ i ].containerCache.height =
16047
					this.containers[ i ].element.outerHeight();
16048
			}
16049
		}
16050
16051
		return this;
16052
	},
16053
16054
	_createPlaceholder: function( that ) {
16055
		that = that || this;
16056
		var className,
16057
			o = that.options;
16058
16059
		if ( !o.placeholder || o.placeholder.constructor === String ) {
16060
			className = o.placeholder;
16061
			o.placeholder = {
16062
				element: function() {
16063
16064
					var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
16065
						element = $( "<" + nodeName + ">", that.document[ 0 ] );
16066
16067
						that._addClass( element, "ui-sortable-placeholder",
16068
								className || that.currentItem[ 0 ].className )
16069
							._removeClass( element, "ui-sortable-helper" );
16070
16071
					if ( nodeName === "tbody" ) {
16072
						that._createTrPlaceholder(
16073
							that.currentItem.find( "tr" ).eq( 0 ),
16074
							$( "<tr>", that.document[ 0 ] ).appendTo( element )
16075
						);
16076
					} else if ( nodeName === "tr" ) {
16077
						that._createTrPlaceholder( that.currentItem, element );
16078
					} else if ( nodeName === "img" ) {
16079
						element.attr( "src", that.currentItem.attr( "src" ) );
16080
					}
16081
16082
					if ( !className ) {
16083
						element.css( "visibility", "hidden" );
16084
					}
16085
16086
					return element;
16087
				},
16088
				update: function( container, p ) {
16089
16090
					// 1. If a className is set as 'placeholder option, we don't force sizes -
16091
					// the class is responsible for that
16092
					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a
16093
					// class name is specified
16094
					if ( className && !o.forcePlaceholderSize ) {
16095
						return;
16096
					}
16097
16098
					//If the element doesn't have a actual height by itself (without styles coming
16099
					// from a stylesheet), it receives the inline height from the dragged item
16100
					if ( !p.height() ) {
16101
						p.height(
16102
							that.currentItem.innerHeight() -
16103
							parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
16104
							parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
16105
					}
16106
					if ( !p.width() ) {
16107
						p.width(
16108
							that.currentItem.innerWidth() -
16109
							parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
16110
							parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
16111
					}
16112
				}
16113
			};
16114
		}
16115
16116
		//Create the placeholder
16117
		that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
16118
16119
		//Append it after the actual current item
16120
		that.currentItem.after( that.placeholder );
16121
16122
		//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
16123
		o.placeholder.update( that, that.placeholder );
16124
16125
	},
16126
16127
	_createTrPlaceholder: function( sourceTr, targetTr ) {
16128
		var that = this;
16129
16130
		sourceTr.children().each( function() {
16131
			$( "<td>&#160;</td>", that.document[ 0 ] )
16132
				.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
16133
				.appendTo( targetTr );
16134
		} );
16135
	},
16136
16137
	_contactContainers: function( event ) {
16138
		var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
16139
			floating, axis,
16140
			innermostContainer = null,
16141
			innermostIndex = null;
16142
16143
		// Get innermost container that intersects with item
16144
		for ( i = this.containers.length - 1; i >= 0; i-- ) {
16145
16146
			// Never consider a container that's located within the item itself
16147
			if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
16148
				continue;
16149
			}
16150
16151
			if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
16152
16153
				// If we've already found a container and it's more "inner" than this, then continue
16154
				if ( innermostContainer &&
16155
						$.contains(
16156
							this.containers[ i ].element[ 0 ],
16157
							innermostContainer.element[ 0 ] ) ) {
16158
					continue;
16159
				}
16160
16161
				innermostContainer = this.containers[ i ];
16162
				innermostIndex = i;
16163
16164
			} else {
16165
16166
				// container doesn't intersect. trigger "out" event if necessary
16167
				if ( this.containers[ i ].containerCache.over ) {
16168
					this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
16169
					this.containers[ i ].containerCache.over = 0;
16170
				}
16171
			}
16172
16173
		}
16174
16175
		// If no intersecting containers found, return
16176
		if ( !innermostContainer ) {
16177
			return;
16178
		}
16179
16180
		// Move the item into the container if it's not there already
16181
		if ( this.containers.length === 1 ) {
16182
			if ( !this.containers[ innermostIndex ].containerCache.over ) {
16183
				this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
16184
				this.containers[ innermostIndex ].containerCache.over = 1;
16185
			}
16186
		} else {
16187
16188
			// When entering a new container, we will find the item with the least distance and
16189
			// append our item near it
16190
			dist = 10000;
16191
			itemWithLeastDistance = null;
16192
			floating = innermostContainer.floating || this._isFloating( this.currentItem );
16193
			posProperty = floating ? "left" : "top";
16194
			sizeProperty = floating ? "width" : "height";
16195
			axis = floating ? "pageX" : "pageY";
16196
16197
			for ( j = this.items.length - 1; j >= 0; j-- ) {
16198
				if ( !$.contains(
16199
						this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
16200
				) {
16201
					continue;
16202
				}
16203
				if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
16204
					continue;
16205
				}
16206
16207
				cur = this.items[ j ].item.offset()[ posProperty ];
16208
				nearBottom = false;
16209
				if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
16210
					nearBottom = true;
16211
				}
16212
16213
				if ( Math.abs( event[ axis ] - cur ) < dist ) {
16214
					dist = Math.abs( event[ axis ] - cur );
16215
					itemWithLeastDistance = this.items[ j ];
16216
					this.direction = nearBottom ? "up" : "down";
16217
				}
16218
			}
16219
16220
			//Check if dropOnEmpty is enabled
16221
			if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
16222
				return;
16223
			}
16224
16225
			if ( this.currentContainer === this.containers[ innermostIndex ] ) {
16226
				if ( !this.currentContainer.containerCache.over ) {
16227
					this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
16228
					this.currentContainer.containerCache.over = 1;
16229
				}
16230
				return;
16231
			}
16232
16233
			itemWithLeastDistance ?
16234
				this._rearrange( event, itemWithLeastDistance, null, true ) :
16235
				this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
16236
			this._trigger( "change", event, this._uiHash() );
16237
			this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
16238
			this.currentContainer = this.containers[ innermostIndex ];
16239
16240
			//Update the placeholder
16241
			this.options.placeholder.update( this.currentContainer, this.placeholder );
16242
16243
			this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
16244
			this.containers[ innermostIndex ].containerCache.over = 1;
16245
		}
16246
16247
	},
16248
16249
	_createHelper: function( event ) {
16250
16251
		var o = this.options,
16252
			helper = $.isFunction( o.helper ) ?
16253
				$( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
16254
				( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
16255
16256
		//Add the helper to the DOM if that didn't happen already
16257
		if ( !helper.parents( "body" ).length ) {
16258
			$( o.appendTo !== "parent" ?
16259
				o.appendTo :
16260
				this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
16261
		}
16262
16263
		if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
16264
			this._storedCSS = {
16265
				width: this.currentItem[ 0 ].style.width,
16266
				height: this.currentItem[ 0 ].style.height,
16267
				position: this.currentItem.css( "position" ),
16268
				top: this.currentItem.css( "top" ),
16269
				left: this.currentItem.css( "left" )
16270
			};
16271
		}
16272
16273
		if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
16274
			helper.width( this.currentItem.width() );
16275
		}
16276
		if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
16277
			helper.height( this.currentItem.height() );
16278
		}
16279
16280
		return helper;
16281
16282
	},
16283
16284 View Code Duplication
	_adjustOffsetFromHelper: function( obj ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
16285
		if ( typeof obj === "string" ) {
16286
			obj = obj.split( " " );
16287
		}
16288
		if ( $.isArray( obj ) ) {
16289
			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
16290
		}
16291
		if ( "left" in obj ) {
16292
			this.offset.click.left = obj.left + this.margins.left;
16293
		}
16294
		if ( "right" in obj ) {
16295
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
16296
		}
16297
		if ( "top" in obj ) {
16298
			this.offset.click.top = obj.top + this.margins.top;
16299
		}
16300
		if ( "bottom" in obj ) {
16301
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
16302
		}
16303
	},
16304
16305
	_getParentOffset: function() {
16306
16307
		//Get the offsetParent and cache its position
16308
		this.offsetParent = this.helper.offsetParent();
16309
		var po = this.offsetParent.offset();
16310
16311
		// This is a special case where we need to modify a offset calculated on start, since the
16312
		// following happened:
16313
		// 1. The position of the helper is absolute, so it's position is calculated based on the
16314
		// next positioned parent
16315
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
16316
		// the document, which means that the scroll is included in the initial calculation of the
16317
		// offset of the parent, and never recalculated upon drag
16318
		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16319
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
16320
			po.left += this.scrollParent.scrollLeft();
16321
			po.top += this.scrollParent.scrollTop();
16322
		}
16323
16324
		// This needs to be actually done for all browsers, since pageX/pageY includes this
16325
		// information with an ugly IE fix
16326
		if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
16327
				( this.offsetParent[ 0 ].tagName &&
16328
				this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
16329
			po = { top: 0, left: 0 };
16330
		}
16331
16332
		return {
16333
			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
16334
			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
16335
		};
16336
16337
	},
16338
16339
	_getRelativeOffset: function() {
16340
16341
		if ( this.cssPosition === "relative" ) {
16342
			var p = this.currentItem.position();
16343
			return {
16344
				top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
16345
					this.scrollParent.scrollTop(),
16346
				left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
16347
					this.scrollParent.scrollLeft()
16348
			};
16349
		} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
16350
			return { top: 0, left: 0 };
16351
		}
16352
16353
	},
16354
16355
	_cacheMargins: function() {
16356
		this.margins = {
16357
			left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
16358
			top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
16359
		};
16360
	},
16361
16362
	_cacheHelperProportions: function() {
16363
		this.helperProportions = {
16364
			width: this.helper.outerWidth(),
16365
			height: this.helper.outerHeight()
16366
		};
16367
	},
16368
16369
	_setContainment: function() {
16370
16371
		var ce, co, over,
16372
			o = this.options;
16373
		if ( o.containment === "parent" ) {
16374
			o.containment = this.helper[ 0 ].parentNode;
16375
		}
16376
		if ( o.containment === "document" || o.containment === "window" ) {
16377
			this.containment = [
16378
				0 - this.offset.relative.left - this.offset.parent.left,
16379
				0 - this.offset.relative.top - this.offset.parent.top,
16380
				o.containment === "document" ?
16381
					this.document.width() :
16382
					this.window.width() - this.helperProportions.width - this.margins.left,
16383
				( o.containment === "document" ?
16384
					( this.document.height() || document.body.parentNode.scrollHeight ) :
16385
					this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
16386
				) - this.helperProportions.height - this.margins.top
16387
			];
16388
		}
16389
16390
		if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
16391
			ce = $( o.containment )[ 0 ];
16392
			co = $( o.containment ).offset();
16393
			over = ( $( ce ).css( "overflow" ) !== "hidden" );
16394
16395
			this.containment = [
16396
				co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
16397
					( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
16398
				co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
16399
					( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
16400
				co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
16401
					( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
16402
					( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
16403
					this.helperProportions.width - this.margins.left,
16404
				co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
16405
					( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
16406
					( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
16407
					this.helperProportions.height - this.margins.top
16408
			];
16409
		}
16410
16411
	},
16412
16413
	_convertPositionTo: function( d, pos ) {
16414
16415
		if ( !pos ) {
16416
			pos = this.position;
16417
		}
16418
		var mod = d === "absolute" ? 1 : -1,
16419
			scroll = this.cssPosition === "absolute" &&
16420
				!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16421
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
16422
					this.offsetParent :
16423
					this.scrollParent,
16424
			scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
16425
16426
		return {
16427
			top: (
16428
16429
				// The absolute mouse position
16430
				pos.top	+
16431
16432
				// Only for relative positioned nodes: Relative offset from element to offset parent
16433
				this.offset.relative.top * mod +
16434
16435
				// The offsetParent's offset without borders (offset + border)
16436
				this.offset.parent.top * mod -
16437
				( ( this.cssPosition === "fixed" ?
16438
					-this.scrollParent.scrollTop() :
16439
					( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
16440
			),
16441
			left: (
16442
16443
				// The absolute mouse position
16444
				pos.left +
16445
16446
				// Only for relative positioned nodes: Relative offset from element to offset parent
16447
				this.offset.relative.left * mod +
16448
16449
				// The offsetParent's offset without borders (offset + border)
16450
				this.offset.parent.left * mod	-
16451
				( ( this.cssPosition === "fixed" ?
16452
					-this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
16453
					scroll.scrollLeft() ) * mod )
16454
			)
16455
		};
16456
16457
	},
16458
16459
	_generatePosition: function( event ) {
16460
16461
		var top, left,
16462
			o = this.options,
16463
			pageX = event.pageX,
16464
			pageY = event.pageY,
16465
			scroll = this.cssPosition === "absolute" &&
16466
				!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16467
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
16468
					this.offsetParent :
16469
					this.scrollParent,
16470
				scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
16471
16472
		// This is another very weird special case that only happens for relative elements:
16473
		// 1. If the css position is relative
16474
		// 2. and the scroll parent is the document or similar to the offset parent
16475
		// we have to refresh the relative offset during the scroll so there are no jumps
16476
		if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16477
				this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
16478
			this.offset.relative = this._getRelativeOffset();
16479
		}
16480
16481
		/*
16482
		 * - Position constraining -
16483
		 * Constrain the position to a mix of grid, containment.
16484
		 */
16485
16486
		if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
16487
16488
			if ( this.containment ) {
16489
				if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
16490
					pageX = this.containment[ 0 ] + this.offset.click.left;
16491
				}
16492
				if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
16493
					pageY = this.containment[ 1 ] + this.offset.click.top;
16494
				}
16495
				if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
16496
					pageX = this.containment[ 2 ] + this.offset.click.left;
16497
				}
16498
				if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
16499
					pageY = this.containment[ 3 ] + this.offset.click.top;
16500
				}
16501
			}
16502
16503 View Code Duplication
			if ( o.grid ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
16504
				top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
16505
					o.grid[ 1 ] ) * o.grid[ 1 ];
16506
				pageY = this.containment ?
16507
					( ( top - this.offset.click.top >= this.containment[ 1 ] &&
16508
						top - this.offset.click.top <= this.containment[ 3 ] ) ?
16509
							top :
16510
							( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
16511
								top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
16512
								top;
16513
16514
				left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
16515
					o.grid[ 0 ] ) * o.grid[ 0 ];
16516
				pageX = this.containment ?
16517
					( ( left - this.offset.click.left >= this.containment[ 0 ] &&
16518
						left - this.offset.click.left <= this.containment[ 2 ] ) ?
16519
							left :
16520
							( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
16521
								left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
16522
								left;
16523
			}
16524
16525
		}
16526
16527
		return {
16528
			top: (
16529
16530
				// The absolute mouse position
16531
				pageY -
16532
16533
				// Click offset (relative to the element)
16534
				this.offset.click.top -
16535
16536
				// Only for relative positioned nodes: Relative offset from element to offset parent
16537
				this.offset.relative.top -
16538
16539
				// The offsetParent's offset without borders (offset + border)
16540
				this.offset.parent.top +
16541
				( ( this.cssPosition === "fixed" ?
16542
					-this.scrollParent.scrollTop() :
16543
					( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
16544
			),
16545
			left: (
16546
16547
				// The absolute mouse position
16548
				pageX -
16549
16550
				// Click offset (relative to the element)
16551
				this.offset.click.left -
16552
16553
				// Only for relative positioned nodes: Relative offset from element to offset parent
16554
				this.offset.relative.left -
16555
16556
				// The offsetParent's offset without borders (offset + border)
16557
				this.offset.parent.left +
16558
				( ( this.cssPosition === "fixed" ?
16559
					-this.scrollParent.scrollLeft() :
16560
					scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
16561
			)
16562
		};
16563
16564
	},
16565
16566
	_rearrange: function( event, i, a, hardRefresh ) {
16567
16568
		a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
16569
			i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
16570
				( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
16571
16572
		//Various things done here to improve the performance:
16573
		// 1. we create a setTimeout, that calls refreshPositions
16574
		// 2. on the instance, we have a counter variable, that get's higher after every append
16575
		// 3. on the local scope, we copy the counter variable, and check in the timeout,
16576
		// if it's still the same
16577
		// 4. this lets only the last addition to the timeout stack through
16578
		this.counter = this.counter ? ++this.counter : 1;
16579
		var counter = this.counter;
16580
16581
		this._delay( function() {
16582
			if ( counter === this.counter ) {
16583
16584
				//Precompute after each DOM insertion, NOT on mousemove
16585
				this.refreshPositions( !hardRefresh );
16586
			}
16587
		} );
16588
16589
	},
16590
16591
	_clear: function( event, noPropagation ) {
16592
16593
		this.reverting = false;
16594
16595
		// We delay all events that have to be triggered to after the point where the placeholder
16596
		// has been removed and everything else normalized again
16597
		var i,
16598
			delayedTriggers = [];
16599
16600
		// We first have to update the dom position of the actual currentItem
16601
		// Note: don't do it if the current item is already removed (by a user), or it gets
16602
		// reappended (see #4088)
16603
		if ( !this._noFinalSort && this.currentItem.parent().length ) {
16604
			this.placeholder.before( this.currentItem );
16605
		}
16606
		this._noFinalSort = null;
16607
16608
		if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
16609
			for ( i in this._storedCSS ) {
16610
				if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
16611
					this._storedCSS[ i ] = "";
16612
				}
16613
			}
16614
			this.currentItem.css( this._storedCSS );
16615
			this._removeClass( this.currentItem, "ui-sortable-helper" );
16616
		} else {
16617
			this.currentItem.show();
16618
		}
16619
16620
		if ( this.fromOutside && !noPropagation ) {
16621
			delayedTriggers.push( function( event ) {
16622
				this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
16623
			} );
16624
		}
16625
		if ( ( this.fromOutside ||
16626
				this.domPosition.prev !==
16627
				this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
16628
				this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
16629
16630
			// Trigger update callback if the DOM position has changed
16631
			delayedTriggers.push( function( event ) {
16632
				this._trigger( "update", event, this._uiHash() );
16633
			} );
16634
		}
16635
16636
		// Check if the items Container has Changed and trigger appropriate
16637
		// events.
16638
		if ( this !== this.currentContainer ) {
16639
			if ( !noPropagation ) {
16640
				delayedTriggers.push( function( event ) {
16641
					this._trigger( "remove", event, this._uiHash() );
16642
				} );
16643
				delayedTriggers.push( ( function( c ) {
16644
					return function( event ) {
16645
						c._trigger( "receive", event, this._uiHash( this ) );
16646
					};
16647
				} ).call( this, this.currentContainer ) );
16648
				delayedTriggers.push( ( function( c ) {
16649
					return function( event ) {
16650
						c._trigger( "update", event, this._uiHash( this ) );
16651
					};
16652
				} ).call( this, this.currentContainer ) );
16653
			}
16654
		}
16655
16656
		//Post events to containers
16657
		function delayEvent( type, instance, container ) {
16658
			return function( event ) {
16659
				container._trigger( type, event, instance._uiHash( instance ) );
16660
			};
16661
		}
16662
		for ( i = this.containers.length - 1; i >= 0; i-- ) {
16663
			if ( !noPropagation ) {
16664
				delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
16665
			}
16666
			if ( this.containers[ i ].containerCache.over ) {
16667
				delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
16668
				this.containers[ i ].containerCache.over = 0;
16669
			}
16670
		}
16671
16672
		//Do what was originally in plugins
16673
		if ( this.storedCursor ) {
16674
			this.document.find( "body" ).css( "cursor", this.storedCursor );
16675
			this.storedStylesheet.remove();
16676
		}
16677
		if ( this._storedOpacity ) {
16678
			this.helper.css( "opacity", this._storedOpacity );
16679
		}
16680
		if ( this._storedZIndex ) {
16681
			this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
16682
		}
16683
16684
		this.dragging = false;
16685
16686
		if ( !noPropagation ) {
16687
			this._trigger( "beforeStop", event, this._uiHash() );
16688
		}
16689
16690
		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
16691
		// it unbinds ALL events from the original node!
16692
		this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
16693
16694
		if ( !this.cancelHelperRemoval ) {
16695
			if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
16696
				this.helper.remove();
16697
			}
16698
			this.helper = null;
16699
		}
16700
16701
		if ( !noPropagation ) {
16702
			for ( i = 0; i < delayedTriggers.length; i++ ) {
16703
16704
				// Trigger all delayed events
16705
				delayedTriggers[ i ].call( this, event );
16706
			}
16707
			this._trigger( "stop", event, this._uiHash() );
16708
		}
16709
16710
		this.fromOutside = false;
16711
		return !this.cancelHelperRemoval;
16712
16713
	},
16714
16715
	_trigger: function() {
16716
		if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
16717
			this.cancel();
16718
		}
16719
	},
16720
16721
	_uiHash: function( _inst ) {
16722
		var inst = _inst || this;
16723
		return {
16724
			helper: inst.helper,
16725
			placeholder: inst.placeholder || $( [] ),
16726
			position: inst.position,
16727
			originalPosition: inst.originalPosition,
16728
			offset: inst.positionAbs,
16729
			item: inst.currentItem,
16730
			sender: _inst ? _inst.element : null
16731
		};
16732
	}
16733
16734
} );
16735
16736
16737
/*!
16738
 * jQuery UI Spinner 1.12.1
16739
 * http://jqueryui.com
16740
 *
16741
 * Copyright jQuery Foundation and other contributors
16742
 * Released under the MIT license.
16743
 * http://jquery.org/license
16744
 */
16745
16746
//>>label: Spinner
16747
//>>group: Widgets
16748
//>>description: Displays buttons to easily input numbers via the keyboard or mouse.
16749
//>>docs: http://api.jqueryui.com/spinner/
16750
//>>demos: http://jqueryui.com/spinner/
16751
//>>css.structure: ../../themes/base/core.css
16752
//>>css.structure: ../../themes/base/spinner.css
16753
//>>css.theme: ../../themes/base/theme.css
16754
16755
16756
16757
function spinnerModifer( fn ) {
16758
	return function() {
16759
		var previous = this.element.val();
16760
		fn.apply( this, arguments );
16761
		this._refresh();
16762
		if ( previous !== this.element.val() ) {
16763
			this._trigger( "change" );
16764
		}
16765
	};
16766
}
16767
16768
$.widget( "ui.spinner", {
16769
	version: "1.12.1",
16770
	defaultElement: "<input>",
16771
	widgetEventPrefix: "spin",
16772
	options: {
16773
		classes: {
16774
			"ui-spinner": "ui-corner-all",
16775
			"ui-spinner-down": "ui-corner-br",
16776
			"ui-spinner-up": "ui-corner-tr"
16777
		},
16778
		culture: null,
16779
		icons: {
16780
			down: "ui-icon-triangle-1-s",
16781
			up: "ui-icon-triangle-1-n"
16782
		},
16783
		incremental: true,
16784
		max: null,
16785
		min: null,
16786
		numberFormat: null,
16787
		page: 10,
16788
		step: 1,
16789
16790
		change: null,
16791
		spin: null,
16792
		start: null,
16793
		stop: null
16794
	},
16795
16796
	_create: function() {
16797
16798
		// handle string values that need to be parsed
16799
		this._setOption( "max", this.options.max );
16800
		this._setOption( "min", this.options.min );
16801
		this._setOption( "step", this.options.step );
16802
16803
		// Only format if there is a value, prevents the field from being marked
16804
		// as invalid in Firefox, see #9573.
16805
		if ( this.value() !== "" ) {
16806
16807
			// Format the value, but don't constrain.
16808
			this._value( this.element.val(), true );
16809
		}
16810
16811
		this._draw();
16812
		this._on( this._events );
16813
		this._refresh();
16814
16815
		// Turning off autocomplete prevents the browser from remembering the
16816
		// value when navigating through history, so we re-enable autocomplete
16817
		// if the page is unloaded before the widget is destroyed. #7790
16818
		this._on( this.window, {
16819
			beforeunload: function() {
16820
				this.element.removeAttr( "autocomplete" );
16821
			}
16822
		} );
16823
	},
16824
16825
	_getCreateOptions: function() {
16826
		var options = this._super();
16827
		var element = this.element;
16828
16829
		$.each( [ "min", "max", "step" ], function( i, option ) {
16830
			var value = element.attr( option );
16831
			if ( value != null && value.length ) {
0 ignored issues
show
Best Practice introduced by
Comparing value to null using the != operator is not safe. Consider using !== instead.
Loading history...
16832
				options[ option ] = value;
16833
			}
16834
		} );
16835
16836
		return options;
16837
	},
16838
16839
	_events: {
16840
		keydown: function( event ) {
16841
			if ( this._start( event ) && this._keydown( event ) ) {
16842
				event.preventDefault();
16843
			}
16844
		},
16845
		keyup: "_stop",
16846
		focus: function() {
16847
			this.previous = this.element.val();
16848
		},
16849
		blur: function( event ) {
16850
			if ( this.cancelBlur ) {
16851
				delete this.cancelBlur;
16852
				return;
16853
			}
16854
16855
			this._stop();
16856
			this._refresh();
16857
			if ( this.previous !== this.element.val() ) {
16858
				this._trigger( "change", event );
16859
			}
16860
		},
16861
		mousewheel: function( event, delta ) {
16862
			if ( !delta ) {
16863
				return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
16864
			}
16865
			if ( !this.spinning && !this._start( event ) ) {
16866
				return false;
16867
			}
16868
16869
			this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
16870
			clearTimeout( this.mousewheelTimer );
16871
			this.mousewheelTimer = this._delay( function() {
16872
				if ( this.spinning ) {
16873
					this._stop( event );
16874
				}
16875
			}, 100 );
16876
			event.preventDefault();
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
16877
		},
16878
		"mousedown .ui-spinner-button": function( event ) {
16879
			var previous;
16880
16881
			// We never want the buttons to have focus; whenever the user is
16882
			// interacting with the spinner, the focus should be on the input.
16883
			// If the input is focused then this.previous is properly set from
16884
			// when the input first received focus. If the input is not focused
16885
			// then we need to set this.previous based on the value before spinning.
16886
			previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
16887
				this.previous : this.element.val();
16888
			function checkFocus() {
16889
				var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
16890
				if ( !isActive ) {
16891
					this.element.trigger( "focus" );
16892
					this.previous = previous;
16893
16894
					// support: IE
16895
					// IE sets focus asynchronously, so we need to check if focus
16896
					// moved off of the input because the user clicked on the button.
16897
					this._delay( function() {
16898
						this.previous = previous;
16899
					} );
16900
				}
16901
			}
16902
16903
			// Ensure focus is on (or stays on) the text field
16904
			event.preventDefault();
16905
			checkFocus.call( this );
16906
16907
			// Support: IE
16908
			// IE doesn't prevent moving focus even with event.preventDefault()
16909
			// so we set a flag to know when we should ignore the blur event
16910
			// and check (again) if focus moved off of the input.
16911
			this.cancelBlur = true;
16912
			this._delay( function() {
16913
				delete this.cancelBlur;
16914
				checkFocus.call( this );
16915
			} );
16916
16917
			if ( this._start( event ) === false ) {
16918
				return;
16919
			}
16920
16921
			this._repeat( null, $( event.currentTarget )
16922
				.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
16923
		},
16924
		"mouseup .ui-spinner-button": "_stop",
16925
		"mouseenter .ui-spinner-button": function( event ) {
16926
16927
			// button will add ui-state-active if mouse was down while mouseleave and kept down
16928
			if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
16929
				return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
16930
			}
16931
16932
			if ( this._start( event ) === false ) {
16933
				return false;
16934
			}
16935
			this._repeat( null, $( event.currentTarget )
16936
				.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
16937
		},
16938
16939
		// TODO: do we really want to consider this a stop?
16940
		// shouldn't we just stop the repeater and wait until mouseup before
16941
		// we trigger the stop event?
16942
		"mouseleave .ui-spinner-button": "_stop"
16943
	},
16944
16945
	// Support mobile enhanced option and make backcompat more sane
16946
	_enhance: function() {
16947
		this.uiSpinner = this.element
16948
			.attr( "autocomplete", "off" )
16949
			.wrap( "<span>" )
16950
			.parent()
16951
16952
				// Add buttons
16953
				.append(
16954
					"<a></a><a></a>"
16955
				);
16956
	},
16957
16958
	_draw: function() {
16959
		this._enhance();
16960
16961
		this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
16962
		this._addClass( "ui-spinner-input" );
16963
16964
		this.element.attr( "role", "spinbutton" );
16965
16966
		// Button bindings
16967
		this.buttons = this.uiSpinner.children( "a" )
16968
			.attr( "tabIndex", -1 )
16969
			.attr( "aria-hidden", true )
16970
			.button( {
16971
				classes: {
16972
					"ui-button": ""
16973
				}
16974
			} );
16975
16976
		// TODO: Right now button does not support classes this is already updated in button PR
16977
		this._removeClass( this.buttons, "ui-corner-all" );
16978
16979
		this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
16980
		this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
16981
		this.buttons.first().button( {
16982
			"icon": this.options.icons.up,
16983
			"showLabel": false
16984
		} );
16985
		this.buttons.last().button( {
16986
			"icon": this.options.icons.down,
16987
			"showLabel": false
16988
		} );
16989
16990
		// IE 6 doesn't understand height: 50% for the buttons
16991
		// unless the wrapper has an explicit height
16992
		if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
16993
				this.uiSpinner.height() > 0 ) {
16994
			this.uiSpinner.height( this.uiSpinner.height() );
16995
		}
16996
	},
16997
16998
	_keydown: function( event ) {
16999
		var options = this.options,
17000
			keyCode = $.ui.keyCode;
17001
17002
		switch ( event.keyCode ) {
17003
		case keyCode.UP:
17004
			this._repeat( null, 1, event );
17005
			return true;
17006
		case keyCode.DOWN:
17007
			this._repeat( null, -1, event );
17008
			return true;
17009
		case keyCode.PAGE_UP:
17010
			this._repeat( null, options.page, event );
17011
			return true;
17012
		case keyCode.PAGE_DOWN:
17013
			this._repeat( null, -options.page, event );
17014
			return true;
17015
		}
17016
17017
		return false;
17018
	},
17019
17020
	_start: function( event ) {
17021
		if ( !this.spinning && this._trigger( "start", event ) === false ) {
17022
			return false;
17023
		}
17024
17025
		if ( !this.counter ) {
17026
			this.counter = 1;
17027
		}
17028
		this.spinning = true;
17029
		return true;
17030
	},
17031
17032
	_repeat: function( i, steps, event ) {
17033
		i = i || 500;
17034
17035
		clearTimeout( this.timer );
17036
		this.timer = this._delay( function() {
17037
			this._repeat( 40, steps, event );
17038
		}, i );
17039
17040
		this._spin( steps * this.options.step, event );
17041
	},
17042
17043
	_spin: function( step, event ) {
17044
		var value = this.value() || 0;
17045
17046
		if ( !this.counter ) {
17047
			this.counter = 1;
17048
		}
17049
17050
		value = this._adjustValue( value + step * this._increment( this.counter ) );
17051
17052
		if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
17053
			this._value( value );
17054
			this.counter++;
17055
		}
17056
	},
17057
17058
	_increment: function( i ) {
17059
		var incremental = this.options.incremental;
17060
17061
		if ( incremental ) {
17062
			return $.isFunction( incremental ) ?
17063
				incremental( i ) :
17064
				Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
17065
		}
17066
17067
		return 1;
17068
	},
17069
17070
	_precision: function() {
17071
		var precision = this._precisionOf( this.options.step );
17072
		if ( this.options.min !== null ) {
17073
			precision = Math.max( precision, this._precisionOf( this.options.min ) );
17074
		}
17075
		return precision;
17076
	},
17077
17078
	_precisionOf: function( num ) {
17079
		var str = num.toString(),
17080
			decimal = str.indexOf( "." );
17081
		return decimal === -1 ? 0 : str.length - decimal - 1;
17082
	},
17083
17084
	_adjustValue: function( value ) {
17085
		var base, aboveMin,
17086
			options = this.options;
17087
17088
		// Make sure we're at a valid step
17089
		// - find out where we are relative to the base (min or 0)
17090
		base = options.min !== null ? options.min : 0;
17091
		aboveMin = value - base;
17092
17093
		// - round to the nearest step
17094
		aboveMin = Math.round( aboveMin / options.step ) * options.step;
17095
17096
		// - rounding is based on 0, so adjust back to our base
17097
		value = base + aboveMin;
17098
17099
		// Fix precision from bad JS floating point math
17100
		value = parseFloat( value.toFixed( this._precision() ) );
17101
17102
		// Clamp the value
17103
		if ( options.max !== null && value > options.max ) {
17104
			return options.max;
17105
		}
17106
		if ( options.min !== null && value < options.min ) {
17107
			return options.min;
17108
		}
17109
17110
		return value;
17111
	},
17112
17113
	_stop: function( event ) {
17114
		if ( !this.spinning ) {
17115
			return;
17116
		}
17117
17118
		clearTimeout( this.timer );
17119
		clearTimeout( this.mousewheelTimer );
17120
		this.counter = 0;
17121
		this.spinning = false;
17122
		this._trigger( "stop", event );
17123
	},
17124
17125
	_setOption: function( key, value ) {
17126
		var prevValue, first, last;
17127
17128
		if ( key === "culture" || key === "numberFormat" ) {
17129
			prevValue = this._parse( this.element.val() );
17130
			this.options[ key ] = value;
17131
			this.element.val( this._format( prevValue ) );
17132
			return;
17133
		}
17134
17135
		if ( key === "max" || key === "min" || key === "step" ) {
17136
			if ( typeof value === "string" ) {
17137
				value = this._parse( value );
17138
			}
17139
		}
17140
		if ( key === "icons" ) {
17141
			first = this.buttons.first().find( ".ui-icon" );
17142
			this._removeClass( first, null, this.options.icons.up );
17143
			this._addClass( first, null, value.up );
17144
			last = this.buttons.last().find( ".ui-icon" );
17145
			this._removeClass( last, null, this.options.icons.down );
17146
			this._addClass( last, null, value.down );
17147
		}
17148
17149
		this._super( key, value );
17150
	},
17151
17152
	_setOptionDisabled: function( value ) {
17153
		this._super( value );
17154
17155
		this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
17156
		this.element.prop( "disabled", !!value );
17157
		this.buttons.button( value ? "disable" : "enable" );
17158
	},
17159
17160
	_setOptions: spinnerModifer( function( options ) {
17161
		this._super( options );
17162
	} ),
17163
17164
	_parse: function( val ) {
17165
		if ( typeof val === "string" && val !== "" ) {
17166
			val = window.Globalize && this.options.numberFormat ?
17167
				Globalize.parseFloat( val, 10, this.options.culture ) : +val;
0 ignored issues
show
Bug introduced by
The variable Globalize seems to be never declared. If this is a global, consider adding a /** global: Globalize */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
17168
		}
17169
		return val === "" || isNaN( val ) ? null : val;
17170
	},
17171
17172
	_format: function( value ) {
17173
		if ( value === "" ) {
17174
			return "";
17175
		}
17176
		return window.Globalize && this.options.numberFormat ?
17177
			Globalize.format( value, this.options.numberFormat, this.options.culture ) :
0 ignored issues
show
Bug introduced by
The variable Globalize seems to be never declared. If this is a global, consider adding a /** global: Globalize */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
17178
			value;
17179
	},
17180
17181
	_refresh: function() {
17182
		this.element.attr( {
17183
			"aria-valuemin": this.options.min,
17184
			"aria-valuemax": this.options.max,
17185
17186
			// TODO: what should we do with values that can't be parsed?
17187
			"aria-valuenow": this._parse( this.element.val() )
17188
		} );
17189
	},
17190
17191
	isValid: function() {
17192
		var value = this.value();
17193
17194
		// Null is invalid
17195
		if ( value === null ) {
17196
			return false;
17197
		}
17198
17199
		// If value gets adjusted, it's invalid
17200
		return value === this._adjustValue( value );
17201
	},
17202
17203
	// Update the value without triggering change
17204
	_value: function( value, allowAny ) {
17205
		var parsed;
17206
		if ( value !== "" ) {
17207
			parsed = this._parse( value );
17208
			if ( parsed !== null ) {
17209
				if ( !allowAny ) {
17210
					parsed = this._adjustValue( parsed );
17211
				}
17212
				value = this._format( parsed );
17213
			}
17214
		}
17215
		this.element.val( value );
17216
		this._refresh();
17217
	},
17218
17219
	_destroy: function() {
17220
		this.element
17221
			.prop( "disabled", false )
17222
			.removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
17223
17224
		this.uiSpinner.replaceWith( this.element );
17225
	},
17226
17227
	stepUp: spinnerModifer( function( steps ) {
17228
		this._stepUp( steps );
17229
	} ),
17230
	_stepUp: function( steps ) {
17231
		if ( this._start() ) {
17232
			this._spin( ( steps || 1 ) * this.options.step );
17233
			this._stop();
17234
		}
17235
	},
17236
17237
	stepDown: spinnerModifer( function( steps ) {
17238
		this._stepDown( steps );
17239
	} ),
17240
	_stepDown: function( steps ) {
17241
		if ( this._start() ) {
17242
			this._spin( ( steps || 1 ) * -this.options.step );
17243
			this._stop();
17244
		}
17245
	},
17246
17247
	pageUp: spinnerModifer( function( pages ) {
17248
		this._stepUp( ( pages || 1 ) * this.options.page );
17249
	} ),
17250
17251
	pageDown: spinnerModifer( function( pages ) {
17252
		this._stepDown( ( pages || 1 ) * this.options.page );
17253
	} ),
17254
17255
	value: function( newVal ) {
17256
		if ( !arguments.length ) {
17257
			return this._parse( this.element.val() );
17258
		}
17259
		spinnerModifer( this._value ).call( this, newVal );
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
17260
	},
17261
17262
	widget: function() {
17263
		return this.uiSpinner;
17264
	}
17265
} );
17266
17267
// DEPRECATED
17268
// TODO: switch return back to widget declaration at top of file when this is removed
17269
if ( $.uiBackCompat !== false ) {
17270
17271
	// Backcompat for spinner html extension points
17272
	$.widget( "ui.spinner", $.ui.spinner, {
17273
		_enhance: function() {
17274
			this.uiSpinner = this.element
17275
				.attr( "autocomplete", "off" )
17276
				.wrap( this._uiSpinnerHtml() )
17277
				.parent()
17278
17279
					// Add buttons
17280
					.append( this._buttonHtml() );
17281
		},
17282
		_uiSpinnerHtml: function() {
17283
			return "<span>";
17284
		},
17285
17286
		_buttonHtml: function() {
17287
			return "<a></a><a></a>";
17288
		}
17289
	} );
17290
}
17291
17292
var widgetsSpinner = $.ui.spinner;
0 ignored issues
show
Unused Code introduced by
The variable widgetsSpinner seems to be never used. Consider removing it.
Loading history...
17293
17294
17295
/*!
17296
 * jQuery UI Tabs 1.12.1
17297
 * http://jqueryui.com
17298
 *
17299
 * Copyright jQuery Foundation and other contributors
17300
 * Released under the MIT license.
17301
 * http://jquery.org/license
17302
 */
17303
17304
//>>label: Tabs
17305
//>>group: Widgets
17306
//>>description: Transforms a set of container elements into a tab structure.
17307
//>>docs: http://api.jqueryui.com/tabs/
17308
//>>demos: http://jqueryui.com/tabs/
17309
//>>css.structure: ../../themes/base/core.css
17310
//>>css.structure: ../../themes/base/tabs.css
17311
//>>css.theme: ../../themes/base/theme.css
17312
17313
17314
17315
$.widget( "ui.tabs", {
17316
	version: "1.12.1",
17317
	delay: 300,
17318
	options: {
17319
		active: null,
17320
		classes: {
17321
			"ui-tabs": "ui-corner-all",
17322
			"ui-tabs-nav": "ui-corner-all",
17323
			"ui-tabs-panel": "ui-corner-bottom",
17324
			"ui-tabs-tab": "ui-corner-top"
17325
		},
17326
		collapsible: false,
17327
		event: "click",
17328
		heightStyle: "content",
17329
		hide: null,
17330
		show: null,
17331
17332
		// Callbacks
17333
		activate: null,
17334
		beforeActivate: null,
17335
		beforeLoad: null,
17336
		load: null
17337
	},
17338
17339
	_isLocal: ( function() {
17340
		var rhash = /#.*$/;
17341
17342
		return function( anchor ) {
17343
			var anchorUrl, locationUrl;
17344
17345
			anchorUrl = anchor.href.replace( rhash, "" );
17346
			locationUrl = location.href.replace( rhash, "" );
17347
17348
			// Decoding may throw an error if the URL isn't UTF-8 (#9518)
17349
			try {
17350
				anchorUrl = decodeURIComponent( anchorUrl );
17351
			} catch ( error ) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
17352
			try {
17353
				locationUrl = decodeURIComponent( locationUrl );
17354
			} catch ( error ) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
17355
17356
			return anchor.hash.length > 1 && anchorUrl === locationUrl;
17357
		};
17358
	} )(),
17359
17360
	_create: function() {
17361
		var that = this,
17362
			options = this.options;
17363
17364
		this.running = false;
17365
17366
		this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
17367
		this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
17368
17369
		this._processTabs();
17370
		options.active = this._initialActive();
17371
17372
		// Take disabling tabs via class attribute from HTML
17373
		// into account and update option properly.
17374
		if ( $.isArray( options.disabled ) ) {
17375
			options.disabled = $.unique( options.disabled.concat(
17376
				$.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
17377
					return that.tabs.index( li );
17378
				} )
17379
			) ).sort();
17380
		}
17381
17382
		// Check for length avoids error when initializing empty list
17383
		if ( this.options.active !== false && this.anchors.length ) {
17384
			this.active = this._findActive( options.active );
17385
		} else {
17386
			this.active = $();
17387
		}
17388
17389
		this._refresh();
17390
17391
		if ( this.active.length ) {
17392
			this.load( options.active );
17393
		}
17394
	},
17395
17396
	_initialActive: function() {
17397
		var active = this.options.active,
17398
			collapsible = this.options.collapsible,
17399
			locationHash = location.hash.substring( 1 );
17400
17401
		if ( active === null ) {
17402
17403
			// check the fragment identifier in the URL
17404
			if ( locationHash ) {
17405
				this.tabs.each( function( i, tab ) {
17406
					if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if $(tab).attr("aria-controls") === locationHash 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...
17407
						active = i;
17408
						return false;
17409
					}
17410
				} );
17411
			}
17412
17413
			// Check for a tab marked active via a class
17414
			if ( active === null ) {
17415
				active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
17416
			}
17417
17418
			// No active tab, set to false
17419
			if ( active === null || active === -1 ) {
17420
				active = this.tabs.length ? 0 : false;
17421
			}
17422
		}
17423
17424
		// Handle numbers: negative, out of range
17425
		if ( active !== false ) {
17426
			active = this.tabs.index( this.tabs.eq( active ) );
17427
			if ( active === -1 ) {
17428
				active = collapsible ? false : 0;
17429
			}
17430
		}
17431
17432
		// Don't allow collapsible: false and active: false
17433
		if ( !collapsible && active === false && this.anchors.length ) {
17434
			active = 0;
17435
		}
17436
17437
		return active;
17438
	},
17439
17440
	_getCreateEventData: function() {
17441
		return {
17442
			tab: this.active,
17443
			panel: !this.active.length ? $() : this._getPanelForTab( this.active )
17444
		};
17445
	},
17446
17447
	_tabKeydown: function( event ) {
17448
		var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
17449
			selectedIndex = this.tabs.index( focusedTab ),
17450
			goingForward = true;
17451
17452
		if ( this._handlePageNav( event ) ) {
17453
			return;
17454
		}
17455
17456
		switch ( event.keyCode ) {
17457
		case $.ui.keyCode.RIGHT:
17458
		case $.ui.keyCode.DOWN:
17459
			selectedIndex++;
17460
			break;
17461
		case $.ui.keyCode.UP:
17462
		case $.ui.keyCode.LEFT:
17463
			goingForward = false;
17464
			selectedIndex--;
17465
			break;
17466
		case $.ui.keyCode.END:
17467
			selectedIndex = this.anchors.length - 1;
17468
			break;
17469
		case $.ui.keyCode.HOME:
17470
			selectedIndex = 0;
17471
			break;
17472
		case $.ui.keyCode.SPACE:
17473
17474
			// Activate only, no collapsing
17475
			event.preventDefault();
17476
			clearTimeout( this.activating );
17477
			this._activate( selectedIndex );
17478
			return;
17479
		case $.ui.keyCode.ENTER:
17480
17481
			// Toggle (cancel delayed activation, allow collapsing)
17482
			event.preventDefault();
17483
			clearTimeout( this.activating );
17484
17485
			// Determine if we should collapse or activate
17486
			this._activate( selectedIndex === this.options.active ? false : selectedIndex );
17487
			return;
17488
		default:
17489
			return;
17490
		}
17491
17492
		// Focus the appropriate tab, based on which key was pressed
17493
		event.preventDefault();
17494
		clearTimeout( this.activating );
17495
		selectedIndex = this._focusNextTab( selectedIndex, goingForward );
17496
17497
		// Navigating with control/command key will prevent automatic activation
17498
		if ( !event.ctrlKey && !event.metaKey ) {
17499
17500
			// Update aria-selected immediately so that AT think the tab is already selected.
17501
			// Otherwise AT may confuse the user by stating that they need to activate the tab,
17502
			// but the tab will already be activated by the time the announcement finishes.
17503
			focusedTab.attr( "aria-selected", "false" );
17504
			this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
17505
17506
			this.activating = this._delay( function() {
17507
				this.option( "active", selectedIndex );
17508
			}, this.delay );
17509
		}
17510
	},
17511
17512
	_panelKeydown: function( event ) {
17513
		if ( this._handlePageNav( event ) ) {
17514
			return;
17515
		}
17516
17517
		// Ctrl+up moves focus to the current tab
17518
		if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
17519
			event.preventDefault();
17520
			this.active.trigger( "focus" );
17521
		}
17522
	},
17523
17524
	// Alt+page up/down moves focus to the previous/next tab (and activates)
17525
	_handlePageNav: function( event ) {
17526
		if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
17527
			this._activate( this._focusNextTab( this.options.active - 1, false ) );
17528
			return true;
17529
		}
17530
		if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if event.altKey && event.ke... $.ui.keyCode.PAGE_DOWN 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...
17531
			this._activate( this._focusNextTab( this.options.active + 1, true ) );
17532
			return true;
17533
		}
17534
	},
17535
17536
	_findNextTab: function( index, goingForward ) {
17537
		var lastTabIndex = this.tabs.length - 1;
17538
17539
		function constrain() {
17540
			if ( index > lastTabIndex ) {
17541
				index = 0;
17542
			}
17543
			if ( index < 0 ) {
17544
				index = lastTabIndex;
17545
			}
17546
			return index;
17547
		}
17548
17549
		while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
17550
			index = goingForward ? index + 1 : index - 1;
17551
		}
17552
17553
		return index;
17554
	},
17555
17556
	_focusNextTab: function( index, goingForward ) {
17557
		index = this._findNextTab( index, goingForward );
17558
		this.tabs.eq( index ).trigger( "focus" );
17559
		return index;
17560
	},
17561
17562
	_setOption: function( key, value ) {
17563
		if ( key === "active" ) {
17564
17565
			// _activate() will handle invalid values and update this.options
17566
			this._activate( value );
17567
			return;
17568
		}
17569
17570
		this._super( key, value );
17571
17572
		if ( key === "collapsible" ) {
17573
			this._toggleClass( "ui-tabs-collapsible", null, value );
17574
17575
			// Setting collapsible: false while collapsed; open first panel
17576
			if ( !value && this.options.active === false ) {
17577
				this._activate( 0 );
17578
			}
17579
		}
17580
17581
		if ( key === "event" ) {
17582
			this._setupEvents( value );
17583
		}
17584
17585
		if ( key === "heightStyle" ) {
17586
			this._setupHeightStyle( value );
17587
		}
17588
	},
17589
17590
	_sanitizeSelector: function( hash ) {
17591
		return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
17592
	},
17593
17594
	refresh: function() {
17595
		var options = this.options,
17596
			lis = this.tablist.children( ":has(a[href])" );
17597
17598
		// Get disabled tabs from class attribute from HTML
17599
		// this will get converted to a boolean if needed in _refresh()
17600
		options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
17601
			return lis.index( tab );
17602
		} );
17603
17604
		this._processTabs();
17605
17606
		// Was collapsed or no tabs
17607
		if ( options.active === false || !this.anchors.length ) {
17608
			options.active = false;
17609
			this.active = $();
17610
17611
		// was active, but active tab is gone
17612
		} else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
17613
17614
			// all remaining tabs are disabled
17615
			if ( this.tabs.length === options.disabled.length ) {
17616
				options.active = false;
17617
				this.active = $();
17618
17619
			// activate previous tab
17620
			} else {
17621
				this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
17622
			}
17623
17624
		// was active, active tab still exists
17625
		} else {
17626
17627
			// make sure active index is correct
17628
			options.active = this.tabs.index( this.active );
17629
		}
17630
17631
		this._refresh();
17632
	},
17633
17634
	_refresh: function() {
17635
		this._setOptionDisabled( this.options.disabled );
17636
		this._setupEvents( this.options.event );
17637
		this._setupHeightStyle( this.options.heightStyle );
17638
17639
		this.tabs.not( this.active ).attr( {
17640
			"aria-selected": "false",
17641
			"aria-expanded": "false",
17642
			tabIndex: -1
17643
		} );
17644
		this.panels.not( this._getPanelForTab( this.active ) )
17645
			.hide()
17646
			.attr( {
17647
				"aria-hidden": "true"
17648
			} );
17649
17650
		// Make sure one tab is in the tab order
17651
		if ( !this.active.length ) {
17652
			this.tabs.eq( 0 ).attr( "tabIndex", 0 );
17653
		} else {
17654
			this.active
17655
				.attr( {
17656
					"aria-selected": "true",
17657
					"aria-expanded": "true",
17658
					tabIndex: 0
17659
				} );
17660
			this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
17661
			this._getPanelForTab( this.active )
17662
				.show()
17663
				.attr( {
17664
					"aria-hidden": "false"
17665
				} );
17666
		}
17667
	},
17668
17669
	_processTabs: function() {
17670
		var that = this,
17671
			prevTabs = this.tabs,
17672
			prevAnchors = this.anchors,
17673
			prevPanels = this.panels;
17674
17675
		this.tablist = this._getList().attr( "role", "tablist" );
17676
		this._addClass( this.tablist, "ui-tabs-nav",
17677
			"ui-helper-reset ui-helper-clearfix ui-widget-header" );
17678
17679
		// Prevent users from focusing disabled tabs via click
17680
		this.tablist
17681
			.on( "mousedown" + this.eventNamespace, "> li", function( event ) {
17682
				if ( $( this ).is( ".ui-state-disabled" ) ) {
17683
					event.preventDefault();
17684
				}
17685
			} )
17686
17687
			// Support: IE <9
17688
			// Preventing the default action in mousedown doesn't prevent IE
17689
			// from focusing the element, so if the anchor gets focused, blur.
17690
			// We don't have to worry about focusing the previously focused
17691
			// element since clicking on a non-focusable element should focus
17692
			// the body anyway.
17693
			.on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
17694
				if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
17695
					this.blur();
17696
				}
17697
			} );
17698
17699
		this.tabs = this.tablist.find( "> li:has(a[href])" )
17700
			.attr( {
17701
				role: "tab",
17702
				tabIndex: -1
17703
			} );
17704
		this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
17705
17706
		this.anchors = this.tabs.map( function() {
17707
			return $( "a", this )[ 0 ];
17708
		} )
17709
			.attr( {
17710
				role: "presentation",
17711
				tabIndex: -1
17712
			} );
17713
		this._addClass( this.anchors, "ui-tabs-anchor" );
17714
17715
		this.panels = $();
17716
17717
		this.anchors.each( function( i, anchor ) {
17718
			var selector, panel, panelId,
17719
				anchorId = $( anchor ).uniqueId().attr( "id" ),
17720
				tab = $( anchor ).closest( "li" ),
17721
				originalAriaControls = tab.attr( "aria-controls" );
17722
17723
			// Inline tab
17724
			if ( that._isLocal( anchor ) ) {
17725
				selector = anchor.hash;
17726
				panelId = selector.substring( 1 );
17727
				panel = that.element.find( that._sanitizeSelector( selector ) );
17728
17729
			// remote tab
17730
			} else {
17731
17732
				// If the tab doesn't already have aria-controls,
17733
				// generate an id by using a throw-away element
17734
				panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
17735
				selector = "#" + panelId;
17736
				panel = that.element.find( selector );
17737
				if ( !panel.length ) {
17738
					panel = that._createPanel( panelId );
17739
					panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
17740
				}
17741
				panel.attr( "aria-live", "polite" );
17742
			}
17743
17744
			if ( panel.length ) {
17745
				that.panels = that.panels.add( panel );
17746
			}
17747
			if ( originalAriaControls ) {
17748
				tab.data( "ui-tabs-aria-controls", originalAriaControls );
17749
			}
17750
			tab.attr( {
17751
				"aria-controls": panelId,
17752
				"aria-labelledby": anchorId
17753
			} );
17754
			panel.attr( "aria-labelledby", anchorId );
17755
		} );
17756
17757
		this.panels.attr( "role", "tabpanel" );
17758
		this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
17759
17760
		// Avoid memory leaks (#10056)
17761
		if ( prevTabs ) {
17762
			this._off( prevTabs.not( this.tabs ) );
17763
			this._off( prevAnchors.not( this.anchors ) );
17764
			this._off( prevPanels.not( this.panels ) );
17765
		}
17766
	},
17767
17768
	// Allow overriding how to find the list for rare usage scenarios (#7715)
17769
	_getList: function() {
17770
		return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
17771
	},
17772
17773
	_createPanel: function( id ) {
17774
		return $( "<div>" )
17775
			.attr( "id", id )
17776
			.data( "ui-tabs-destroy", true );
17777
	},
17778
17779
	_setOptionDisabled: function( disabled ) {
17780
		var currentItem, li, i;
17781
17782
		if ( $.isArray( disabled ) ) {
17783
			if ( !disabled.length ) {
17784
				disabled = false;
17785
			} else if ( disabled.length === this.anchors.length ) {
17786
				disabled = true;
17787
			}
17788
		}
17789
17790
		// Disable tabs
17791
		for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
17792
			currentItem = $( li );
17793
			if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
17794
				currentItem.attr( "aria-disabled", "true" );
17795
				this._addClass( currentItem, null, "ui-state-disabled" );
17796
			} else {
17797
				currentItem.removeAttr( "aria-disabled" );
17798
				this._removeClass( currentItem, null, "ui-state-disabled" );
17799
			}
17800
		}
17801
17802
		this.options.disabled = disabled;
17803
17804
		this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
17805
			disabled === true );
17806
	},
17807
17808
	_setupEvents: function( event ) {
17809
		var events = {};
17810
		if ( event ) {
17811
			$.each( event.split( " " ), function( index, eventName ) {
17812
				events[ eventName ] = "_eventHandler";
17813
			} );
17814
		}
17815
17816
		this._off( this.anchors.add( this.tabs ).add( this.panels ) );
17817
17818
		// Always prevent the default action, even when disabled
17819
		this._on( true, this.anchors, {
17820
			click: function( event ) {
17821
				event.preventDefault();
17822
			}
17823
		} );
17824
		this._on( this.anchors, events );
17825
		this._on( this.tabs, { keydown: "_tabKeydown" } );
17826
		this._on( this.panels, { keydown: "_panelKeydown" } );
17827
17828
		this._focusable( this.tabs );
17829
		this._hoverable( this.tabs );
17830
	},
17831
17832
	_setupHeightStyle: function( heightStyle ) {
17833
		var maxHeight,
17834
			parent = this.element.parent();
17835
17836
		if ( heightStyle === "fill" ) {
17837
			maxHeight = parent.height();
17838
			maxHeight -= this.element.outerHeight() - this.element.height();
17839
17840
			this.element.siblings( ":visible" ).each( function() {
17841
				var elem = $( this ),
17842
					position = elem.css( "position" );
17843
17844
				if ( position === "absolute" || position === "fixed" ) {
17845
					return;
17846
				}
17847
				maxHeight -= elem.outerHeight( true );
17848
			} );
17849
17850
			this.element.children().not( this.panels ).each( function() {
17851
				maxHeight -= $( this ).outerHeight( true );
17852
			} );
17853
17854
			this.panels.each( function() {
17855
				$( this ).height( Math.max( 0, maxHeight -
17856
					$( this ).innerHeight() + $( this ).height() ) );
17857
			} )
17858
				.css( "overflow", "auto" );
17859
		} else if ( heightStyle === "auto" ) {
17860
			maxHeight = 0;
17861
			this.panels.each( function() {
17862
				maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
17863
			} ).height( maxHeight );
17864
		}
17865
	},
17866
17867
	_eventHandler: function( event ) {
17868
		var options = this.options,
17869
			active = this.active,
17870
			anchor = $( event.currentTarget ),
17871
			tab = anchor.closest( "li" ),
17872
			clickedIsActive = tab[ 0 ] === active[ 0 ],
17873
			collapsing = clickedIsActive && options.collapsible,
17874
			toShow = collapsing ? $() : this._getPanelForTab( tab ),
17875
			toHide = !active.length ? $() : this._getPanelForTab( active ),
17876
			eventData = {
17877
				oldTab: active,
17878
				oldPanel: toHide,
17879
				newTab: collapsing ? $() : tab,
17880
				newPanel: toShow
17881
			};
17882
17883
		event.preventDefault();
17884
17885
		if ( tab.hasClass( "ui-state-disabled" ) ||
17886
17887
				// tab is already loading
17888
				tab.hasClass( "ui-tabs-loading" ) ||
17889
17890
				// can't switch durning an animation
17891
				this.running ||
17892
17893
				// click on active header, but not collapsible
17894
				( clickedIsActive && !options.collapsible ) ||
17895
17896
				// allow canceling activation
17897
				( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
17898
			return;
17899
		}
17900
17901
		options.active = collapsing ? false : this.tabs.index( tab );
17902
17903
		this.active = clickedIsActive ? $() : tab;
17904
		if ( this.xhr ) {
17905
			this.xhr.abort();
17906
		}
17907
17908
		if ( !toHide.length && !toShow.length ) {
17909
			$.error( "jQuery UI Tabs: Mismatching fragment identifier." );
17910
		}
17911
17912
		if ( toShow.length ) {
17913
			this.load( this.tabs.index( tab ), event );
17914
		}
17915
		this._toggle( event, eventData );
17916
	},
17917
17918
	// Handles show/hide for selecting tabs
17919
	_toggle: function( event, eventData ) {
17920
		var that = this,
17921
			toShow = eventData.newPanel,
17922
			toHide = eventData.oldPanel;
17923
17924
		this.running = true;
17925
17926
		function complete() {
17927
			that.running = false;
17928
			that._trigger( "activate", event, eventData );
17929
		}
17930
17931
		function show() {
17932
			that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
17933
17934
			if ( toShow.length && that.options.show ) {
17935
				that._show( toShow, that.options.show, complete );
17936
			} else {
17937
				toShow.show();
17938
				complete();
17939
			}
17940
		}
17941
17942
		// Start out by hiding, then showing, then completing
17943
		if ( toHide.length && this.options.hide ) {
17944
			this._hide( toHide, this.options.hide, function() {
17945
				that._removeClass( eventData.oldTab.closest( "li" ),
17946
					"ui-tabs-active", "ui-state-active" );
17947
				show();
17948
			} );
17949
		} else {
17950
			this._removeClass( eventData.oldTab.closest( "li" ),
17951
				"ui-tabs-active", "ui-state-active" );
17952
			toHide.hide();
17953
			show();
17954
		}
17955
17956
		toHide.attr( "aria-hidden", "true" );
17957
		eventData.oldTab.attr( {
17958
			"aria-selected": "false",
17959
			"aria-expanded": "false"
17960
		} );
17961
17962
		// If we're switching tabs, remove the old tab from the tab order.
17963
		// If we're opening from collapsed state, remove the previous tab from the tab order.
17964
		// If we're collapsing, then keep the collapsing tab in the tab order.
17965
		if ( toShow.length && toHide.length ) {
17966
			eventData.oldTab.attr( "tabIndex", -1 );
17967
		} else if ( toShow.length ) {
17968
			this.tabs.filter( function() {
17969
				return $( this ).attr( "tabIndex" ) === 0;
17970
			} )
17971
				.attr( "tabIndex", -1 );
17972
		}
17973
17974
		toShow.attr( "aria-hidden", "false" );
17975
		eventData.newTab.attr( {
17976
			"aria-selected": "true",
17977
			"aria-expanded": "true",
17978
			tabIndex: 0
17979
		} );
17980
	},
17981
17982
	_activate: function( index ) {
17983
		var anchor,
17984
			active = this._findActive( index );
17985
17986
		// Trying to activate the already active panel
17987
		if ( active[ 0 ] === this.active[ 0 ] ) {
17988
			return;
17989
		}
17990
17991
		// Trying to collapse, simulate a click on the current active header
17992
		if ( !active.length ) {
17993
			active = this.active;
17994
		}
17995
17996
		anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
17997
		this._eventHandler( {
17998
			target: anchor,
17999
			currentTarget: anchor,
18000
			preventDefault: $.noop
18001
		} );
18002
	},
18003
18004
	_findActive: function( index ) {
18005
		return index === false ? $() : this.tabs.eq( index );
18006
	},
18007
18008
	_getIndex: function( index ) {
18009
18010
		// meta-function to give users option to provide a href string instead of a numerical index.
18011
		if ( typeof index === "string" ) {
18012
			index = this.anchors.index( this.anchors.filter( "[href$='" +
18013
				$.ui.escapeSelector( index ) + "']" ) );
18014
		}
18015
18016
		return index;
18017
	},
18018
18019
	_destroy: function() {
18020
		if ( this.xhr ) {
18021
			this.xhr.abort();
18022
		}
18023
18024
		this.tablist
18025
			.removeAttr( "role" )
18026
			.off( this.eventNamespace );
18027
18028
		this.anchors
18029
			.removeAttr( "role tabIndex" )
18030
			.removeUniqueId();
18031
18032
		this.tabs.add( this.panels ).each( function() {
18033
			if ( $.data( this, "ui-tabs-destroy" ) ) {
18034
				$( this ).remove();
18035
			} else {
18036
				$( this ).removeAttr( "role tabIndex " +
18037
					"aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
18038
			}
18039
		} );
18040
18041
		this.tabs.each( function() {
18042
			var li = $( this ),
18043
				prev = li.data( "ui-tabs-aria-controls" );
18044
			if ( prev ) {
18045
				li
18046
					.attr( "aria-controls", prev )
18047
					.removeData( "ui-tabs-aria-controls" );
18048
			} else {
18049
				li.removeAttr( "aria-controls" );
18050
			}
18051
		} );
18052
18053
		this.panels.show();
18054
18055
		if ( this.options.heightStyle !== "content" ) {
18056
			this.panels.css( "height", "" );
18057
		}
18058
	},
18059
18060
	enable: function( index ) {
18061
		var disabled = this.options.disabled;
18062
		if ( disabled === false ) {
18063
			return;
18064
		}
18065
18066
		if ( index === undefined ) {
18067
			disabled = false;
18068
		} else {
18069
			index = this._getIndex( index );
18070
			if ( $.isArray( disabled ) ) {
18071
				disabled = $.map( disabled, function( num ) {
18072
					return num !== index ? num : null;
18073
				} );
18074
			} else {
18075
				disabled = $.map( this.tabs, function( li, num ) {
18076
					return num !== index ? num : null;
18077
				} );
18078
			}
18079
		}
18080
		this._setOptionDisabled( disabled );
18081
	},
18082
18083
	disable: function( index ) {
18084
		var disabled = this.options.disabled;
18085
		if ( disabled === true ) {
18086
			return;
18087
		}
18088
18089
		if ( index === undefined ) {
18090
			disabled = true;
18091
		} else {
18092
			index = this._getIndex( index );
18093
			if ( $.inArray( index, disabled ) !== -1 ) {
18094
				return;
18095
			}
18096
			if ( $.isArray( disabled ) ) {
18097
				disabled = $.merge( [ index ], disabled ).sort();
18098
			} else {
18099
				disabled = [ index ];
18100
			}
18101
		}
18102
		this._setOptionDisabled( disabled );
18103
	},
18104
18105
	load: function( index, event ) {
18106
		index = this._getIndex( index );
18107
		var that = this,
18108
			tab = this.tabs.eq( index ),
18109
			anchor = tab.find( ".ui-tabs-anchor" ),
18110
			panel = this._getPanelForTab( tab ),
18111
			eventData = {
18112
				tab: tab,
18113
				panel: panel
18114
			},
18115
			complete = function( jqXHR, status ) {
18116
				if ( status === "abort" ) {
18117
					that.panels.stop( false, true );
18118
				}
18119
18120
				that._removeClass( tab, "ui-tabs-loading" );
18121
				panel.removeAttr( "aria-busy" );
18122
18123
				if ( jqXHR === that.xhr ) {
18124
					delete that.xhr;
18125
				}
18126
			};
18127
18128
		// Not remote
18129
		if ( this._isLocal( anchor[ 0 ] ) ) {
18130
			return;
18131
		}
18132
18133
		this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
18134
18135
		// Support: jQuery <1.8
18136
		// jQuery <1.8 returns false if the request is canceled in beforeSend,
18137
		// but as of 1.8, $.ajax() always returns a jqXHR object.
18138
		if ( this.xhr && this.xhr.statusText !== "canceled" ) {
18139
			this._addClass( tab, "ui-tabs-loading" );
18140
			panel.attr( "aria-busy", "true" );
18141
18142
			this.xhr
18143
				.done( function( response, status, jqXHR ) {
18144
18145
					// support: jQuery <1.8
18146
					// http://bugs.jquery.com/ticket/11778
18147
					setTimeout( function() {
18148
						panel.html( response );
18149
						that._trigger( "load", event, eventData );
18150
18151
						complete( jqXHR, status );
18152
					}, 1 );
18153
				} )
18154
				.fail( function( jqXHR, status ) {
18155
18156
					// support: jQuery <1.8
18157
					// http://bugs.jquery.com/ticket/11778
18158
					setTimeout( function() {
18159
						complete( jqXHR, status );
18160
					}, 1 );
18161
				} );
18162
		}
18163
	},
18164
18165
	_ajaxSettings: function( anchor, event, eventData ) {
18166
		var that = this;
18167
		return {
18168
18169
			// Support: IE <11 only
18170
			// Strip any hash that exists to prevent errors with the Ajax request
18171
			url: anchor.attr( "href" ).replace( /#.*$/, "" ),
18172
			beforeSend: function( jqXHR, settings ) {
18173
				return that._trigger( "beforeLoad", event,
18174
					$.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
18175
			}
18176
		};
18177
	},
18178
18179
	_getPanelForTab: function( tab ) {
18180
		var id = $( tab ).attr( "aria-controls" );
18181
		return this.element.find( this._sanitizeSelector( "#" + id ) );
18182
	}
18183
} );
18184
18185
// DEPRECATED
18186
// TODO: Switch return back to widget declaration at top of file when this is removed
18187
if ( $.uiBackCompat !== false ) {
18188
18189
	// Backcompat for ui-tab class (now ui-tabs-tab)
18190
	$.widget( "ui.tabs", $.ui.tabs, {
18191
		_processTabs: function() {
18192
			this._superApply( arguments );
18193
			this._addClass( this.tabs, "ui-tab" );
18194
		}
18195
	} );
18196
}
18197
18198
var widgetsTabs = $.ui.tabs;
0 ignored issues
show
Unused Code introduced by
The variable widgetsTabs seems to be never used. Consider removing it.
Loading history...
18199
18200
18201
/*!
18202
 * jQuery UI Tooltip 1.12.1
18203
 * http://jqueryui.com
18204
 *
18205
 * Copyright jQuery Foundation and other contributors
18206
 * Released under the MIT license.
18207
 * http://jquery.org/license
18208
 */
18209
18210
//>>label: Tooltip
18211
//>>group: Widgets
18212
//>>description: Shows additional information for any element on hover or focus.
18213
//>>docs: http://api.jqueryui.com/tooltip/
18214
//>>demos: http://jqueryui.com/tooltip/
18215
//>>css.structure: ../../themes/base/core.css
18216
//>>css.structure: ../../themes/base/tooltip.css
18217
//>>css.theme: ../../themes/base/theme.css
18218
18219
18220
18221
$.widget( "ui.tooltip", {
18222
	version: "1.12.1",
18223
	options: {
18224
		classes: {
18225
			"ui-tooltip": "ui-corner-all ui-widget-shadow"
18226
		},
18227
		content: function() {
18228
18229
			// support: IE<9, Opera in jQuery <1.7
18230
			// .text() can't accept undefined, so coerce to a string
18231
			var title = $( this ).attr( "title" ) || "";
18232
18233
			// Escape title, since we're going from an attribute to raw HTML
18234
			return $( "<a>" ).text( title ).html();
18235
		},
18236
		hide: true,
18237
18238
		// Disabled elements have inconsistent behavior across browsers (#8661)
18239
		items: "[title]:not([disabled])",
18240
		position: {
18241
			my: "left top+15",
18242
			at: "left bottom",
18243
			collision: "flipfit flip"
18244
		},
18245
		show: true,
18246
		track: false,
18247
18248
		// Callbacks
18249
		close: null,
18250
		open: null
18251
	},
18252
18253
	_addDescribedBy: function( elem, id ) {
18254
		var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
18255
		describedby.push( id );
18256
		elem
18257
			.data( "ui-tooltip-id", id )
18258
			.attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
18259
	},
18260
18261
	_removeDescribedBy: function( elem ) {
18262
		var id = elem.data( "ui-tooltip-id" ),
18263
			describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
18264
			index = $.inArray( id, describedby );
18265
18266
		if ( index !== -1 ) {
18267
			describedby.splice( index, 1 );
18268
		}
18269
18270
		elem.removeData( "ui-tooltip-id" );
18271
		describedby = $.trim( describedby.join( " " ) );
18272
		if ( describedby ) {
18273
			elem.attr( "aria-describedby", describedby );
18274
		} else {
18275
			elem.removeAttr( "aria-describedby" );
18276
		}
18277
	},
18278
18279
	_create: function() {
18280
		this._on( {
18281
			mouseover: "open",
18282
			focusin: "open"
18283
		} );
18284
18285
		// IDs of generated tooltips, needed for destroy
18286
		this.tooltips = {};
18287
18288
		// IDs of parent tooltips where we removed the title attribute
18289
		this.parents = {};
18290
18291
		// Append the aria-live region so tooltips announce correctly
18292
		this.liveRegion = $( "<div>" )
18293
			.attr( {
18294
				role: "log",
18295
				"aria-live": "assertive",
18296
				"aria-relevant": "additions"
18297
			} )
18298
			.appendTo( this.document[ 0 ].body );
18299
		this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
18300
18301
		this.disabledTitles = $( [] );
18302
	},
18303
18304
	_setOption: function( key, value ) {
18305
		var that = this;
18306
18307
		this._super( key, value );
18308
18309
		if ( key === "content" ) {
18310
			$.each( this.tooltips, function( id, tooltipData ) {
18311
				that._updateContent( tooltipData.element );
18312
			} );
18313
		}
18314
	},
18315
18316
	_setOptionDisabled: function( value ) {
18317
		this[ value ? "_disable" : "_enable" ]();
18318
	},
18319
18320
	_disable: function() {
18321
		var that = this;
18322
18323
		// Close open tooltips
18324
		$.each( this.tooltips, function( id, tooltipData ) {
18325
			var event = $.Event( "blur" );
18326
			event.target = event.currentTarget = tooltipData.element[ 0 ];
18327
			that.close( event, true );
18328
		} );
18329
18330
		// Remove title attributes to prevent native tooltips
18331
		this.disabledTitles = this.disabledTitles.add(
18332
			this.element.find( this.options.items ).addBack()
18333
				.filter( function() {
18334
					var element = $( this );
18335
					if ( element.is( "[title]" ) ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if element.is("[title]") 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...
18336
						return element
18337
							.data( "ui-tooltip-title", element.attr( "title" ) )
18338
							.removeAttr( "title" );
18339
					}
18340
				} )
18341
		);
18342
	},
18343
18344
	_enable: function() {
18345
18346
		// restore title attributes
18347
		this.disabledTitles.each( function() {
18348
			var element = $( this );
18349
			if ( element.data( "ui-tooltip-title" ) ) {
18350
				element.attr( "title", element.data( "ui-tooltip-title" ) );
18351
			}
18352
		} );
18353
		this.disabledTitles = $( [] );
18354
	},
18355
18356
	open: function( event ) {
18357
		var that = this,
18358
			target = $( event ? event.target : this.element )
18359
18360
				// we need closest here due to mouseover bubbling,
18361
				// but always pointing at the same event target
18362
				.closest( this.options.items );
18363
18364
		// No element to show a tooltip for or the tooltip is already open
18365
		if ( !target.length || target.data( "ui-tooltip-id" ) ) {
18366
			return;
18367
		}
18368
18369
		if ( target.attr( "title" ) ) {
18370
			target.data( "ui-tooltip-title", target.attr( "title" ) );
18371
		}
18372
18373
		target.data( "ui-tooltip-open", true );
18374
18375
		// Kill parent tooltips, custom or native, for hover
18376
		if ( event && event.type === "mouseover" ) {
18377
			target.parents().each( function() {
18378
				var parent = $( this ),
18379
					blurEvent;
18380
				if ( parent.data( "ui-tooltip-open" ) ) {
18381
					blurEvent = $.Event( "blur" );
18382
					blurEvent.target = blurEvent.currentTarget = this;
18383
					that.close( blurEvent, true );
18384
				}
18385
				if ( parent.attr( "title" ) ) {
18386
					parent.uniqueId();
18387
					that.parents[ this.id ] = {
18388
						element: this,
18389
						title: parent.attr( "title" )
18390
					};
18391
					parent.attr( "title", "" );
18392
				}
18393
			} );
18394
		}
18395
18396
		this._registerCloseHandlers( event, target );
18397
		this._updateContent( target, event );
18398
	},
18399
18400
	_updateContent: function( target, event ) {
18401
		var content,
18402
			contentOption = this.options.content,
18403
			that = this,
18404
			eventType = event ? event.type : null;
18405
18406
		if ( typeof contentOption === "string" || contentOption.nodeType ||
18407
				contentOption.jquery ) {
18408
			return this._open( event, target, contentOption );
18409
		}
18410
18411
		content = contentOption.call( target[ 0 ], function( response ) {
18412
18413
			// IE may instantly serve a cached response for ajax requests
18414
			// delay this call to _open so the other call to _open runs first
18415
			that._delay( function() {
18416
18417
				// Ignore async response if tooltip was closed already
18418
				if ( !target.data( "ui-tooltip-open" ) ) {
18419
					return;
18420
				}
18421
18422
				// JQuery creates a special event for focusin when it doesn't
18423
				// exist natively. To improve performance, the native event
18424
				// object is reused and the type is changed. Therefore, we can't
18425
				// rely on the type being correct after the event finished
18426
				// bubbling, so we set it back to the previous value. (#8740)
18427
				if ( event ) {
18428
					event.type = eventType;
18429
				}
18430
				this._open( event, target, response );
18431
			} );
18432
		} );
18433
		if ( content ) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if content 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...
18434
			this._open( event, target, content );
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
18435
		}
18436
	},
18437
18438
	_open: function( event, target, content ) {
18439
		var tooltipData, tooltip, delayedShow, a11yContent,
18440
			positionOption = $.extend( {}, this.options.position );
18441
18442
		if ( !content ) {
18443
			return;
18444
		}
18445
18446
		// Content can be updated multiple times. If the tooltip already
18447
		// exists, then just update the content and bail.
18448
		tooltipData = this._find( target );
18449
		if ( tooltipData ) {
18450
			tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
18451
			return;
18452
		}
18453
18454
		// If we have a title, clear it to prevent the native tooltip
18455
		// we have to check first to avoid defining a title if none exists
18456
		// (we don't want to cause an element to start matching [title])
18457
		//
18458
		// We use removeAttr only for key events, to allow IE to export the correct
18459
		// accessible attributes. For mouse events, set to empty string to avoid
18460
		// native tooltip showing up (happens only when removing inside mouseover).
18461
		if ( target.is( "[title]" ) ) {
18462
			if ( event && event.type === "mouseover" ) {
18463
				target.attr( "title", "" );
18464
			} else {
18465
				target.removeAttr( "title" );
18466
			}
18467
		}
18468
18469
		tooltipData = this._tooltip( target );
18470
		tooltip = tooltipData.tooltip;
18471
		this._addDescribedBy( target, tooltip.attr( "id" ) );
18472
		tooltip.find( ".ui-tooltip-content" ).html( content );
18473
18474
		// Support: Voiceover on OS X, JAWS on IE <= 9
18475
		// JAWS announces deletions even when aria-relevant="additions"
18476
		// Voiceover will sometimes re-read the entire log region's contents from the beginning
18477
		this.liveRegion.children().hide();
18478
		a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
18479
		a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
18480
		a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
18481
		a11yContent.appendTo( this.liveRegion );
18482
18483
		function position( event ) {
18484
			positionOption.of = event;
18485
			if ( tooltip.is( ":hidden" ) ) {
18486
				return;
18487
			}
18488
			tooltip.position( positionOption );
18489
		}
18490
		if ( this.options.track && event && /^mouse/.test( event.type ) ) {
18491
			this._on( this.document, {
18492
				mousemove: position
18493
			} );
18494
18495
			// trigger once to override element-relative positioning
18496
			position( event );
18497
		} else {
18498
			tooltip.position( $.extend( {
18499
				of: target
18500
			}, this.options.position ) );
18501
		}
18502
18503
		tooltip.hide();
18504
18505
		this._show( tooltip, this.options.show );
18506
18507
		// Handle tracking tooltips that are shown with a delay (#8644). As soon
18508
		// as the tooltip is visible, position the tooltip using the most recent
18509
		// event.
18510
		// Adds the check to add the timers only when both delay and track options are set (#14682)
18511
		if ( this.options.track && this.options.show && this.options.show.delay ) {
18512
			delayedShow = this.delayedShow = setInterval( function() {
18513
				if ( tooltip.is( ":visible" ) ) {
18514
					position( positionOption.of );
18515
					clearInterval( delayedShow );
18516
				}
18517
			}, $.fx.interval );
18518
		}
18519
18520
		this._trigger( "open", event, { tooltip: tooltip } );
18521
	},
18522
18523
	_registerCloseHandlers: function( event, target ) {
18524
		var events = {
18525
			keyup: function( event ) {
18526
				if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
18527
					var fakeEvent = $.Event( event );
18528
					fakeEvent.currentTarget = target[ 0 ];
18529
					this.close( fakeEvent, true );
18530
				}
18531
			}
18532
		};
18533
18534
		// Only bind remove handler for delegated targets. Non-delegated
18535
		// tooltips will handle this in destroy.
18536
		if ( target[ 0 ] !== this.element[ 0 ] ) {
18537
			events.remove = function() {
18538
				this._removeTooltip( this._find( target ).tooltip );
18539
			};
18540
		}
18541
18542
		if ( !event || event.type === "mouseover" ) {
18543
			events.mouseleave = "close";
18544
		}
18545
		if ( !event || event.type === "focusin" ) {
18546
			events.focusout = "close";
18547
		}
18548
		this._on( true, target, events );
18549
	},
18550
18551
	close: function( event ) {
18552
		var tooltip,
18553
			that = this,
18554
			target = $( event ? event.currentTarget : this.element ),
18555
			tooltipData = this._find( target );
18556
18557
		// The tooltip may already be closed
18558
		if ( !tooltipData ) {
18559
18560
			// We set ui-tooltip-open immediately upon open (in open()), but only set the
18561
			// additional data once there's actually content to show (in _open()). So even if the
18562
			// tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
18563
			// the period between open() and _open().
18564
			target.removeData( "ui-tooltip-open" );
18565
			return;
18566
		}
18567
18568
		tooltip = tooltipData.tooltip;
18569
18570
		// Disabling closes the tooltip, so we need to track when we're closing
18571
		// to avoid an infinite loop in case the tooltip becomes disabled on close
18572
		if ( tooltipData.closing ) {
18573
			return;
18574
		}
18575
18576
		// Clear the interval for delayed tracking tooltips
18577
		clearInterval( this.delayedShow );
18578
18579
		// Only set title if we had one before (see comment in _open())
18580
		// If the title attribute has changed since open(), don't restore
18581
		if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
18582
			target.attr( "title", target.data( "ui-tooltip-title" ) );
18583
		}
18584
18585
		this._removeDescribedBy( target );
18586
18587
		tooltipData.hiding = true;
18588
		tooltip.stop( true );
18589
		this._hide( tooltip, this.options.hide, function() {
18590
			that._removeTooltip( $( this ) );
18591
		} );
18592
18593
		target.removeData( "ui-tooltip-open" );
18594
		this._off( target, "mouseleave focusout keyup" );
18595
18596
		// Remove 'remove' binding only on delegated targets
18597
		if ( target[ 0 ] !== this.element[ 0 ] ) {
18598
			this._off( target, "remove" );
18599
		}
18600
		this._off( this.document, "mousemove" );
18601
18602
		if ( event && event.type === "mouseleave" ) {
18603
			$.each( this.parents, function( id, parent ) {
18604
				$( parent.element ).attr( "title", parent.title );
18605
				delete that.parents[ id ];
18606
			} );
18607
		}
18608
18609
		tooltipData.closing = true;
18610
		this._trigger( "close", event, { tooltip: tooltip } );
18611
		if ( !tooltipData.hiding ) {
18612
			tooltipData.closing = false;
18613
		}
18614
	},
18615
18616
	_tooltip: function( element ) {
18617
		var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
18618
			content = $( "<div>" ).appendTo( tooltip ),
18619
			id = tooltip.uniqueId().attr( "id" );
18620
18621
		this._addClass( content, "ui-tooltip-content" );
18622
		this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
18623
18624
		tooltip.appendTo( this._appendTo( element ) );
18625
18626
		return this.tooltips[ id ] = {
18627
			element: element,
18628
			tooltip: tooltip
18629
		};
18630
	},
18631
18632
	_find: function( target ) {
18633
		var id = target.data( "ui-tooltip-id" );
18634
		return id ? this.tooltips[ id ] : null;
18635
	},
18636
18637
	_removeTooltip: function( tooltip ) {
18638
		tooltip.remove();
18639
		delete this.tooltips[ tooltip.attr( "id" ) ];
18640
	},
18641
18642
	_appendTo: function( target ) {
18643
		var element = target.closest( ".ui-front, dialog" );
18644
18645
		if ( !element.length ) {
18646
			element = this.document[ 0 ].body;
18647
		}
18648
18649
		return element;
18650
	},
18651
18652
	_destroy: function() {
18653
		var that = this;
18654
18655
		// Close open tooltips
18656
		$.each( this.tooltips, function( id, tooltipData ) {
18657
18658
			// Delegate to close method to handle common cleanup
18659
			var event = $.Event( "blur" ),
18660
				element = tooltipData.element;
18661
			event.target = event.currentTarget = element[ 0 ];
18662
			that.close( event, true );
18663
18664
			// Remove immediately; destroying an open tooltip doesn't use the
18665
			// hide animation
18666
			$( "#" + id ).remove();
18667
18668
			// Restore the title
18669
			if ( element.data( "ui-tooltip-title" ) ) {
18670
18671
				// If the title attribute has changed since open(), don't restore
18672
				if ( !element.attr( "title" ) ) {
18673
					element.attr( "title", element.data( "ui-tooltip-title" ) );
18674
				}
18675
				element.removeData( "ui-tooltip-title" );
18676
			}
18677
		} );
18678
		this.liveRegion.remove();
18679
	}
18680
} );
18681
18682
// DEPRECATED
18683
// TODO: Switch return back to widget declaration at top of file when this is removed
18684
if ( $.uiBackCompat !== false ) {
18685
18686
	// Backcompat for tooltipClass option
18687
	$.widget( "ui.tooltip", $.ui.tooltip, {
18688
		options: {
18689
			tooltipClass: null
18690
		},
18691
		_tooltip: function() {
18692
			var tooltipData = this._superApply( arguments );
18693
			if ( this.options.tooltipClass ) {
18694
				tooltipData.tooltip.addClass( this.options.tooltipClass );
18695
			}
18696
			return tooltipData;
18697
		}
18698
	} );
18699
}
18700
18701
var widgetsTooltip = $.ui.tooltip;
0 ignored issues
show
Unused Code introduced by
The variable widgetsTooltip seems to be never used. Consider removing it.
Loading history...
18702
18703
18704
18705
18706
}));