PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 1.3.0
Forumax – AI Powered Advanced Community Forum Plugin v1.3.0
2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 trunk 1.0.8 1.1.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 2.0.0 2.1.0 All 29 releases
bbp-core / assets / js / jquery-ui.js

jquery-ui.js in Forumax – AI Powered Advanced Community Forum Plugin 1.3.0, at assets/js/jquery-ui.js

18,706 lines 526.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*! jQuery UI - v1.12.1 - 2021-10-02
2 * http://jqueryui.com
3 * Includes: widget.js, position.js, data.js, disable-selection.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/draggable.js, widgets/droppable.js, widgets/resizable.js, widgets/selectable.js, widgets/sortable.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/selectmenu.js, widgets/slider.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.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
4 * Copyright jQuery Foundation and other contributors; Licensed MIT */
5
6 (function( factory ) {
7 if ( typeof define === "function" && define.amd ) {
8
9 // AMD. Register as an anonymous module.
10 define([ "jquery" ], factory );
11 } else {
12
13 // Browser globals
14 factory( jQuery );
15 }
16 }(function( $ ) {
17
18 $.ui = $.ui || {};
19
20 var version = $.ui.version = "1.12.1";
21
22
23 /*!
24 * jQuery UI Widget 1.12.1
25 * http://jqueryui.com
26 *
27 * Copyright jQuery Foundation and other contributors
28 * Released under the MIT license.
29 * http://jquery.org/license
30 */
31
32 //>>label: Widget
33 //>>group: Core
34 //>>description: Provides a factory for creating stateful widgets with a common API.
35 //>>docs: http://api.jqueryui.com/jQuery.widget/
36 //>>demos: http://jqueryui.com/widget/
37
38
39
40 var widgetUuid = 0;
41 var widgetSlice = Array.prototype.slice;
42
43 $.cleanData = ( function( orig ) {
44 return function( elems ) {
45 var events, elem, i;
46 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
47 try {
48
49 // Only trigger remove when necessary to save time
50 events = $._data( elem, "events" );
51 if ( events && events.remove ) {
52 $( elem ).triggerHandler( "remove" );
53 }
54
55 // Http://bugs.jquery.com/ticket/8235
56 } catch ( e ) {}
57 }
58 orig( elems );
59 };
60 } )( $.cleanData );
61
62 $.widget = function( name, base, prototype ) {
63 var existingConstructor, constructor, basePrototype;
64
65 // ProxiedPrototype allows the provided prototype to remain unmodified
66 // so that it can be used as a mixin for multiple widgets (#8876)
67 var proxiedPrototype = {};
68
69 var namespace = name.split( "." )[ 0 ];
70 name = name.split( "." )[ 1 ];
71 var fullName = namespace + "-" + name;
72
73 if ( !prototype ) {
74 prototype = base;
75 base = $.Widget;
76 }
77
78 if ( $.isArray( prototype ) ) {
79 prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
80 }
81
82 // Create selector for plugin
83 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
84 return !!$.data( elem, fullName );
85 };
86
87 $[ namespace ] = $[ namespace ] || {};
88 existingConstructor = $[ namespace ][ name ];
89 constructor = $[ namespace ][ name ] = function( options, element ) {
90
91 // Allow instantiation without "new" keyword
92 if ( !this._createWidget ) {
93 return new constructor( options, element );
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 ) {
99 this._createWidget( options, element );
100 }
101 };
102
103 // Extend with the existing constructor to carry over any static properties
104 $.extend( constructor, existingConstructor, {
105 version: prototype.version,
106
107 // Copy the object used to create the prototype in case we need to
108 // redefine the widget later
109 _proto: $.extend( {}, prototype ),
110
111 // Track widgets that inherit from this widget in case this widget is
112 // redefined after a widget inherits from it
113 _childConstructors: []
114 } );
115
116 basePrototype = new base();
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 ) {
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 ) );
282 }
283 } );
284 }
285
286 return returnValue;
287 };
288 };
289
290 $.Widget = function( /* options, element */ ) {};
291 $.Widget._childConstructors = [];
292
293 $.Widget.prototype = {
294 widgetName: "widget",
295 widgetEventPrefix: "",
296 defaultElement: "<div>",
297
298 options: {
299 classes: {},
300 disabled: false,
301
302 // Callbacks
303 create: null
304 },
305
306 _createWidget: function( options, element ) {
307 element = $( element || this.defaultElement || this )[ 0 ];
308 this.element = $( element );
309 this.uuid = widgetUuid++;
310 this.eventNamespace = "." + this.widgetName + this.uuid;
311
312 this.bindings = $();
313 this.hoverable = $();
314 this.focusable = $();
315 this.classesElementLookup = {};
316
317 if ( element !== this ) {
318 $.data( element, this.widgetFullName, this );
319 this._on( true, this.element, {
320 remove: function( event ) {
321 if ( event.target === element ) {
322 this.destroy();
323 }
324 }
325 } );
326 this.document = $( element.style ?
327
328 // Element within the document
329 element.ownerDocument :
330
331 // Element is window or document
332 element.document || element );
333 this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
334 }
335
336 this.options = $.widget.extend( {},
337 this.options,
338 this._getCreateOptions(),
339 options );
340
341 this._create();
342
343 if ( this.options.disabled ) {
344 this._setOptionDisabled( this.options.disabled );
345 }
346
347 this._trigger( "create", null, this._getCreateEventData() );
348 this._init();
349 },
350
351 _getCreateOptions: function() {
352 return {};
353 },
354
355 _getCreateEventData: $.noop,
356
357 _create: $.noop,
358
359 _init: $.noop,
360
361 destroy: function() {
362 var that = this;
363
364 this._destroy();
365 $.each( this.classesElementLookup, function( key, value ) {
366 that._removeClass( value, key );
367 } );
368
369 // We can probably remove the unbind calls in 2.0
370 // all event bindings should go through this._on()
371 this.element
372 .off( this.eventNamespace )
373 .removeData( this.widgetFullName );
374 this.widget()
375 .off( this.eventNamespace )
376 .removeAttr( "aria-disabled" );
377
378 // Clean up events and states
379 this.bindings.off( this.eventNamespace );
380 },
381
382 _destroy: $.noop,
383
384 widget: function() {
385 return this.element;
386 },
387
388 option: function( key, value ) {
389 var options = key;
390 var parts;
391 var curOption;
392 var i;
393
394 if ( arguments.length === 0 ) {
395
396 // Don't return a reference to the internal hash
397 return $.widget.extend( {}, this.options );
398 }
399
400 if ( typeof key === "string" ) {
401
402 // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
403 options = {};
404 parts = key.split( "." );
405 key = parts.shift();
406 if ( parts.length ) {
407 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
408 for ( i = 0; i < parts.length - 1; i++ ) {
409 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
410 curOption = curOption[ parts[ i ] ];
411 }
412 key = parts.pop();
413 if ( arguments.length === 1 ) {
414 return curOption[ key ] === undefined ? null : curOption[ key ];
415 }
416 curOption[ key ] = value;
417 } else {
418 if ( arguments.length === 1 ) {
419 return this.options[ key ] === undefined ? null : this.options[ key ];
420 }
421 options[ key ] = value;
422 }
423 }
424
425 this._setOptions( options );
426
427 return this;
428 },
429
430 _setOptions: function( options ) {
431 var key;
432
433 for ( key in options ) {
434 this._setOption( key, options[ key ] );
435 }
436
437 return this;
438 },
439
440 _setOption: function( key, value ) {
441 if ( key === "classes" ) {
442 this._setOptionClasses( value );
443 }
444
445 this.options[ key ] = value;
446
447 if ( key === "disabled" ) {
448 this._setOptionDisabled( value );
449 }
450
451 return this;
452 },
453
454 _setOptionClasses: function( value ) {
455 var classKey, elements, currentElements;
456
457 for ( classKey in value ) {
458 currentElements = this.classesElementLookup[ classKey ];
459 if ( value[ classKey ] === this.options.classes[ classKey ] ||
460 !currentElements ||
461 !currentElements.length ) {
462 continue;
463 }
464
465 // We are doing this to create a new jQuery object because the _removeClass() call
466 // on the next line is going to destroy the reference to the current elements being
467 // tracked. We need to save a copy of this collection so that we can add the new classes
468 // below.
469 elements = $( currentElements.get() );
470 this._removeClass( currentElements, classKey );
471
472 // We don't use _addClass() here, because that uses this.options.classes
473 // for generating the string of classes. We want to use the value passed in from
474 // _setOption(), this is the new value of the classes option which was passed to
475 // _setOption(). We pass this value directly to _classes().
476 elements.addClass( this._classes( {
477 element: elements,
478 keys: classKey,
479 classes: value,
480 add: true
481 } ) );
482 }
483 },
484
485 _setOptionDisabled: function( value ) {
486 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
487
488 // If the widget is becoming disabled, then nothing is interactive
489 if ( value ) {
490 this._removeClass( this.hoverable, null, "ui-state-hover" );
491 this._removeClass( this.focusable, null, "ui-state-focus" );
492 }
493 },
494
495 enable: function() {
496 return this._setOptions( { disabled: false } );
497 },
498
499 disable: function() {
500 return this._setOptions( { disabled: true } );
501 },
502
503 _classes: function( options ) {
504 var full = [];
505 var that = this;
506
507 options = $.extend( {
508 element: this.element,
509 classes: this.options.classes || {}
510 }, options );
511
512 function processClassString( classes, checkOption ) {
513 var current, i;
514 for ( i = 0; i < classes.length; i++ ) {
515 current = that.classesElementLookup[ classes[ i ] ] || $();
516 if ( options.add ) {
517 current = $( $.unique( current.get().concat( options.element.get() ) ) );
518 } else {
519 current = $( current.not( options.element ).get() );
520 }
521 that.classesElementLookup[ classes[ i ] ] = current;
522 full.push( classes[ i ] );
523 if ( checkOption && options.classes[ classes[ i ] ] ) {
524 full.push( options.classes[ classes[ i ] ] );
525 }
526 }
527 }
528
529 this._on( options.element, {
530 "remove": "_untrackClassesElement"
531 } );
532
533 if ( options.keys ) {
534 processClassString( options.keys.match( /\S+/g ) || [], true );
535 }
536 if ( options.extra ) {
537 processClassString( options.extra.match( /\S+/g ) || [] );
538 }
539
540 return full.join( " " );
541 },
542
543 _untrackClassesElement: function( event ) {
544 var that = this;
545 $.each( that.classesElementLookup, function( key, value ) {
546 if ( $.inArray( event.target, value ) !== -1 ) {
547 that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
548 }
549 } );
550 },
551
552 _removeClass: function( element, keys, extra ) {
553 return this._toggleClass( element, keys, extra, false );
554 },
555
556 _addClass: function( element, keys, extra ) {
557 return this._toggleClass( element, keys, extra, true );
558 },
559
560 _toggleClass: function( element, keys, extra, add ) {
561 add = ( typeof add === "boolean" ) ? add : extra;
562 var shift = ( typeof element === "string" || element === null ),
563 options = {
564 extra: shift ? keys : extra,
565 keys: shift ? element : keys,
566 element: shift ? this.element : element,
567 add: add
568 };
569 options.element.toggleClass( this._classes( options ), add );
570 return this;
571 },
572
573 _on: function( suppressDisabledCheck, element, handlers ) {
574 var delegateElement;
575 var instance = this;
576
577 // No suppressDisabledCheck flag, shuffle arguments
578 if ( typeof suppressDisabledCheck !== "boolean" ) {
579 handlers = element;
580 element = suppressDisabledCheck;
581 suppressDisabledCheck = false;
582 }
583
584 // No element argument, shuffle and use this.element
585 if ( !handlers ) {
586 handlers = element;
587 element = this.element;
588 delegateElement = this.widget();
589 } else {
590 element = delegateElement = $( element );
591 this.bindings = this.bindings.add( element );
592 }
593
594 $.each( handlers, function( event, handler ) {
595 function handlerProxy() {
596
597 // Allow widgets to customize the disabled handling
598 // - disabled as an array instead of boolean
599 // - disabled class as method for disabling individual parts
600 if ( !suppressDisabledCheck &&
601 ( instance.options.disabled === true ||
602 $( this ).hasClass( "ui-state-disabled" ) ) ) {
603 return;
604 }
605 return ( typeof handler === "string" ? instance[ handler ] : handler )
606 .apply( instance, arguments );
607 }
608
609 // Copy the guid so direct unbinding works
610 if ( typeof handler !== "string" ) {
611 handlerProxy.guid = handler.guid =
612 handler.guid || handlerProxy.guid || $.guid++;
613 }
614
615 var match = event.match( /^([\w:-]*)\s*(.*)$/ );
616 var eventName = match[ 1 ] + instance.eventNamespace;
617 var selector = match[ 2 ];
618
619 if ( selector ) {
620 delegateElement.on( eventName, selector, handlerProxy );
621 } else {
622 element.on( eventName, handlerProxy );
623 }
624 } );
625 },
626
627 _off: function( element, eventName ) {
628 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
629 this.eventNamespace;
630 element.off( eventName ).off( eventName );
631
632 // Clear the stack to avoid memory leaks (#10056)
633 this.bindings = $( this.bindings.not( element ).get() );
634 this.focusable = $( this.focusable.not( element ).get() );
635 this.hoverable = $( this.hoverable.not( element ).get() );
636 },
637
638 _delay: function( handler, delay ) {
639 function handlerProxy() {
640 return ( typeof handler === "string" ? instance[ handler ] : handler )
641 .apply( instance, arguments );
642 }
643 var instance = this;
644 return setTimeout( handlerProxy, delay || 0 );
645 },
646
647 _hoverable: function( element ) {
648 this.hoverable = this.hoverable.add( element );
649 this._on( element, {
650 mouseenter: function( event ) {
651 this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
652 },
653 mouseleave: function( event ) {
654 this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
655 }
656 } );
657 },
658
659 _focusable: function( element ) {
660 this.focusable = this.focusable.add( element );
661 this._on( element, {
662 focusin: function( event ) {
663 this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
664 },
665 focusout: function( event ) {
666 this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
667 }
668 } );
669 },
670
671 _trigger: function( type, event, data ) {
672 var prop, orig;
673 var callback = this.options[ type ];
674
675 data = data || {};
676 event = $.Event( event );
677 event.type = ( type === this.widgetEventPrefix ?
678 type :
679 this.widgetEventPrefix + type ).toLowerCase();
680
681 // The original event may come from any element
682 // so we need to reset the target on the new event
683 event.target = this.element[ 0 ];
684
685 // Copy original event properties over to the new event
686 orig = event.originalEvent;
687 if ( orig ) {
688 for ( prop in orig ) {
689 if ( !( prop in event ) ) {
690 event[ prop ] = orig[ prop ];
691 }
692 }
693 }
694
695 this.element.trigger( event, data );
696 return !( $.isFunction( callback ) &&
697 callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
698 event.isDefaultPrevented() );
699 }
700 };
701
702 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
703 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
704 if ( typeof options === "string" ) {
705 options = { effect: options };
706 }
707
708 var hasOptions;
709 var effectName = !options ?
710 method :
711 options === true || typeof options === "number" ?
712 defaultEffect :
713 options.effect || defaultEffect;
714
715 options = options || {};
716 if ( typeof options === "number" ) {
717 options = { duration: options };
718 }
719
720 hasOptions = !$.isEmptyObject( options );
721 options.complete = callback;
722
723 if ( options.delay ) {
724 element.delay( options.delay );
725 }
726
727 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
728 element[ method ]( options );
729 } else if ( effectName !== method && element[ effectName ] ) {
730 element[ effectName ]( options.duration, options.easing, callback );
731 } else {
732 element.queue( function( next ) {
733 $( this )[ method ]();
734 if ( callback ) {
735 callback.call( element[ 0 ] );
736 }
737 next();
738 } );
739 }
740 };
741 } );
742
743 var widget = $.widget;
744
745
746 /*!
747 * 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 } ) );
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 Focusable 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: :focusable Selector
1309 //>>group: Core
1310 //>>description: Selects elements which can be focused.
1311 //>>docs: http://api.jqueryui.com/focusable-selector/
1312
1313
1314
1315 // Selectors
1316 $.ui.focusable = function( element, hasTabindex ) {
1317 var map, mapName, img, focusableIfVisible, fieldset,
1318 nodeName = element.nodeName.toLowerCase();
1319
1320 if ( "area" === nodeName ) {
1321 map = element.parentNode;
1322 mapName = map.name;
1323 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
1324 return false;
1325 }
1326 img = $( "img[usemap='#" + mapName + "']" );
1327 return img.length > 0 && img.is( ":visible" );
1328 }
1329
1330 if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
1331 focusableIfVisible = !element.disabled;
1332
1333 if ( focusableIfVisible ) {
1334
1335 // Form controls within a disabled fieldset are disabled.
1336 // However, controls within the fieldset's legend do not get disabled.
1337 // Since controls generally aren't placed inside legends, we skip
1338 // this portion of the check.
1339 fieldset = $( element ).closest( "fieldset" )[ 0 ];
1340 if ( fieldset ) {
1341 focusableIfVisible = !fieldset.disabled;
1342 }
1343 }
1344 } else if ( "a" === nodeName ) {
1345 focusableIfVisible = element.href || hasTabindex;
1346 } else {
1347 focusableIfVisible = hasTabindex;
1348 }
1349
1350 return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
1351 };
1352
1353 // Support: IE 8 only
1354 // IE 8 doesn't resolve inherit to visible/hidden for computed values
1355 function visible( element ) {
1356 var visibility = element.css( "visibility" );
1357 while ( visibility === "inherit" ) {
1358 element = element.parent();
1359 visibility = element.css( "visibility" );
1360 }
1361 return visibility !== "hidden";
1362 }
1363
1364 $.extend( $.expr[ ":" ], {
1365 focusable: function( element ) {
1366 return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
1367 }
1368 } );
1369
1370 var focusable = $.ui.focusable;
1371
1372
1373
1374
1375 // Support: IE8 Only
1376 // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
1377 // with a string, so we need to find the proper form.
1378 var form = $.fn.form = function() {
1379 return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
1380 };
1381
1382
1383 /*!
1384 * jQuery UI Form Reset Mixin 1.12.1
1385 * http://jqueryui.com
1386 *
1387 * Copyright jQuery Foundation and other contributors
1388 * Released under the MIT license.
1389 * http://jquery.org/license
1390 */
1391
1392 //>>label: Form Reset Mixin
1393 //>>group: Core
1394 //>>description: Refresh input widgets when their form is reset
1395 //>>docs: http://api.jqueryui.com/form-reset-mixin/
1396
1397
1398
1399 var formResetMixin = $.ui.formResetMixin = {
1400 _formResetHandler: function() {
1401 var form = $( this );
1402
1403 // Wait for the form reset to actually happen before refreshing
1404 setTimeout( function() {
1405 var instances = form.data( "ui-form-reset-instances" );
1406 $.each( instances, function() {
1407 this.refresh();
1408 } );
1409 } );
1410 },
1411
1412 _bindFormResetHandler: function() {
1413 this.form = this.element.form();
1414 if ( !this.form.length ) {
1415 return;
1416 }
1417
1418 var instances = this.form.data( "ui-form-reset-instances" ) || [];
1419 if ( !instances.length ) {
1420
1421 // We don't use _on() here because we use a single event handler per form
1422 this.form.on( "reset.ui-form-reset", this._formResetHandler );
1423 }
1424 instances.push( this );
1425 this.form.data( "ui-form-reset-instances", instances );
1426 },
1427
1428 _unbindFormResetHandler: function() {
1429 if ( !this.form.length ) {
1430 return;
1431 }
1432
1433 var instances = this.form.data( "ui-form-reset-instances" );
1434 instances.splice( $.inArray( this, instances ), 1 );
1435 if ( instances.length ) {
1436 this.form.data( "ui-form-reset-instances", instances );
1437 } else {
1438 this.form
1439 .removeData( "ui-form-reset-instances" )
1440 .off( "reset.ui-form-reset" );
1441 }
1442 }
1443 };
1444
1445
1446 /*!
1447 * jQuery UI Support for jQuery core 1.7.x 1.12.1
1448 * http://jqueryui.com
1449 *
1450 * Copyright jQuery Foundation and other contributors
1451 * Released under the MIT license.
1452 * http://jquery.org/license
1453 *
1454 */
1455
1456 //>>label: jQuery 1.7 Support
1457 //>>group: Core
1458 //>>description: Support version 1.7.x of jQuery core
1459
1460
1461
1462 // Support: jQuery 1.7 only
1463 // Not a great way to check versions, but since we only support 1.7+ and only
1464 // need to detect <1.8, this is a simple check that should suffice. Checking
1465 // for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0
1466 // and we'll never reach 1.70.0 (if we do, we certainly won't be supporting
1467 // 1.7 anymore). See #11197 for why we're not using feature detection.
1468 if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) {
1469
1470 // Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()
1471 // Unlike jQuery Core 1.8+, these only support numeric values to set the
1472 // dimensions in pixels
1473 $.each( [ "Width", "Height" ], function( i, name ) {
1474 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
1475 type = name.toLowerCase(),
1476 orig = {
1477 innerWidth: $.fn.innerWidth,
1478 innerHeight: $.fn.innerHeight,
1479 outerWidth: $.fn.outerWidth,
1480 outerHeight: $.fn.outerHeight
1481 };
1482
1483 function reduce( elem, size, border, margin ) {
1484 $.each( side, function() {
1485 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
1486 if ( border ) {
1487 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
1488 }
1489 if ( margin ) {
1490 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
1491 }
1492 } );
1493 return size;
1494 }
1495
1496 $.fn[ "inner" + name ] = function( size ) {
1497 if ( size === undefined ) {
1498 return orig[ "inner" + name ].call( this );
1499 }
1500
1501 return this.each( function() {
1502 $( this ).css( type, reduce( this, size ) + "px" );
1503 } );
1504 };
1505
1506 $.fn[ "outer" + name ] = function( size, margin ) {
1507 if ( typeof size !== "number" ) {
1508 return orig[ "outer" + name ].call( this, size );
1509 }
1510
1511 return this.each( function() {
1512 $( this ).css( type, reduce( this, size, true, margin ) + "px" );
1513 } );
1514 };
1515 } );
1516
1517 $.fn.addBack = function( selector ) {
1518 return this.add( selector == null ?
1519 this.prevObject : this.prevObject.filter( selector )
1520 );
1521 };
1522 }
1523
1524 ;
1525 /*!
1526 * jQuery UI Keycode 1.12.1
1527 * http://jqueryui.com
1528 *
1529 * Copyright jQuery Foundation and other contributors
1530 * Released under the MIT license.
1531 * http://jquery.org/license
1532 */
1533
1534 //>>label: Keycode
1535 //>>group: Core
1536 //>>description: Provide keycodes as keynames
1537 //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
1538
1539
1540 var keycode = $.ui.keyCode = {
1541 BACKSPACE: 8,
1542 COMMA: 188,
1543 DELETE: 46,
1544 DOWN: 40,
1545 END: 35,
1546 ENTER: 13,
1547 ESCAPE: 27,
1548 HOME: 36,
1549 LEFT: 37,
1550 PAGE_DOWN: 34,
1551 PAGE_UP: 33,
1552 PERIOD: 190,
1553 RIGHT: 39,
1554 SPACE: 32,
1555 TAB: 9,
1556 UP: 38
1557 };
1558
1559
1560
1561
1562 // Internal use only
1563 var escapeSelector = $.ui.escapeSelector = ( function() {
1564 var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
1565 return function( selector ) {
1566 return selector.replace( selectorEscape, "\\$1" );
1567 };
1568 } )();
1569
1570
1571 /*!
1572 * jQuery UI Labels 1.12.1
1573 * http://jqueryui.com
1574 *
1575 * Copyright jQuery Foundation and other contributors
1576 * Released under the MIT license.
1577 * http://jquery.org/license
1578 */
1579
1580 //>>label: labels
1581 //>>group: Core
1582 //>>description: Find all the labels associated with a given input
1583 //>>docs: http://api.jqueryui.com/labels/
1584
1585
1586
1587 var labels = $.fn.labels = function() {
1588 var ancestor, selector, id, labels, ancestors;
1589
1590 // Check control.labels first
1591 if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
1592 return this.pushStack( this[ 0 ].labels );
1593 }
1594
1595 // Support: IE <= 11, FF <= 37, Android <= 2.3 only
1596 // Above browsers do not support control.labels. Everything below is to support them
1597 // as well as document fragments. control.labels does not work on document fragments
1598 labels = this.eq( 0 ).parents( "label" );
1599
1600 // Look for the label based on the id
1601 id = this.attr( "id" );
1602 if ( id ) {
1603
1604 // We don't search against the document in case the element
1605 // is disconnected from the DOM
1606 ancestor = this.eq( 0 ).parents().last();
1607
1608 // Get a full set of top level ancestors
1609 ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
1610
1611 // Create a selector for the label based on the id
1612 selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
1613
1614 labels = labels.add( ancestors.find( selector ).addBack( selector ) );
1615
1616 }
1617
1618 // Return whatever we have found for labels
1619 return this.pushStack( labels );
1620 };
1621
1622
1623 /*!
1624 * jQuery UI Scroll Parent 1.12.1
1625 * http://jqueryui.com
1626 *
1627 * Copyright jQuery Foundation and other contributors
1628 * Released under the MIT license.
1629 * http://jquery.org/license
1630 */
1631
1632 //>>label: scrollParent
1633 //>>group: Core
1634 //>>description: Get the closest ancestor element that is scrollable.
1635 //>>docs: http://api.jqueryui.com/scrollParent/
1636
1637
1638
1639 var scrollParent = $.fn.scrollParent = function( includeHidden ) {
1640 var position = this.css( "position" ),
1641 excludeStaticParent = position === "absolute",
1642 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
1643 scrollParent = this.parents().filter( function() {
1644 var parent = $( this );
1645 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
1646 return false;
1647 }
1648 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
1649 parent.css( "overflow-x" ) );
1650 } ).eq( 0 );
1651
1652 return position === "fixed" || !scrollParent.length ?
1653 $( this[ 0 ].ownerDocument || document ) :
1654 scrollParent;
1655 };
1656
1657
1658 /*!
1659 * jQuery UI Tabbable 1.12.1
1660 * http://jqueryui.com
1661 *
1662 * Copyright jQuery Foundation and other contributors
1663 * Released under the MIT license.
1664 * http://jquery.org/license
1665 */
1666
1667 //>>label: :tabbable Selector
1668 //>>group: Core
1669 //>>description: Selects elements which can be tabbed to.
1670 //>>docs: http://api.jqueryui.com/tabbable-selector/
1671
1672
1673
1674 var tabbable = $.extend( $.expr[ ":" ], {
1675 tabbable: function( element ) {
1676 var tabIndex = $.attr( element, "tabindex" ),
1677 hasTabindex = tabIndex != null;
1678 return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
1679 }
1680 } );
1681
1682
1683 /*!
1684 * jQuery UI Unique ID 1.12.1
1685 * http://jqueryui.com
1686 *
1687 * Copyright jQuery Foundation and other contributors
1688 * Released under the MIT license.
1689 * http://jquery.org/license
1690 */
1691
1692 //>>label: uniqueId
1693 //>>group: Core
1694 //>>description: Functions to generate and remove uniqueId's
1695 //>>docs: http://api.jqueryui.com/uniqueId/
1696
1697
1698
1699 var uniqueId = $.fn.extend( {
1700 uniqueId: ( function() {
1701 var uuid = 0;
1702
1703 return function() {
1704 return this.each( function() {
1705 if ( !this.id ) {
1706 this.id = "ui-id-" + ( ++uuid );
1707 }
1708 } );
1709 };
1710 } )(),
1711
1712 removeUniqueId: function() {
1713 return this.each( function() {
1714 if ( /^ui-id-\d+$/.test( this.id ) ) {
1715 $( this ).removeAttr( "id" );
1716 }
1717 } );
1718 }
1719 } );
1720
1721
1722
1723
1724 // This file is deprecated
1725 var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
1726
1727 /*!
1728 * jQuery UI Mouse 1.12.1
1729 * http://jqueryui.com
1730 *
1731 * Copyright jQuery Foundation and other contributors
1732 * Released under the MIT license.
1733 * http://jquery.org/license
1734 */
1735
1736 //>>label: Mouse
1737 //>>group: Widgets
1738 //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
1739 //>>docs: http://api.jqueryui.com/mouse/
1740
1741
1742
1743 var mouseHandled = false;
1744 $( document ).on( "mouseup", function() {
1745 mouseHandled = false;
1746 } );
1747
1748 var widgetsMouse = $.widget( "ui.mouse", {
1749 version: "1.12.1",
1750 options: {
1751 cancel: "input, textarea, button, select, option",
1752 distance: 1,
1753 delay: 0
1754 },
1755 _mouseInit: function() {
1756 var that = this;
1757
1758 this.element
1759 .on( "mousedown." + this.widgetName, function( event ) {
1760 return that._mouseDown( event );
1761 } )
1762 .on( "click." + this.widgetName, function( event ) {
1763 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
1764 $.removeData( event.target, that.widgetName + ".preventClickEvent" );
1765 event.stopImmediatePropagation();
1766 return false;
1767 }
1768 } );
1769
1770 this.started = false;
1771 },
1772
1773 // TODO: make sure destroying one instance of mouse doesn't mess with
1774 // other instances of mouse
1775 _mouseDestroy: function() {
1776 this.element.off( "." + this.widgetName );
1777 if ( this._mouseMoveDelegate ) {
1778 this.document
1779 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1780 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
1781 }
1782 },
1783
1784 _mouseDown: function( event ) {
1785
1786 // don't let more than one widget handle mouseStart
1787 if ( mouseHandled ) {
1788 return;
1789 }
1790
1791 this._mouseMoved = false;
1792
1793 // We may have missed mouseup (out of window)
1794 ( this._mouseStarted && this._mouseUp( event ) );
1795
1796 this._mouseDownEvent = event;
1797
1798 var that = this,
1799 btnIsLeft = ( event.which === 1 ),
1800
1801 // event.target.nodeName works around a bug in IE 8 with
1802 // disabled inputs (#7620)
1803 elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
1804 $( event.target ).closest( this.options.cancel ).length : false );
1805 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
1806 return true;
1807 }
1808
1809 this.mouseDelayMet = !this.options.delay;
1810 if ( !this.mouseDelayMet ) {
1811 this._mouseDelayTimer = setTimeout( function() {
1812 that.mouseDelayMet = true;
1813 }, this.options.delay );
1814 }
1815
1816 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
1817 this._mouseStarted = ( this._mouseStart( event ) !== false );
1818 if ( !this._mouseStarted ) {
1819 event.preventDefault();
1820 return true;
1821 }
1822 }
1823
1824 // Click event may never have fired (Gecko & Opera)
1825 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
1826 $.removeData( event.target, this.widgetName + ".preventClickEvent" );
1827 }
1828
1829 // These delegates are required to keep context
1830 this._mouseMoveDelegate = function( event ) {
1831 return that._mouseMove( event );
1832 };
1833 this._mouseUpDelegate = function( event ) {
1834 return that._mouseUp( event );
1835 };
1836
1837 this.document
1838 .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1839 .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
1840
1841 event.preventDefault();
1842
1843 mouseHandled = true;
1844 return true;
1845 },
1846
1847 _mouseMove: function( event ) {
1848
1849 // Only check for mouseups outside the document if you've moved inside the document
1850 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
1851 // fire a mousemove event if content is placed under the cursor. See #7778
1852 // Support: IE <9
1853 if ( this._mouseMoved ) {
1854
1855 // IE mouseup check - mouseup happened when mouse was out of window
1856 if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
1857 !event.button ) {
1858 return this._mouseUp( event );
1859
1860 // Iframe mouseup check - mouseup occurred in another document
1861 } else if ( !event.which ) {
1862
1863 // Support: Safari <=8 - 9
1864 // Safari sets which to 0 if you press any of the following keys
1865 // during a drag (#14461)
1866 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
1867 event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
1868 this.ignoreMissingWhich = true;
1869 } else if ( !this.ignoreMissingWhich ) {
1870 return this._mouseUp( event );
1871 }
1872 }
1873 }
1874
1875 if ( event.which || event.button ) {
1876 this._mouseMoved = true;
1877 }
1878
1879 if ( this._mouseStarted ) {
1880 this._mouseDrag( event );
1881 return event.preventDefault();
1882 }
1883
1884 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
1885 this._mouseStarted =
1886 ( this._mouseStart( this._mouseDownEvent, event ) !== false );
1887 ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
1888 }
1889
1890 return !this._mouseStarted;
1891 },
1892
1893 _mouseUp: function( event ) {
1894 this.document
1895 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1896 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
1897
1898 if ( this._mouseStarted ) {
1899 this._mouseStarted = false;
1900
1901 if ( event.target === this._mouseDownEvent.target ) {
1902 $.data( event.target, this.widgetName + ".preventClickEvent", true );
1903 }
1904
1905 this._mouseStop( event );
1906 }
1907
1908 if ( this._mouseDelayTimer ) {
1909 clearTimeout( this._mouseDelayTimer );
1910 delete this._mouseDelayTimer;
1911 }
1912
1913 this.ignoreMissingWhich = false;
1914 mouseHandled = false;
1915 event.preventDefault();
1916 },
1917
1918 _mouseDistanceMet: function( event ) {
1919 return ( Math.max(
1920 Math.abs( this._mouseDownEvent.pageX - event.pageX ),
1921 Math.abs( this._mouseDownEvent.pageY - event.pageY )
1922 ) >= this.options.distance
1923 );
1924 },
1925
1926 _mouseDelayMet: function( /* event */ ) {
1927 return this.mouseDelayMet;
1928 },
1929
1930 // These are placeholder methods, to be overriden by extending plugin
1931 _mouseStart: function( /* event */ ) {},
1932 _mouseDrag: function( /* event */ ) {},
1933 _mouseStop: function( /* event */ ) {},
1934 _mouseCapture: function( /* event */ ) { return true; }
1935 } );
1936
1937
1938
1939
1940 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
1941 var plugin = $.ui.plugin = {
1942 add: function( module, option, set ) {
1943 var i,
1944 proto = $.ui[ module ].prototype;
1945 for ( i in set ) {
1946 proto.plugins[ i ] = proto.plugins[ i ] || [];
1947 proto.plugins[ i ].push( [ option, set[ i ] ] );
1948 }
1949 },
1950 call: function( instance, name, args, allowDisconnected ) {
1951 var i,
1952 set = instance.plugins[ name ];
1953
1954 if ( !set ) {
1955 return;
1956 }
1957
1958 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
1959 instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
1960 return;
1961 }
1962
1963 for ( i = 0; i < set.length; i++ ) {
1964 if ( instance.options[ set[ i ][ 0 ] ] ) {
1965 set[ i ][ 1 ].apply( instance.element, args );
1966 }
1967 }
1968 }
1969 };
1970
1971
1972
1973 var safeActiveElement = $.ui.safeActiveElement = function( document ) {
1974 var activeElement;
1975
1976 // Support: IE 9 only
1977 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
1978 try {
1979 activeElement = document.activeElement;
1980 } catch ( error ) {
1981 activeElement = document.body;
1982 }
1983
1984 // Support: IE 9 - 11 only
1985 // IE may return null instead of an element
1986 // Interestingly, this only seems to occur when NOT in an iframe
1987 if ( !activeElement ) {
1988 activeElement = document.body;
1989 }
1990
1991 // Support: IE 11 only
1992 // IE11 returns a seemingly empty object in some cases when accessing
1993 // document.activeElement from an <iframe>
1994 if ( !activeElement.nodeName ) {
1995 activeElement = document.body;
1996 }
1997
1998 return activeElement;
1999 };
2000
2001
2002
2003 var safeBlur = $.ui.safeBlur = function( element ) {
2004
2005 // Support: IE9 - 10 only
2006 // If the <body> is blurred, IE will switch windows, see #9420
2007 if ( element && element.nodeName.toLowerCase() !== "body" ) {
2008 $( element ).trigger( "blur" );
2009 }
2010 };
2011
2012
2013 /*!
2014 * jQuery UI Draggable 1.12.1
2015 * http://jqueryui.com
2016 *
2017 * Copyright jQuery Foundation and other contributors
2018 * Released under the MIT license.
2019 * http://jquery.org/license
2020 */
2021
2022 //>>label: Draggable
2023 //>>group: Interactions
2024 //>>description: Enables dragging functionality for any element.
2025 //>>docs: http://api.jqueryui.com/draggable/
2026 //>>demos: http://jqueryui.com/draggable/
2027 //>>css.structure: ../../themes/base/draggable.css
2028
2029
2030
2031 $.widget( "ui.draggable", $.ui.mouse, {
2032 version: "1.12.1",
2033 widgetEventPrefix: "drag",
2034 options: {
2035 addClasses: true,
2036 appendTo: "parent",
2037 axis: false,
2038 connectToSortable: false,
2039 containment: false,
2040 cursor: "auto",
2041 cursorAt: false,
2042 grid: false,
2043 handle: false,
2044 helper: "original",
2045 iframeFix: false,
2046 opacity: false,
2047 refreshPositions: false,
2048 revert: false,
2049 revertDuration: 500,
2050 scope: "default",
2051 scroll: true,
2052 scrollSensitivity: 20,
2053 scrollSpeed: 20,
2054 snap: false,
2055 snapMode: "both",
2056 snapTolerance: 20,
2057 stack: false,
2058 zIndex: false,
2059
2060 // Callbacks
2061 drag: null,
2062 start: null,
2063 stop: null
2064 },
2065 _create: function() {
2066
2067 if ( this.options.helper === "original" ) {
2068 this._setPositionRelative();
2069 }
2070 if ( this.options.addClasses ) {
2071 this._addClass( "ui-draggable" );
2072 }
2073 this._setHandleClassName();
2074
2075 this._mouseInit();
2076 },
2077
2078 _setOption: function( key, value ) {
2079 this._super( key, value );
2080 if ( key === "handle" ) {
2081 this._removeHandleClassName();
2082 this._setHandleClassName();
2083 }
2084 },
2085
2086 _destroy: function() {
2087 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
2088 this.destroyOnClear = true;
2089 return;
2090 }
2091 this._removeHandleClassName();
2092 this._mouseDestroy();
2093 },
2094
2095 _mouseCapture: function( event ) {
2096 var o = this.options;
2097
2098 // Among others, prevent a drag on a resizable-handle
2099 if ( this.helper || o.disabled ||
2100 $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
2101 return false;
2102 }
2103
2104 //Quit if we're not on a valid handle
2105 this.handle = this._getHandle( event );
2106 if ( !this.handle ) {
2107 return false;
2108 }
2109
2110 this._blurActiveElement( event );
2111
2112 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
2113
2114 return true;
2115
2116 },
2117
2118 _blockFrames: function( selector ) {
2119 this.iframeBlocks = this.document.find( selector ).map( function() {
2120 var iframe = $( this );
2121
2122 return $( "<div>" )
2123 .css( "position", "absolute" )
2124 .appendTo( iframe.parent() )
2125 .outerWidth( iframe.outerWidth() )
2126 .outerHeight( iframe.outerHeight() )
2127 .offset( iframe.offset() )[ 0 ];
2128 } );
2129 },
2130
2131 _unblockFrames: function() {
2132 if ( this.iframeBlocks ) {
2133 this.iframeBlocks.remove();
2134 delete this.iframeBlocks;
2135 }
2136 },
2137
2138 _blurActiveElement: function( event ) {
2139 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
2140 target = $( event.target );
2141
2142 // Don't blur if the event occurred on an element that is within
2143 // the currently focused element
2144 // See #10527, #12472
2145 if ( target.closest( activeElement ).length ) {
2146 return;
2147 }
2148
2149 // Blur any element that currently has focus, see #4261
2150 $.ui.safeBlur( activeElement );
2151 },
2152
2153 _mouseStart: function( event ) {
2154
2155 var o = this.options;
2156
2157 //Create and append the visible helper
2158 this.helper = this._createHelper( event );
2159
2160 this._addClass( this.helper, "ui-draggable-dragging" );
2161
2162 //Cache the helper size
2163 this._cacheHelperProportions();
2164
2165 //If ddmanager is used for droppables, set the global draggable
2166 if ( $.ui.ddmanager ) {
2167 $.ui.ddmanager.current = this;
2168 }
2169
2170 /*
2171 * - Position generation -
2172 * This block generates everything position related - it's the core of draggables.
2173 */
2174
2175 //Cache the margins of the original element
2176 this._cacheMargins();
2177
2178 //Store the helper's css position
2179 this.cssPosition = this.helper.css( "position" );
2180 this.scrollParent = this.helper.scrollParent( true );
2181 this.offsetParent = this.helper.offsetParent();
2182 this.hasFixedAncestor = this.helper.parents().filter( function() {
2183 return $( this ).css( "position" ) === "fixed";
2184 } ).length > 0;
2185
2186 //The element's absolute position on the page minus margins
2187 this.positionAbs = this.element.offset();
2188 this._refreshOffsets( event );
2189
2190 //Generate the original position
2191 this.originalPosition = this.position = this._generatePosition( event, false );
2192 this.originalPageX = event.pageX;
2193 this.originalPageY = event.pageY;
2194
2195 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
2196 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
2197
2198 //Set a containment if given in the options
2199 this._setContainment();
2200
2201 //Trigger event + callbacks
2202 if ( this._trigger( "start", event ) === false ) {
2203 this._clear();
2204 return false;
2205 }
2206
2207 //Recache the helper size
2208 this._cacheHelperProportions();
2209
2210 //Prepare the droppable offsets
2211 if ( $.ui.ddmanager && !o.dropBehaviour ) {
2212 $.ui.ddmanager.prepareOffsets( this, event );
2213 }
2214
2215 // Execute the drag once - this causes the helper not to be visible before getting its
2216 // correct position
2217 this._mouseDrag( event, true );
2218
2219 // If the ddmanager is used for droppables, inform the manager that dragging has started
2220 // (see #5003)
2221 if ( $.ui.ddmanager ) {
2222 $.ui.ddmanager.dragStart( this, event );
2223 }
2224
2225 return true;
2226 },
2227
2228 _refreshOffsets: function( event ) {
2229 this.offset = {
2230 top: this.positionAbs.top - this.margins.top,
2231 left: this.positionAbs.left - this.margins.left,
2232 scroll: false,
2233 parent: this._getParentOffset(),
2234 relative: this._getRelativeOffset()
2235 };
2236
2237 this.offset.click = {
2238 left: event.pageX - this.offset.left,
2239 top: event.pageY - this.offset.top
2240 };
2241 },
2242
2243 _mouseDrag: function( event, noPropagation ) {
2244
2245 // reset any necessary cached properties (see #5009)
2246 if ( this.hasFixedAncestor ) {
2247 this.offset.parent = this._getParentOffset();
2248 }
2249
2250 //Compute the helpers position
2251 this.position = this._generatePosition( event, true );
2252 this.positionAbs = this._convertPositionTo( "absolute" );
2253
2254 //Call plugins and callbacks and use the resulting position if something is returned
2255 if ( !noPropagation ) {
2256 var ui = this._uiHash();
2257 if ( this._trigger( "drag", event, ui ) === false ) {
2258 this._mouseUp( new $.Event( "mouseup", event ) );
2259 return false;
2260 }
2261 this.position = ui.position;
2262 }
2263
2264 this.helper[ 0 ].style.left = this.position.left + "px";
2265 this.helper[ 0 ].style.top = this.position.top + "px";
2266
2267 if ( $.ui.ddmanager ) {
2268 $.ui.ddmanager.drag( this, event );
2269 }
2270
2271 return false;
2272 },
2273
2274 _mouseStop: function( event ) {
2275
2276 //If we are using droppables, inform the manager about the drop
2277 var that = this,
2278 dropped = false;
2279 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
2280 dropped = $.ui.ddmanager.drop( this, event );
2281 }
2282
2283 //if a drop comes from outside (a sortable)
2284 if ( this.dropped ) {
2285 dropped = this.dropped;
2286 this.dropped = false;
2287 }
2288
2289 if ( ( this.options.revert === "invalid" && !dropped ) ||
2290 ( this.options.revert === "valid" && dropped ) ||
2291 this.options.revert === true || ( $.isFunction( this.options.revert ) &&
2292 this.options.revert.call( this.element, dropped ) )
2293 ) {
2294 $( this.helper ).animate(
2295 this.originalPosition,
2296 parseInt( this.options.revertDuration, 10 ),
2297 function() {
2298 if ( that._trigger( "stop", event ) !== false ) {
2299 that._clear();
2300 }
2301 }
2302 );
2303 } else {
2304 if ( this._trigger( "stop", event ) !== false ) {
2305 this._clear();
2306 }
2307 }
2308
2309 return false;
2310 },
2311
2312 _mouseUp: function( event ) {
2313 this._unblockFrames();
2314
2315 // If the ddmanager is used for droppables, inform the manager that dragging has stopped
2316 // (see #5003)
2317 if ( $.ui.ddmanager ) {
2318 $.ui.ddmanager.dragStop( this, event );
2319 }
2320
2321 // Only need to focus if the event occurred on the draggable itself, see #10527
2322 if ( this.handleElement.is( event.target ) ) {
2323
2324 // The interaction is over; whether or not the click resulted in a drag,
2325 // focus the element
2326 this.element.trigger( "focus" );
2327 }
2328
2329 return $.ui.mouse.prototype._mouseUp.call( this, event );
2330 },
2331
2332 cancel: function() {
2333
2334 if ( this.helper.is( ".ui-draggable-dragging" ) ) {
2335 this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
2336 } else {
2337 this._clear();
2338 }
2339
2340 return this;
2341
2342 },
2343
2344 _getHandle: function( event ) {
2345 return this.options.handle ?
2346 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
2347 true;
2348 },
2349
2350 _setHandleClassName: function() {
2351 this.handleElement = this.options.handle ?
2352 this.element.find( this.options.handle ) : this.element;
2353 this._addClass( this.handleElement, "ui-draggable-handle" );
2354 },
2355
2356 _removeHandleClassName: function() {
2357 this._removeClass( this.handleElement, "ui-draggable-handle" );
2358 },
2359
2360 _createHelper: function( event ) {
2361
2362 var o = this.options,
2363 helperIsFunction = $.isFunction( o.helper ),
2364 helper = helperIsFunction ?
2365 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
2366 ( o.helper === "clone" ?
2367 this.element.clone().removeAttr( "id" ) :
2368 this.element );
2369
2370 if ( !helper.parents( "body" ).length ) {
2371 helper.appendTo( ( o.appendTo === "parent" ?
2372 this.element[ 0 ].parentNode :
2373 o.appendTo ) );
2374 }
2375
2376 // Http://bugs.jqueryui.com/ticket/9446
2377 // a helper function can return the original element
2378 // which wouldn't have been set to relative in _create
2379 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
2380 this._setPositionRelative();
2381 }
2382
2383 if ( helper[ 0 ] !== this.element[ 0 ] &&
2384 !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
2385 helper.css( "position", "absolute" );
2386 }
2387
2388 return helper;
2389
2390 },
2391
2392 _setPositionRelative: function() {
2393 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
2394 this.element[ 0 ].style.position = "relative";
2395 }
2396 },
2397
2398 _adjustOffsetFromHelper: function( obj ) {
2399 if ( typeof obj === "string" ) {
2400 obj = obj.split( " " );
2401 }
2402 if ( $.isArray( obj ) ) {
2403 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
2404 }
2405 if ( "left" in obj ) {
2406 this.offset.click.left = obj.left + this.margins.left;
2407 }
2408 if ( "right" in obj ) {
2409 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
2410 }
2411 if ( "top" in obj ) {
2412 this.offset.click.top = obj.top + this.margins.top;
2413 }
2414 if ( "bottom" in obj ) {
2415 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
2416 }
2417 },
2418
2419 _isRootNode: function( element ) {
2420 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
2421 },
2422
2423 _getParentOffset: function() {
2424
2425 //Get the offsetParent and cache its position
2426 var po = this.offsetParent.offset(),
2427 document = this.document[ 0 ];
2428
2429 // This is a special case where we need to modify a offset calculated on start, since the
2430 // following happened:
2431 // 1. The position of the helper is absolute, so it's position is calculated based on the
2432 // next positioned parent
2433 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
2434 // the document, which means that the scroll is included in the initial calculation of the
2435 // offset of the parent, and never recalculated upon drag
2436 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
2437 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
2438 po.left += this.scrollParent.scrollLeft();
2439 po.top += this.scrollParent.scrollTop();
2440 }
2441
2442 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
2443 po = { top: 0, left: 0 };
2444 }
2445
2446 return {
2447 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
2448 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
2449 };
2450
2451 },
2452
2453 _getRelativeOffset: function() {
2454 if ( this.cssPosition !== "relative" ) {
2455 return { top: 0, left: 0 };
2456 }
2457
2458 var p = this.element.position(),
2459 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
2460
2461 return {
2462 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
2463 ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
2464 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
2465 ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
2466 };
2467
2468 },
2469
2470 _cacheMargins: function() {
2471 this.margins = {
2472 left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
2473 top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
2474 right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
2475 bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
2476 };
2477 },
2478
2479 _cacheHelperProportions: function() {
2480 this.helperProportions = {
2481 width: this.helper.outerWidth(),
2482 height: this.helper.outerHeight()
2483 };
2484 },
2485
2486 _setContainment: function() {
2487
2488 var isUserScrollable, c, ce,
2489 o = this.options,
2490 document = this.document[ 0 ];
2491
2492 this.relativeContainer = null;
2493
2494 if ( !o.containment ) {
2495 this.containment = null;
2496 return;
2497 }
2498
2499 if ( o.containment === "window" ) {
2500 this.containment = [
2501 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
2502 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
2503 $( window ).scrollLeft() + $( window ).width() -
2504 this.helperProportions.width - this.margins.left,
2505 $( window ).scrollTop() +
2506 ( $( window ).height() || document.body.parentNode.scrollHeight ) -
2507 this.helperProportions.height - this.margins.top
2508 ];
2509 return;
2510 }
2511
2512 if ( o.containment === "document" ) {
2513 this.containment = [
2514 0,
2515 0,
2516 $( document ).width() - this.helperProportions.width - this.margins.left,
2517 ( $( document ).height() || document.body.parentNode.scrollHeight ) -
2518 this.helperProportions.height - this.margins.top
2519 ];
2520 return;
2521 }
2522
2523 if ( o.containment.constructor === Array ) {
2524 this.containment = o.containment;
2525 return;
2526 }
2527
2528 if ( o.containment === "parent" ) {
2529 o.containment = this.helper[ 0 ].parentNode;
2530 }
2531
2532 c = $( o.containment );
2533 ce = c[ 0 ];
2534
2535 if ( !ce ) {
2536 return;
2537 }
2538
2539 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
2540
2541 this.containment = [
2542 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
2543 ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
2544 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
2545 ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
2546 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
2547 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
2548 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
2549 this.helperProportions.width -
2550 this.margins.left -
2551 this.margins.right,
2552 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
2553 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
2554 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
2555 this.helperProportions.height -
2556 this.margins.top -
2557 this.margins.bottom
2558 ];
2559 this.relativeContainer = c;
2560 },
2561
2562 _convertPositionTo: function( d, pos ) {
2563
2564 if ( !pos ) {
2565 pos = this.position;
2566 }
2567
2568 var mod = d === "absolute" ? 1 : -1,
2569 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
2570
2571 return {
2572 top: (
2573
2574 // The absolute mouse position
2575 pos.top +
2576
2577 // Only for relative positioned nodes: Relative offset from element to offset parent
2578 this.offset.relative.top * mod +
2579
2580 // The offsetParent's offset without borders (offset + border)
2581 this.offset.parent.top * mod -
2582 ( ( this.cssPosition === "fixed" ?
2583 -this.offset.scroll.top :
2584 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
2585 ),
2586 left: (
2587
2588 // The absolute mouse position
2589 pos.left +
2590
2591 // Only for relative positioned nodes: Relative offset from element to offset parent
2592 this.offset.relative.left * mod +
2593
2594 // The offsetParent's offset without borders (offset + border)
2595 this.offset.parent.left * mod -
2596 ( ( this.cssPosition === "fixed" ?
2597 -this.offset.scroll.left :
2598 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
2599 )
2600 };
2601
2602 },
2603
2604 _generatePosition: function( event, constrainPosition ) {
2605
2606 var containment, co, top, left,
2607 o = this.options,
2608 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
2609 pageX = event.pageX,
2610 pageY = event.pageY;
2611
2612 // Cache the scroll
2613 if ( !scrollIsRootNode || !this.offset.scroll ) {
2614 this.offset.scroll = {
2615 top: this.scrollParent.scrollTop(),
2616 left: this.scrollParent.scrollLeft()
2617 };
2618 }
2619
2620 /*
2621 * - Position constraining -
2622 * Constrain the position to a mix of grid, containment.
2623 */
2624
2625 // If we are not dragging yet, we won't check for options
2626 if ( constrainPosition ) {
2627 if ( this.containment ) {
2628 if ( this.relativeContainer ) {
2629 co = this.relativeContainer.offset();
2630 containment = [
2631 this.containment[ 0 ] + co.left,
2632 this.containment[ 1 ] + co.top,
2633 this.containment[ 2 ] + co.left,
2634 this.containment[ 3 ] + co.top
2635 ];
2636 } else {
2637 containment = this.containment;
2638 }
2639
2640 if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
2641 pageX = containment[ 0 ] + this.offset.click.left;
2642 }
2643 if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
2644 pageY = containment[ 1 ] + this.offset.click.top;
2645 }
2646 if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
2647 pageX = containment[ 2 ] + this.offset.click.left;
2648 }
2649 if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
2650 pageY = containment[ 3 ] + this.offset.click.top;
2651 }
2652 }
2653
2654 if ( o.grid ) {
2655
2656 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid
2657 // argument errors in IE (see ticket #6950)
2658 top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
2659 this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
2660 pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
2661 top - this.offset.click.top > containment[ 3 ] ) ?
2662 top :
2663 ( ( top - this.offset.click.top >= containment[ 1 ] ) ?
2664 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
2665
2666 left = o.grid[ 0 ] ? this.originalPageX +
2667 Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
2668 this.originalPageX;
2669 pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
2670 left - this.offset.click.left > containment[ 2 ] ) ?
2671 left :
2672 ( ( left - this.offset.click.left >= containment[ 0 ] ) ?
2673 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
2674 }
2675
2676 if ( o.axis === "y" ) {
2677 pageX = this.originalPageX;
2678 }
2679
2680 if ( o.axis === "x" ) {
2681 pageY = this.originalPageY;
2682 }
2683 }
2684
2685 return {
2686 top: (
2687
2688 // The absolute mouse position
2689 pageY -
2690
2691 // Click offset (relative to the element)
2692 this.offset.click.top -
2693
2694 // Only for relative positioned nodes: Relative offset from element to offset parent
2695 this.offset.relative.top -
2696
2697 // The offsetParent's offset without borders (offset + border)
2698 this.offset.parent.top +
2699 ( this.cssPosition === "fixed" ?
2700 -this.offset.scroll.top :
2701 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
2702 ),
2703 left: (
2704
2705 // The absolute mouse position
2706 pageX -
2707
2708 // Click offset (relative to the element)
2709 this.offset.click.left -
2710
2711 // Only for relative positioned nodes: Relative offset from element to offset parent
2712 this.offset.relative.left -
2713
2714 // The offsetParent's offset without borders (offset + border)
2715 this.offset.parent.left +
2716 ( this.cssPosition === "fixed" ?
2717 -this.offset.scroll.left :
2718 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
2719 )
2720 };
2721
2722 },
2723
2724 _clear: function() {
2725 this._removeClass( this.helper, "ui-draggable-dragging" );
2726 if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
2727 this.helper.remove();
2728 }
2729 this.helper = null;
2730 this.cancelHelperRemoval = false;
2731 if ( this.destroyOnClear ) {
2732 this.destroy();
2733 }
2734 },
2735
2736 // From now on bulk stuff - mainly helpers
2737
2738 _trigger: function( type, event, ui ) {
2739 ui = ui || this._uiHash();
2740 $.ui.plugin.call( this, type, [ event, ui, this ], true );
2741
2742 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
2743 if ( /^(drag|start|stop)/.test( type ) ) {
2744 this.positionAbs = this._convertPositionTo( "absolute" );
2745 ui.offset = this.positionAbs;
2746 }
2747 return $.Widget.prototype._trigger.call( this, type, event, ui );
2748 },
2749
2750 plugins: {},
2751
2752 _uiHash: function() {
2753 return {
2754 helper: this.helper,
2755 position: this.position,
2756 originalPosition: this.originalPosition,
2757 offset: this.positionAbs
2758 };
2759 }
2760
2761 } );
2762
2763 $.ui.plugin.add( "draggable", "connectToSortable", {
2764 start: function( event, ui, draggable ) {
2765 var uiSortable = $.extend( {}, ui, {
2766 item: draggable.element
2767 } );
2768
2769 draggable.sortables = [];
2770 $( draggable.options.connectToSortable ).each( function() {
2771 var sortable = $( this ).sortable( "instance" );
2772
2773 if ( sortable && !sortable.options.disabled ) {
2774 draggable.sortables.push( sortable );
2775
2776 // RefreshPositions is called at drag start to refresh the containerCache
2777 // which is used in drag. This ensures it's initialized and synchronized
2778 // with any changes that might have happened on the page since initialization.
2779 sortable.refreshPositions();
2780 sortable._trigger( "activate", event, uiSortable );
2781 }
2782 } );
2783 },
2784 stop: function( event, ui, draggable ) {
2785 var uiSortable = $.extend( {}, ui, {
2786 item: draggable.element
2787 } );
2788
2789 draggable.cancelHelperRemoval = false;
2790
2791 $.each( draggable.sortables, function() {
2792 var sortable = this;
2793
2794 if ( sortable.isOver ) {
2795 sortable.isOver = 0;
2796
2797 // Allow this sortable to handle removing the helper
2798 draggable.cancelHelperRemoval = true;
2799 sortable.cancelHelperRemoval = false;
2800
2801 // Use _storedCSS To restore properties in the sortable,
2802 // as this also handles revert (#9675) since the draggable
2803 // may have modified them in unexpected ways (#8809)
2804 sortable._storedCSS = {
2805 position: sortable.placeholder.css( "position" ),
2806 top: sortable.placeholder.css( "top" ),
2807 left: sortable.placeholder.css( "left" )
2808 };
2809
2810 sortable._mouseStop( event );
2811
2812 // Once drag has ended, the sortable should return to using
2813 // its original helper, not the shared helper from draggable
2814 sortable.options.helper = sortable.options._helper;
2815 } else {
2816
2817 // Prevent this Sortable from removing the helper.
2818 // However, don't set the draggable to remove the helper
2819 // either as another connected Sortable may yet handle the removal.
2820 sortable.cancelHelperRemoval = true;
2821
2822 sortable._trigger( "deactivate", event, uiSortable );
2823 }
2824 } );
2825 },
2826 drag: function( event, ui, draggable ) {
2827 $.each( draggable.sortables, function() {
2828 var innermostIntersecting = false,
2829 sortable = this;
2830
2831 // Copy over variables that sortable's _intersectsWith uses
2832 sortable.positionAbs = draggable.positionAbs;
2833 sortable.helperProportions = draggable.helperProportions;
2834 sortable.offset.click = draggable.offset.click;
2835
2836 if ( sortable._intersectsWith( sortable.containerCache ) ) {
2837 innermostIntersecting = true;
2838
2839 $.each( draggable.sortables, function() {
2840
2841 // Copy over variables that sortable's _intersectsWith uses
2842 this.positionAbs = draggable.positionAbs;
2843 this.helperProportions = draggable.helperProportions;
2844 this.offset.click = draggable.offset.click;
2845
2846 if ( this !== sortable &&
2847 this._intersectsWith( this.containerCache ) &&
2848 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
2849 innermostIntersecting = false;
2850 }
2851
2852 return innermostIntersecting;
2853 } );
2854 }
2855
2856 if ( innermostIntersecting ) {
2857
2858 // If it intersects, we use a little isOver variable and set it once,
2859 // so that the move-in stuff gets fired only once.
2860 if ( !sortable.isOver ) {
2861 sortable.isOver = 1;
2862
2863 // Store draggable's parent in case we need to reappend to it later.
2864 draggable._parent = ui.helper.parent();
2865
2866 sortable.currentItem = ui.helper
2867 .appendTo( sortable.element )
2868 .data( "ui-sortable-item", true );
2869
2870 // Store helper option to later restore it
2871 sortable.options._helper = sortable.options.helper;
2872
2873 sortable.options.helper = function() {
2874 return ui.helper[ 0 ];
2875 };
2876
2877 // Fire the start events of the sortable with our passed browser event,
2878 // and our own helper (so it doesn't create a new one)
2879 event.target = sortable.currentItem[ 0 ];
2880 sortable._mouseCapture( event, true );
2881 sortable._mouseStart( event, true, true );
2882
2883 // Because the browser event is way off the new appended portlet,
2884 // modify necessary variables to reflect the changes
2885 sortable.offset.click.top = draggable.offset.click.top;
2886 sortable.offset.click.left = draggable.offset.click.left;
2887 sortable.offset.parent.left -= draggable.offset.parent.left -
2888 sortable.offset.parent.left;
2889 sortable.offset.parent.top -= draggable.offset.parent.top -
2890 sortable.offset.parent.top;
2891
2892 draggable._trigger( "toSortable", event );
2893
2894 // Inform draggable that the helper is in a valid drop zone,
2895 // used solely in the revert option to handle "valid/invalid".
2896 draggable.dropped = sortable.element;
2897
2898 // Need to refreshPositions of all sortables in the case that
2899 // adding to one sortable changes the location of the other sortables (#9675)
2900 $.each( draggable.sortables, function() {
2901 this.refreshPositions();
2902 } );
2903
2904 // Hack so receive/update callbacks work (mostly)
2905 draggable.currentItem = draggable.element;
2906 sortable.fromOutside = draggable;
2907 }
2908
2909 if ( sortable.currentItem ) {
2910 sortable._mouseDrag( event );
2911
2912 // Copy the sortable's position because the draggable's can potentially reflect
2913 // a relative position, while sortable is always absolute, which the dragged
2914 // element has now become. (#8809)
2915 ui.position = sortable.position;
2916 }
2917 } else {
2918
2919 // If it doesn't intersect with the sortable, and it intersected before,
2920 // we fake the drag stop of the sortable, but make sure it doesn't remove
2921 // the helper by using cancelHelperRemoval.
2922 if ( sortable.isOver ) {
2923
2924 sortable.isOver = 0;
2925 sortable.cancelHelperRemoval = true;
2926
2927 // Calling sortable's mouseStop would trigger a revert,
2928 // so revert must be temporarily false until after mouseStop is called.
2929 sortable.options._revert = sortable.options.revert;
2930 sortable.options.revert = false;
2931
2932 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
2933 sortable._mouseStop( event, true );
2934
2935 // Restore sortable behaviors that were modfied
2936 // when the draggable entered the sortable area (#9481)
2937 sortable.options.revert = sortable.options._revert;
2938 sortable.options.helper = sortable.options._helper;
2939
2940 if ( sortable.placeholder ) {
2941 sortable.placeholder.remove();
2942 }
2943
2944 // Restore and recalculate the draggable's offset considering the sortable
2945 // may have modified them in unexpected ways. (#8809, #10669)
2946 ui.helper.appendTo( draggable._parent );
2947 draggable._refreshOffsets( event );
2948 ui.position = draggable._generatePosition( event, true );
2949
2950 draggable._trigger( "fromSortable", event );
2951
2952 // Inform draggable that the helper is no longer in a valid drop zone
2953 draggable.dropped = false;
2954
2955 // Need to refreshPositions of all sortables just in case removing
2956 // from one sortable changes the location of other sortables (#9675)
2957 $.each( draggable.sortables, function() {
2958 this.refreshPositions();
2959 } );
2960 }
2961 }
2962 } );
2963 }
2964 } );
2965
2966 $.ui.plugin.add( "draggable", "cursor", {
2967 start: function( event, ui, instance ) {
2968 var t = $( "body" ),
2969 o = instance.options;
2970
2971 if ( t.css( "cursor" ) ) {
2972 o._cursor = t.css( "cursor" );
2973 }
2974 t.css( "cursor", o.cursor );
2975 },
2976 stop: function( event, ui, instance ) {
2977 var o = instance.options;
2978 if ( o._cursor ) {
2979 $( "body" ).css( "cursor", o._cursor );
2980 }
2981 }
2982 } );
2983
2984 $.ui.plugin.add( "draggable", "opacity", {
2985 start: function( event, ui, instance ) {
2986 var t = $( ui.helper ),
2987 o = instance.options;
2988 if ( t.css( "opacity" ) ) {
2989 o._opacity = t.css( "opacity" );
2990 }
2991 t.css( "opacity", o.opacity );
2992 },
2993 stop: function( event, ui, instance ) {
2994 var o = instance.options;
2995 if ( o._opacity ) {
2996 $( ui.helper ).css( "opacity", o._opacity );
2997 }
2998 }
2999 } );
3000
3001 $.ui.plugin.add( "draggable", "scroll", {
3002 start: function( event, ui, i ) {
3003 if ( !i.scrollParentNotHidden ) {
3004 i.scrollParentNotHidden = i.helper.scrollParent( false );
3005 }
3006
3007 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
3008 i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
3009 i.overflowOffset = i.scrollParentNotHidden.offset();
3010 }
3011 },
3012 drag: function( event, ui, i ) {
3013
3014 var o = i.options,
3015 scrolled = false,
3016 scrollParent = i.scrollParentNotHidden[ 0 ],
3017 document = i.document[ 0 ];
3018
3019 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
3020 if ( !o.axis || o.axis !== "x" ) {
3021 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
3022 o.scrollSensitivity ) {
3023 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
3024 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
3025 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
3026 }
3027 }
3028
3029 if ( !o.axis || o.axis !== "y" ) {
3030 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
3031 o.scrollSensitivity ) {
3032 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
3033 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
3034 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
3035 }
3036 }
3037
3038 } else {
3039
3040 if ( !o.axis || o.axis !== "x" ) {
3041 if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
3042 scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
3043 } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
3044 o.scrollSensitivity ) {
3045 scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
3046 }
3047 }
3048
3049 if ( !o.axis || o.axis !== "y" ) {
3050 if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
3051 scrolled = $( document ).scrollLeft(
3052 $( document ).scrollLeft() - o.scrollSpeed
3053 );
3054 } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
3055 o.scrollSensitivity ) {
3056 scrolled = $( document ).scrollLeft(
3057 $( document ).scrollLeft() + o.scrollSpeed
3058 );
3059 }
3060 }
3061
3062 }
3063
3064 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
3065 $.ui.ddmanager.prepareOffsets( i, event );
3066 }
3067
3068 }
3069 } );
3070
3071 $.ui.plugin.add( "draggable", "snap", {
3072 start: function( event, ui, i ) {
3073
3074 var o = i.options;
3075
3076 i.snapElements = [];
3077
3078 $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
3079 .each( function() {
3080 var $t = $( this ),
3081 $o = $t.offset();
3082 if ( this !== i.element[ 0 ] ) {
3083 i.snapElements.push( {
3084 item: this,
3085 width: $t.outerWidth(), height: $t.outerHeight(),
3086 top: $o.top, left: $o.left
3087 } );
3088 }
3089 } );
3090
3091 },
3092 drag: function( event, ui, inst ) {
3093
3094 var ts, bs, ls, rs, l, r, t, b, i, first,
3095 o = inst.options,
3096 d = o.snapTolerance,
3097 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
3098 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
3099
3100 for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
3101
3102 l = inst.snapElements[ i ].left - inst.margins.left;
3103 r = l + inst.snapElements[ i ].width;
3104 t = inst.snapElements[ i ].top - inst.margins.top;
3105 b = t + inst.snapElements[ i ].height;
3106
3107 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
3108 !$.contains( inst.snapElements[ i ].item.ownerDocument,
3109 inst.snapElements[ i ].item ) ) {
3110 if ( inst.snapElements[ i ].snapping ) {
3111 ( inst.options.snap.release &&
3112 inst.options.snap.release.call(
3113 inst.element,
3114 event,
3115 $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
3116 ) );
3117 }
3118 inst.snapElements[ i ].snapping = false;
3119 continue;
3120 }
3121
3122 if ( o.snapMode !== "inner" ) {
3123 ts = Math.abs( t - y2 ) <= d;
3124 bs = Math.abs( b - y1 ) <= d;
3125 ls = Math.abs( l - x2 ) <= d;
3126 rs = Math.abs( r - x1 ) <= d;
3127 if ( ts ) {
3128 ui.position.top = inst._convertPositionTo( "relative", {
3129 top: t - inst.helperProportions.height,
3130 left: 0
3131 } ).top;
3132 }
3133 if ( bs ) {
3134 ui.position.top = inst._convertPositionTo( "relative", {
3135 top: b,
3136 left: 0
3137 } ).top;
3138 }
3139 if ( ls ) {
3140 ui.position.left = inst._convertPositionTo( "relative", {
3141 top: 0,
3142 left: l - inst.helperProportions.width
3143 } ).left;
3144 }
3145 if ( rs ) {
3146 ui.position.left = inst._convertPositionTo( "relative", {
3147 top: 0,
3148 left: r
3149 } ).left;
3150 }
3151 }
3152
3153 first = ( ts || bs || ls || rs );
3154
3155 if ( o.snapMode !== "outer" ) {
3156 ts = Math.abs( t - y1 ) <= d;
3157 bs = Math.abs( b - y2 ) <= d;
3158 ls = Math.abs( l - x1 ) <= d;
3159 rs = Math.abs( r - x2 ) <= d;
3160 if ( ts ) {
3161 ui.position.top = inst._convertPositionTo( "relative", {
3162 top: t,
3163 left: 0
3164 } ).top;
3165 }
3166 if ( bs ) {
3167 ui.position.top = inst._convertPositionTo( "relative", {
3168 top: b - inst.helperProportions.height,
3169 left: 0
3170 } ).top;
3171 }
3172 if ( ls ) {
3173 ui.position.left = inst._convertPositionTo( "relative", {
3174 top: 0,
3175 left: l
3176 } ).left;
3177 }
3178 if ( rs ) {
3179 ui.position.left = inst._convertPositionTo( "relative", {
3180 top: 0,
3181 left: r - inst.helperProportions.width
3182 } ).left;
3183 }
3184 }
3185
3186 if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
3187 ( inst.options.snap.snap &&
3188 inst.options.snap.snap.call(
3189 inst.element,
3190 event,
3191 $.extend( inst._uiHash(), {
3192 snapItem: inst.snapElements[ i ].item
3193 } ) ) );
3194 }
3195 inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
3196
3197 }
3198
3199 }
3200 } );
3201
3202 $.ui.plugin.add( "draggable", "stack", {
3203 start: function( event, ui, instance ) {
3204 var min,
3205 o = instance.options,
3206 group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
3207 return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
3208 ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
3209 } );
3210
3211 if ( !group.length ) { return; }
3212
3213 min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
3214 $( group ).each( function( i ) {
3215 $( this ).css( "zIndex", min + i );
3216 } );
3217 this.css( "zIndex", ( min + group.length ) );
3218 }
3219 } );
3220
3221 $.ui.plugin.add( "draggable", "zIndex", {
3222 start: function( event, ui, instance ) {
3223 var t = $( ui.helper ),
3224 o = instance.options;
3225
3226 if ( t.css( "zIndex" ) ) {
3227 o._zIndex = t.css( "zIndex" );
3228 }
3229 t.css( "zIndex", o.zIndex );
3230 },
3231 stop: function( event, ui, instance ) {
3232 var o = instance.options;
3233
3234 if ( o._zIndex ) {
3235 $( ui.helper ).css( "zIndex", o._zIndex );
3236 }
3237 }
3238 } );
3239
3240 var widgetsDraggable = $.ui.draggable;
3241
3242
3243 /*!
3244 * jQuery UI Droppable 1.12.1
3245 * http://jqueryui.com
3246 *
3247 * Copyright jQuery Foundation and other contributors
3248 * Released under the MIT license.
3249 * http://jquery.org/license
3250 */
3251
3252 //>>label: Droppable
3253 //>>group: Interactions
3254 //>>description: Enables drop targets for draggable elements.
3255 //>>docs: http://api.jqueryui.com/droppable/
3256 //>>demos: http://jqueryui.com/droppable/
3257
3258
3259
3260 $.widget( "ui.droppable", {
3261 version: "1.12.1",
3262 widgetEventPrefix: "drop",
3263 options: {
3264 accept: "*",
3265 addClasses: true,
3266 greedy: false,
3267 scope: "default",
3268 tolerance: "intersect",
3269
3270 // Callbacks
3271 activate: null,
3272 deactivate: null,
3273 drop: null,
3274 out: null,
3275 over: null
3276 },
3277 _create: function() {
3278
3279 var proportions,
3280 o = this.options,
3281 accept = o.accept;
3282
3283 this.isover = false;
3284 this.isout = true;
3285
3286 this.accept = $.isFunction( accept ) ? accept : function( d ) {
3287 return d.is( accept );
3288 };
3289
3290 this.proportions = function( /* valueToWrite */ ) {
3291 if ( arguments.length ) {
3292
3293 // Store the droppable's proportions
3294 proportions = arguments[ 0 ];
3295 } else {
3296
3297 // Retrieve or derive the droppable's proportions
3298 return proportions ?
3299 proportions :
3300 proportions = {
3301 width: this.element[ 0 ].offsetWidth,
3302 height: this.element[ 0 ].offsetHeight
3303 };
3304 }
3305 };
3306
3307 this._addToManager( o.scope );
3308
3309 o.addClasses && this._addClass( "ui-droppable" );
3310
3311 },
3312
3313 _addToManager: function( scope ) {
3314
3315 // Add the reference and positions to the manager
3316 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
3317 $.ui.ddmanager.droppables[ scope ].push( this );
3318 },
3319
3320 _splice: function( drop ) {
3321 var i = 0;
3322 for ( ; i < drop.length; i++ ) {
3323 if ( drop[ i ] === this ) {
3324 drop.splice( i, 1 );
3325 }
3326 }
3327 },
3328
3329 _destroy: function() {
3330 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
3331
3332 this._splice( drop );
3333 },
3334
3335 _setOption: function( key, value ) {
3336
3337 if ( key === "accept" ) {
3338 this.accept = $.isFunction( value ) ? value : function( d ) {
3339 return d.is( value );
3340 };
3341 } else if ( key === "scope" ) {
3342 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
3343
3344 this._splice( drop );
3345 this._addToManager( value );
3346 }
3347
3348 this._super( key, value );
3349 },
3350
3351 _activate: function( event ) {
3352 var draggable = $.ui.ddmanager.current;
3353
3354 this._addActiveClass();
3355 if ( draggable ) {
3356 this._trigger( "activate", event, this.ui( draggable ) );
3357 }
3358 },
3359
3360 _deactivate: function( event ) {
3361 var draggable = $.ui.ddmanager.current;
3362
3363 this._removeActiveClass();
3364 if ( draggable ) {
3365 this._trigger( "deactivate", event, this.ui( draggable ) );
3366 }
3367 },
3368
3369 _over: function( event ) {
3370
3371 var draggable = $.ui.ddmanager.current;
3372
3373 // Bail if draggable and droppable are same element
3374 if ( !draggable || ( draggable.currentItem ||
3375 draggable.element )[ 0 ] === this.element[ 0 ] ) {
3376 return;
3377 }
3378
3379 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
3380 draggable.element ) ) ) {
3381 this._addHoverClass();
3382 this._trigger( "over", event, this.ui( draggable ) );
3383 }
3384
3385 },
3386
3387 _out: function( event ) {
3388
3389 var draggable = $.ui.ddmanager.current;
3390
3391 // Bail if draggable and droppable are same element
3392 if ( !draggable || ( draggable.currentItem ||
3393 draggable.element )[ 0 ] === this.element[ 0 ] ) {
3394 return;
3395 }
3396
3397 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
3398 draggable.element ) ) ) {
3399 this._removeHoverClass();
3400 this._trigger( "out", event, this.ui( draggable ) );
3401 }
3402
3403 },
3404
3405 _drop: function( event, custom ) {
3406
3407 var draggable = custom || $.ui.ddmanager.current,
3408 childrenIntersection = false;
3409
3410 // Bail if draggable and droppable are same element
3411 if ( !draggable || ( draggable.currentItem ||
3412 draggable.element )[ 0 ] === this.element[ 0 ] ) {
3413 return false;
3414 }
3415
3416 this.element
3417 .find( ":data(ui-droppable)" )
3418 .not( ".ui-draggable-dragging" )
3419 .each( function() {
3420 var inst = $( this ).droppable( "instance" );
3421 if (
3422 inst.options.greedy &&
3423 !inst.options.disabled &&
3424 inst.options.scope === draggable.options.scope &&
3425 inst.accept.call(
3426 inst.element[ 0 ], ( draggable.currentItem || draggable.element )
3427 ) &&
3428 intersect(
3429 draggable,
3430 $.extend( inst, { offset: inst.element.offset() } ),
3431 inst.options.tolerance, event
3432 )
3433 ) {
3434 childrenIntersection = true;
3435 return false; }
3436 } );
3437 if ( childrenIntersection ) {
3438 return false;
3439 }
3440
3441 if ( this.accept.call( this.element[ 0 ],
3442 ( draggable.currentItem || draggable.element ) ) ) {
3443 this._removeActiveClass();
3444 this._removeHoverClass();
3445
3446 this._trigger( "drop", event, this.ui( draggable ) );
3447 return this.element;
3448 }
3449
3450 return false;
3451
3452 },
3453
3454 ui: function( c ) {
3455 return {
3456 draggable: ( c.currentItem || c.element ),
3457 helper: c.helper,
3458 position: c.position,
3459 offset: c.positionAbs
3460 };
3461 },
3462
3463 // Extension points just to make backcompat sane and avoid duplicating logic
3464 // TODO: Remove in 1.13 along with call to it below
3465 _addHoverClass: function() {
3466 this._addClass( "ui-droppable-hover" );
3467 },
3468
3469 _removeHoverClass: function() {
3470 this._removeClass( "ui-droppable-hover" );
3471 },
3472
3473 _addActiveClass: function() {
3474 this._addClass( "ui-droppable-active" );
3475 },
3476
3477 _removeActiveClass: function() {
3478 this._removeClass( "ui-droppable-active" );
3479 }
3480 } );
3481
3482 var intersect = $.ui.intersect = ( function() {
3483 function isOverAxis( x, reference, size ) {
3484 return ( x >= reference ) && ( x < ( reference + size ) );
3485 }
3486
3487 return function( draggable, droppable, toleranceMode, event ) {
3488
3489 if ( !droppable.offset ) {
3490 return false;
3491 }
3492
3493 var x1 = ( draggable.positionAbs ||
3494 draggable.position.absolute ).left + draggable.margins.left,
3495 y1 = ( draggable.positionAbs ||
3496 draggable.position.absolute ).top + draggable.margins.top,
3497 x2 = x1 + draggable.helperProportions.width,
3498 y2 = y1 + draggable.helperProportions.height,
3499 l = droppable.offset.left,
3500 t = droppable.offset.top,
3501 r = l + droppable.proportions().width,
3502 b = t + droppable.proportions().height;
3503
3504 switch ( toleranceMode ) {
3505 case "fit":
3506 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
3507 case "intersect":
3508 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
3509 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
3510 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
3511 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
3512 case "pointer":
3513 return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
3514 isOverAxis( event.pageX, l, droppable.proportions().width );
3515 case "touch":
3516 return (
3517 ( y1 >= t && y1 <= b ) || // Top edge touching
3518 ( y2 >= t && y2 <= b ) || // Bottom edge touching
3519 ( y1 < t && y2 > b ) // Surrounded vertically
3520 ) && (
3521 ( x1 >= l && x1 <= r ) || // Left edge touching
3522 ( x2 >= l && x2 <= r ) || // Right edge touching
3523 ( x1 < l && x2 > r ) // Surrounded horizontally
3524 );
3525 default:
3526 return false;
3527 }
3528 };
3529 } )();
3530
3531 /*
3532 This manager tracks offsets of draggables and droppables
3533 */
3534 $.ui.ddmanager = {
3535 current: null,
3536 droppables: { "default": [] },
3537 prepareOffsets: function( t, event ) {
3538
3539 var i, j,
3540 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
3541 type = event ? event.type : null, // workaround for #2317
3542 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
3543
3544 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
3545
3546 // No disabled and non-accepted
3547 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
3548 ( t.currentItem || t.element ) ) ) ) {
3549 continue;
3550 }
3551
3552 // Filter out elements in the current dragged item
3553 for ( j = 0; j < list.length; j++ ) {
3554 if ( list[ j ] === m[ i ].element[ 0 ] ) {
3555 m[ i ].proportions().height = 0;
3556 continue droppablesLoop;
3557 }
3558 }
3559
3560 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
3561 if ( !m[ i ].visible ) {
3562 continue;
3563 }
3564
3565 // Activate the droppable if used directly from draggables
3566 if ( type === "mousedown" ) {
3567 m[ i ]._activate.call( m[ i ], event );
3568 }
3569
3570 m[ i ].offset = m[ i ].element.offset();
3571 m[ i ].proportions( {
3572 width: m[ i ].element[ 0 ].offsetWidth,
3573 height: m[ i ].element[ 0 ].offsetHeight
3574 } );
3575
3576 }
3577
3578 },
3579 drop: function( draggable, event ) {
3580
3581 var dropped = false;
3582
3583 // Create a copy of the droppables in case the list changes during the drop (#9116)
3584 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
3585
3586 if ( !this.options ) {
3587 return;
3588 }
3589 if ( !this.options.disabled && this.visible &&
3590 intersect( draggable, this, this.options.tolerance, event ) ) {
3591 dropped = this._drop.call( this, event ) || dropped;
3592 }
3593
3594 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
3595 ( draggable.currentItem || draggable.element ) ) ) {
3596 this.isout = true;
3597 this.isover = false;
3598 this._deactivate.call( this, event );
3599 }
3600
3601 } );
3602 return dropped;
3603
3604 },
3605 dragStart: function( draggable, event ) {
3606
3607 // Listen for scrolling so that if the dragging causes scrolling the position of the
3608 // droppables can be recalculated (see #5003)
3609 draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
3610 if ( !draggable.options.refreshPositions ) {
3611 $.ui.ddmanager.prepareOffsets( draggable, event );
3612 }
3613 } );
3614 },
3615 drag: function( draggable, event ) {
3616
3617 // If you have a highly dynamic page, you might try this option. It renders positions
3618 // every time you move the mouse.
3619 if ( draggable.options.refreshPositions ) {
3620 $.ui.ddmanager.prepareOffsets( draggable, event );
3621 }
3622
3623 // Run through all droppables and check their positions based on specific tolerance options
3624 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
3625
3626 if ( this.options.disabled || this.greedyChild || !this.visible ) {
3627 return;
3628 }
3629
3630 var parentInstance, scope, parent,
3631 intersects = intersect( draggable, this, this.options.tolerance, event ),
3632 c = !intersects && this.isover ?
3633 "isout" :
3634 ( intersects && !this.isover ? "isover" : null );
3635 if ( !c ) {
3636 return;
3637 }
3638
3639 if ( this.options.greedy ) {
3640
3641 // find droppable parents with same scope
3642 scope = this.options.scope;
3643 parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
3644 return $( this ).droppable( "instance" ).options.scope === scope;
3645 } );
3646
3647 if ( parent.length ) {
3648 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
3649 parentInstance.greedyChild = ( c === "isover" );
3650 }
3651 }
3652
3653 // We just moved into a greedy child
3654 if ( parentInstance && c === "isover" ) {
3655 parentInstance.isover = false;
3656 parentInstance.isout = true;
3657 parentInstance._out.call( parentInstance, event );
3658 }
3659
3660 this[ c ] = true;
3661 this[ c === "isout" ? "isover" : "isout" ] = false;
3662 this[ c === "isover" ? "_over" : "_out" ].call( this, event );
3663
3664 // We just moved out of a greedy child
3665 if ( parentInstance && c === "isout" ) {
3666 parentInstance.isout = false;
3667 parentInstance.isover = true;
3668 parentInstance._over.call( parentInstance, event );
3669 }
3670 } );
3671
3672 },
3673 dragStop: function( draggable, event ) {
3674 draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
3675
3676 // Call prepareOffsets one final time since IE does not fire return scroll events when
3677 // overflow was caused by drag (see #5003)
3678 if ( !draggable.options.refreshPositions ) {
3679 $.ui.ddmanager.prepareOffsets( draggable, event );
3680 }
3681 }
3682 };
3683
3684 // DEPRECATED
3685 // TODO: switch return back to widget declaration at top of file when this is removed
3686 if ( $.uiBackCompat !== false ) {
3687
3688 // Backcompat for activeClass and hoverClass options
3689 $.widget( "ui.droppable", $.ui.droppable, {
3690 options: {
3691 hoverClass: false,
3692 activeClass: false
3693 },
3694 _addActiveClass: function() {
3695 this._super();
3696 if ( this.options.activeClass ) {
3697 this.element.addClass( this.options.activeClass );
3698 }
3699 },
3700 _removeActiveClass: function() {
3701 this._super();
3702 if ( this.options.activeClass ) {
3703 this.element.removeClass( this.options.activeClass );
3704 }
3705 },
3706 _addHoverClass: function() {
3707 this._super();
3708 if ( this.options.hoverClass ) {
3709 this.element.addClass( this.options.hoverClass );
3710 }
3711 },
3712 _removeHoverClass: function() {
3713 this._super();
3714 if ( this.options.hoverClass ) {
3715 this.element.removeClass( this.options.hoverClass );
3716 }
3717 }
3718 } );
3719 }
3720
3721 var widgetsDroppable = $.ui.droppable;
3722
3723
3724 /*!
3725 * jQuery UI Resizable 1.12.1
3726 * http://jqueryui.com
3727 *
3728 * Copyright jQuery Foundation and other contributors
3729 * Released under the MIT license.
3730 * http://jquery.org/license
3731 */
3732
3733 //>>label: Resizable
3734 //>>group: Interactions
3735 //>>description: Enables resize functionality for any element.
3736 //>>docs: http://api.jqueryui.com/resizable/
3737 //>>demos: http://jqueryui.com/resizable/
3738 //>>css.structure: ../../themes/base/core.css
3739 //>>css.structure: ../../themes/base/resizable.css
3740 //>>css.theme: ../../themes/base/theme.css
3741
3742
3743
3744 $.widget( "ui.resizable", $.ui.mouse, {
3745 version: "1.12.1",
3746 widgetEventPrefix: "resize",
3747 options: {
3748 alsoResize: false,
3749 animate: false,
3750 animateDuration: "slow",
3751 animateEasing: "swing",
3752 aspectRatio: false,
3753 autoHide: false,
3754 classes: {
3755 "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
3756 },
3757 containment: false,
3758 ghost: false,
3759 grid: false,
3760 handles: "e,s,se",
3761 helper: false,
3762 maxHeight: null,
3763 maxWidth: null,
3764 minHeight: 10,
3765 minWidth: 10,
3766
3767 // See #7960
3768 zIndex: 90,
3769
3770 // Callbacks
3771 resize: null,
3772 start: null,
3773 stop: null
3774 },
3775
3776 _num: function( value ) {
3777 return parseFloat( value ) || 0;
3778 },
3779
3780 _isNumber: function( value ) {
3781 return !isNaN( parseFloat( value ) );
3782 },
3783
3784 _hasScroll: function( el, a ) {
3785
3786 if ( $( el ).css( "overflow" ) === "hidden" ) {
3787 return false;
3788 }
3789
3790 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
3791 has = false;
3792
3793 if ( el[ scroll ] > 0 ) {
3794 return true;
3795 }
3796
3797 // TODO: determine which cases actually cause this to happen
3798 // if the element doesn't have the scroll set, see if it's possible to
3799 // set the scroll
3800 el[ scroll ] = 1;
3801 has = ( el[ scroll ] > 0 );
3802 el[ scroll ] = 0;
3803 return has;
3804 },
3805
3806 _create: function() {
3807
3808 var margins,
3809 o = this.options,
3810 that = this;
3811 this._addClass( "ui-resizable" );
3812
3813 $.extend( this, {
3814 _aspectRatio: !!( o.aspectRatio ),
3815 aspectRatio: o.aspectRatio,
3816 originalElement: this.element,
3817 _proportionallyResizeElements: [],
3818 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
3819 } );
3820
3821 // Wrap the element if it cannot hold child nodes
3822 if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
3823
3824 this.element.wrap(
3825 $( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
3826 position: this.element.css( "position" ),
3827 width: this.element.outerWidth(),
3828 height: this.element.outerHeight(),
3829 top: this.element.css( "top" ),
3830 left: this.element.css( "left" )
3831 } )
3832 );
3833
3834 this.element = this.element.parent().data(
3835 "ui-resizable", this.element.resizable( "instance" )
3836 );
3837
3838 this.elementIsWrapper = true;
3839
3840 margins = {
3841 marginTop: this.originalElement.css( "marginTop" ),
3842 marginRight: this.originalElement.css( "marginRight" ),
3843 marginBottom: this.originalElement.css( "marginBottom" ),
3844 marginLeft: this.originalElement.css( "marginLeft" )
3845 };
3846
3847 this.element.css( margins );
3848 this.originalElement.css( "margin", 0 );
3849
3850 // support: Safari
3851 // Prevent Safari textarea resize
3852 this.originalResizeStyle = this.originalElement.css( "resize" );
3853 this.originalElement.css( "resize", "none" );
3854
3855 this._proportionallyResizeElements.push( this.originalElement.css( {
3856 position: "static",
3857 zoom: 1,
3858 display: "block"
3859 } ) );
3860
3861 // Support: IE9
3862 // avoid IE jump (hard set the margin)
3863 this.originalElement.css( margins );
3864
3865 this._proportionallyResize();
3866 }
3867
3868 this._setupHandles();
3869
3870 if ( o.autoHide ) {
3871 $( this.element )
3872 .on( "mouseenter", function() {
3873 if ( o.disabled ) {
3874 return;
3875 }
3876 that._removeClass( "ui-resizable-autohide" );
3877 that._handles.show();
3878 } )
3879 .on( "mouseleave", function() {
3880 if ( o.disabled ) {
3881 return;
3882 }
3883 if ( !that.resizing ) {
3884 that._addClass( "ui-resizable-autohide" );
3885 that._handles.hide();
3886 }
3887 } );
3888 }
3889
3890 this._mouseInit();
3891 },
3892
3893 _destroy: function() {
3894
3895 this._mouseDestroy();
3896
3897 var wrapper,
3898 _destroy = function( exp ) {
3899 $( exp )
3900 .removeData( "resizable" )
3901 .removeData( "ui-resizable" )
3902 .off( ".resizable" )
3903 .find( ".ui-resizable-handle" )
3904 .remove();
3905 };
3906
3907 // TODO: Unwrap at same DOM position
3908 if ( this.elementIsWrapper ) {
3909 _destroy( this.element );
3910 wrapper = this.element;
3911 this.originalElement.css( {
3912 position: wrapper.css( "position" ),
3913 width: wrapper.outerWidth(),
3914 height: wrapper.outerHeight(),
3915 top: wrapper.css( "top" ),
3916 left: wrapper.css( "left" )
3917 } ).insertAfter( wrapper );
3918 wrapper.remove();
3919 }
3920
3921 this.originalElement.css( "resize", this.originalResizeStyle );
3922 _destroy( this.originalElement );
3923
3924 return this;
3925 },
3926
3927 _setOption: function( key, value ) {
3928 this._super( key, value );
3929
3930 switch ( key ) {
3931 case "handles":
3932 this._removeHandles();
3933 this._setupHandles();
3934 break;
3935 default:
3936 break;
3937 }
3938 },
3939
3940 _setupHandles: function() {
3941 var o = this.options, handle, i, n, hname, axis, that = this;
3942 this.handles = o.handles ||
3943 ( !$( ".ui-resizable-handle", this.element ).length ?
3944 "e,s,se" : {
3945 n: ".ui-resizable-n",
3946 e: ".ui-resizable-e",
3947 s: ".ui-resizable-s",
3948 w: ".ui-resizable-w",
3949 se: ".ui-resizable-se",
3950 sw: ".ui-resizable-sw",
3951 ne: ".ui-resizable-ne",
3952 nw: ".ui-resizable-nw"
3953 } );
3954
3955 this._handles = $();
3956 if ( this.handles.constructor === String ) {
3957
3958 if ( this.handles === "all" ) {
3959 this.handles = "n,e,s,w,se,sw,ne,nw";
3960 }
3961
3962 n = this.handles.split( "," );
3963 this.handles = {};
3964
3965 for ( i = 0; i < n.length; i++ ) {
3966
3967 handle = $.trim( n[ i ] );
3968 hname = "ui-resizable-" + handle;
3969 axis = $( "<div>" );
3970 this._addClass( axis, "ui-resizable-handle " + hname );
3971
3972 axis.css( { zIndex: o.zIndex } );
3973
3974 this.handles[ handle ] = ".ui-resizable-" + handle;
3975 this.element.append( axis );
3976 }
3977
3978 }
3979
3980 this._renderAxis = function( target ) {
3981
3982 var i, axis, padPos, padWrapper;
3983
3984 target = target || this.element;
3985
3986 for ( i in this.handles ) {
3987
3988 if ( this.handles[ i ].constructor === String ) {
3989 this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
3990 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
3991 this.handles[ i ] = $( this.handles[ i ] );
3992 this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
3993 }
3994
3995 if ( this.elementIsWrapper &&
3996 this.originalElement[ 0 ]
3997 .nodeName
3998 .match( /^(textarea|input|select|button)$/i ) ) {
3999 axis = $( this.handles[ i ], this.element );
4000
4001 padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
4002 axis.outerHeight() :
4003 axis.outerWidth();
4004
4005 padPos = [ "padding",
4006 /ne|nw|n/.test( i ) ? "Top" :
4007 /se|sw|s/.test( i ) ? "Bottom" :
4008 /^e$/.test( i ) ? "Right" : "Left" ].join( "" );
4009
4010 target.css( padPos, padWrapper );
4011
4012 this._proportionallyResize();
4013 }
4014
4015 this._handles = this._handles.add( this.handles[ i ] );
4016 }
4017 };
4018
4019 // TODO: make renderAxis a prototype function
4020 this._renderAxis( this.element );
4021
4022 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
4023 this._handles.disableSelection();
4024
4025 this._handles.on( "mouseover", function() {
4026 if ( !that.resizing ) {
4027 if ( this.className ) {
4028 axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
4029 }
4030 that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
4031 }
4032 } );
4033
4034 if ( o.autoHide ) {
4035 this._handles.hide();
4036 this._addClass( "ui-resizable-autohide" );
4037 }
4038 },
4039
4040 _removeHandles: function() {
4041 this._handles.remove();
4042 },
4043
4044 _mouseCapture: function( event ) {
4045 var i, handle,
4046 capture = false;
4047
4048 for ( i in this.handles ) {
4049 handle = $( this.handles[ i ] )[ 0 ];
4050 if ( handle === event.target || $.contains( handle, event.target ) ) {
4051 capture = true;
4052 }
4053 }
4054
4055 return !this.options.disabled && capture;
4056 },
4057
4058 _mouseStart: function( event ) {
4059
4060 var curleft, curtop, cursor,
4061 o = this.options,
4062 el = this.element;
4063
4064 this.resizing = true;
4065
4066 this._renderProxy();
4067
4068 curleft = this._num( this.helper.css( "left" ) );
4069 curtop = this._num( this.helper.css( "top" ) );
4070
4071 if ( o.containment ) {
4072 curleft += $( o.containment ).scrollLeft() || 0;
4073 curtop += $( o.containment ).scrollTop() || 0;
4074 }
4075
4076 this.offset = this.helper.offset();
4077 this.position = { left: curleft, top: curtop };
4078
4079 this.size = this._helper ? {
4080 width: this.helper.width(),
4081 height: this.helper.height()
4082 } : {
4083 width: el.width(),
4084 height: el.height()
4085 };
4086
4087 this.originalSize = this._helper ? {
4088 width: el.outerWidth(),
4089 height: el.outerHeight()
4090 } : {
4091 width: el.width(),
4092 height: el.height()
4093 };
4094
4095 this.sizeDiff = {
4096 width: el.outerWidth() - el.width(),
4097 height: el.outerHeight() - el.height()
4098 };
4099
4100 this.originalPosition = { left: curleft, top: curtop };
4101 this.originalMousePosition = { left: event.pageX, top: event.pageY };
4102
4103 this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
4104 o.aspectRatio :
4105 ( ( this.originalSize.width / this.originalSize.height ) || 1 );
4106
4107 cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
4108 $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
4109
4110 this._addClass( "ui-resizable-resizing" );
4111 this._propagate( "start", event );
4112 return true;
4113 },
4114
4115 _mouseDrag: function( event ) {
4116
4117 var data, props,
4118 smp = this.originalMousePosition,
4119 a = this.axis,
4120 dx = ( event.pageX - smp.left ) || 0,
4121 dy = ( event.pageY - smp.top ) || 0,
4122 trigger = this._change[ a ];
4123
4124 this._updatePrevProperties();
4125
4126 if ( !trigger ) {
4127 return false;
4128 }
4129
4130 data = trigger.apply( this, [ event, dx, dy ] );
4131
4132 this._updateVirtualBoundaries( event.shiftKey );
4133 if ( this._aspectRatio || event.shiftKey ) {
4134 data = this._updateRatio( data, event );
4135 }
4136
4137 data = this._respectSize( data, event );
4138
4139 this._updateCache( data );
4140
4141 this._propagate( "resize", event );
4142
4143 props = this._applyChanges();
4144
4145 if ( !this._helper && this._proportionallyResizeElements.length ) {
4146 this._proportionallyResize();
4147 }
4148
4149 if ( !$.isEmptyObject( props ) ) {
4150 this._updatePrevProperties();
4151 this._trigger( "resize", event, this.ui() );
4152 this._applyChanges();
4153 }
4154
4155 return false;
4156 },
4157
4158 _mouseStop: function( event ) {
4159
4160 this.resizing = false;
4161 var pr, ista, soffseth, soffsetw, s, left, top,
4162 o = this.options, that = this;
4163
4164 if ( this._helper ) {
4165
4166 pr = this._proportionallyResizeElements;
4167 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
4168 soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
4169 soffsetw = ista ? 0 : that.sizeDiff.width;
4170
4171 s = {
4172 width: ( that.helper.width() - soffsetw ),
4173 height: ( that.helper.height() - soffseth )
4174 };
4175 left = ( parseFloat( that.element.css( "left" ) ) +
4176 ( that.position.left - that.originalPosition.left ) ) || null;
4177 top = ( parseFloat( that.element.css( "top" ) ) +
4178 ( that.position.top - that.originalPosition.top ) ) || null;
4179
4180 if ( !o.animate ) {
4181 this.element.css( $.extend( s, { top: top, left: left } ) );
4182 }
4183
4184 that.helper.height( that.size.height );
4185 that.helper.width( that.size.width );
4186
4187 if ( this._helper && !o.animate ) {
4188 this._proportionallyResize();
4189 }
4190 }
4191
4192 $( "body" ).css( "cursor", "auto" );
4193
4194 this._removeClass( "ui-resizable-resizing" );
4195
4196 this._propagate( "stop", event );
4197
4198 if ( this._helper ) {
4199 this.helper.remove();
4200 }
4201
4202 return false;
4203
4204 },
4205
4206 _updatePrevProperties: function() {
4207 this.prevPosition = {
4208 top: this.position.top,
4209 left: this.position.left
4210 };
4211 this.prevSize = {
4212 width: this.size.width,
4213 height: this.size.height
4214 };
4215 },
4216
4217 _applyChanges: function() {
4218 var props = {};
4219
4220 if ( this.position.top !== this.prevPosition.top ) {
4221 props.top = this.position.top + "px";
4222 }
4223 if ( this.position.left !== this.prevPosition.left ) {
4224 props.left = this.position.left + "px";
4225 }
4226 if ( this.size.width !== this.prevSize.width ) {
4227 props.width = this.size.width + "px";
4228 }
4229 if ( this.size.height !== this.prevSize.height ) {
4230 props.height = this.size.height + "px";
4231 }
4232
4233 this.helper.css( props );
4234
4235 return props;
4236 },
4237
4238 _updateVirtualBoundaries: function( forceAspectRatio ) {
4239 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
4240 o = this.options;
4241
4242 b = {
4243 minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
4244 maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
4245 minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
4246 maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
4247 };
4248
4249 if ( this._aspectRatio || forceAspectRatio ) {
4250 pMinWidth = b.minHeight * this.aspectRatio;
4251 pMinHeight = b.minWidth / this.aspectRatio;
4252 pMaxWidth = b.maxHeight * this.aspectRatio;
4253 pMaxHeight = b.maxWidth / this.aspectRatio;
4254
4255 if ( pMinWidth > b.minWidth ) {
4256 b.minWidth = pMinWidth;
4257 }
4258 if ( pMinHeight > b.minHeight ) {
4259 b.minHeight = pMinHeight;
4260 }
4261 if ( pMaxWidth < b.maxWidth ) {
4262 b.maxWidth = pMaxWidth;
4263 }
4264 if ( pMaxHeight < b.maxHeight ) {
4265 b.maxHeight = pMaxHeight;
4266 }
4267 }
4268 this._vBoundaries = b;
4269 },
4270
4271 _updateCache: function( data ) {
4272 this.offset = this.helper.offset();
4273 if ( this._isNumber( data.left ) ) {
4274 this.position.left = data.left;
4275 }
4276 if ( this._isNumber( data.top ) ) {
4277 this.position.top = data.top;
4278 }
4279 if ( this._isNumber( data.height ) ) {
4280 this.size.height = data.height;
4281 }
4282 if ( this._isNumber( data.width ) ) {
4283 this.size.width = data.width;
4284 }
4285 },
4286
4287 _updateRatio: function( data ) {
4288
4289 var cpos = this.position,
4290 csize = this.size,
4291 a = this.axis;
4292
4293 if ( this._isNumber( data.height ) ) {
4294 data.width = ( data.height * this.aspectRatio );
4295 } else if ( this._isNumber( data.width ) ) {
4296 data.height = ( data.width / this.aspectRatio );
4297 }
4298
4299 if ( a === "sw" ) {
4300 data.left = cpos.left + ( csize.width - data.width );
4301 data.top = null;
4302 }
4303 if ( a === "nw" ) {
4304 data.top = cpos.top + ( csize.height - data.height );
4305 data.left = cpos.left + ( csize.width - data.width );
4306 }
4307
4308 return data;
4309 },
4310
4311 _respectSize: function( data ) {
4312
4313 var o = this._vBoundaries,
4314 a = this.axis,
4315 ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
4316 ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
4317 isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
4318 isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
4319 dw = this.originalPosition.left + this.originalSize.width,
4320 dh = this.originalPosition.top + this.originalSize.height,
4321 cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
4322 if ( isminw ) {
4323 data.width = o.minWidth;
4324 }
4325 if ( isminh ) {
4326 data.height = o.minHeight;
4327 }
4328 if ( ismaxw ) {
4329 data.width = o.maxWidth;
4330 }
4331 if ( ismaxh ) {
4332 data.height = o.maxHeight;
4333 }
4334
4335 if ( isminw && cw ) {
4336 data.left = dw - o.minWidth;
4337 }
4338 if ( ismaxw && cw ) {
4339 data.left = dw - o.maxWidth;
4340 }
4341 if ( isminh && ch ) {
4342 data.top = dh - o.minHeight;
4343 }
4344 if ( ismaxh && ch ) {
4345 data.top = dh - o.maxHeight;
4346 }
4347
4348 // Fixing jump error on top/left - bug #2330
4349 if ( !data.width && !data.height && !data.left && data.top ) {
4350 data.top = null;
4351 } else if ( !data.width && !data.height && !data.top && data.left ) {
4352 data.left = null;
4353 }
4354
4355 return data;
4356 },
4357
4358 _getPaddingPlusBorderDimensions: function( element ) {
4359 var i = 0,
4360 widths = [],
4361 borders = [
4362 element.css( "borderTopWidth" ),
4363 element.css( "borderRightWidth" ),
4364 element.css( "borderBottomWidth" ),
4365 element.css( "borderLeftWidth" )
4366 ],
4367 paddings = [
4368 element.css( "paddingTop" ),
4369 element.css( "paddingRight" ),
4370 element.css( "paddingBottom" ),
4371 element.css( "paddingLeft" )
4372 ];
4373
4374 for ( ; i < 4; i++ ) {
4375 widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
4376 widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
4377 }
4378
4379 return {
4380 height: widths[ 0 ] + widths[ 2 ],
4381 width: widths[ 1 ] + widths[ 3 ]
4382 };
4383 },
4384
4385 _proportionallyResize: function() {
4386
4387 if ( !this._proportionallyResizeElements.length ) {
4388 return;
4389 }
4390
4391 var prel,
4392 i = 0,
4393 element = this.helper || this.element;
4394
4395 for ( ; i < this._proportionallyResizeElements.length; i++ ) {
4396
4397 prel = this._proportionallyResizeElements[ i ];
4398
4399 // TODO: Seems like a bug to cache this.outerDimensions
4400 // considering that we are in a loop.
4401 if ( !this.outerDimensions ) {
4402 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
4403 }
4404
4405 prel.css( {
4406 height: ( element.height() - this.outerDimensions.height ) || 0,
4407 width: ( element.width() - this.outerDimensions.width ) || 0
4408 } );
4409
4410 }
4411
4412 },
4413
4414 _renderProxy: function() {
4415
4416 var el = this.element, o = this.options;
4417 this.elementOffset = el.offset();
4418
4419 if ( this._helper ) {
4420
4421 this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );
4422
4423 this._addClass( this.helper, this._helper );
4424 this.helper.css( {
4425 width: this.element.outerWidth(),
4426 height: this.element.outerHeight(),
4427 position: "absolute",
4428 left: this.elementOffset.left + "px",
4429 top: this.elementOffset.top + "px",
4430 zIndex: ++o.zIndex //TODO: Don't modify option
4431 } );
4432
4433 this.helper
4434 .appendTo( "body" )
4435 .disableSelection();
4436
4437 } else {
4438 this.helper = this.element;
4439 }
4440
4441 },
4442
4443 _change: {
4444 e: function( event, dx ) {
4445 return { width: this.originalSize.width + dx };
4446 },
4447 w: function( event, dx ) {
4448 var cs = this.originalSize, sp = this.originalPosition;
4449 return { left: sp.left + dx, width: cs.width - dx };
4450 },
4451 n: function( event, dx, dy ) {
4452 var cs = this.originalSize, sp = this.originalPosition;
4453 return { top: sp.top + dy, height: cs.height - dy };
4454 },
4455 s: function( event, dx, dy ) {
4456 return { height: this.originalSize.height + dy };
4457 },
4458 se: function( event, dx, dy ) {
4459 return $.extend( this._change.s.apply( this, arguments ),
4460 this._change.e.apply( this, [ event, dx, dy ] ) );
4461 },
4462 sw: function( event, dx, dy ) {
4463 return $.extend( this._change.s.apply( this, arguments ),
4464 this._change.w.apply( this, [ event, dx, dy ] ) );
4465 },
4466 ne: function( event, dx, dy ) {
4467 return $.extend( this._change.n.apply( this, arguments ),
4468 this._change.e.apply( this, [ event, dx, dy ] ) );
4469 },
4470 nw: function( event, dx, dy ) {
4471 return $.extend( this._change.n.apply( this, arguments ),
4472 this._change.w.apply( this, [ event, dx, dy ] ) );
4473 }
4474 },
4475
4476 _propagate: function( n, event ) {
4477 $.ui.plugin.call( this, n, [ event, this.ui() ] );
4478 ( n !== "resize" && this._trigger( n, event, this.ui() ) );
4479 },
4480
4481 plugins: {},
4482
4483 ui: function() {
4484 return {
4485 originalElement: this.originalElement,
4486 element: this.element,
4487 helper: this.helper,
4488 position: this.position,
4489 size: this.size,
4490 originalSize: this.originalSize,
4491 originalPosition: this.originalPosition
4492 };
4493 }
4494
4495 } );
4496
4497 /*
4498 * Resizable Extensions
4499 */
4500
4501 $.ui.plugin.add( "resizable", "animate", {
4502
4503 stop: function( event ) {
4504 var that = $( this ).resizable( "instance" ),
4505 o = that.options,
4506 pr = that._proportionallyResizeElements,
4507 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
4508 soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
4509 soffsetw = ista ? 0 : that.sizeDiff.width,
4510 style = {
4511 width: ( that.size.width - soffsetw ),
4512 height: ( that.size.height - soffseth )
4513 },
4514 left = ( parseFloat( that.element.css( "left" ) ) +
4515 ( that.position.left - that.originalPosition.left ) ) || null,
4516 top = ( parseFloat( that.element.css( "top" ) ) +
4517 ( that.position.top - that.originalPosition.top ) ) || null;
4518
4519 that.element.animate(
4520 $.extend( style, top && left ? { top: top, left: left } : {} ), {
4521 duration: o.animateDuration,
4522 easing: o.animateEasing,
4523 step: function() {
4524
4525 var data = {
4526 width: parseFloat( that.element.css( "width" ) ),
4527 height: parseFloat( that.element.css( "height" ) ),
4528 top: parseFloat( that.element.css( "top" ) ),
4529 left: parseFloat( that.element.css( "left" ) )
4530 };
4531
4532 if ( pr && pr.length ) {
4533 $( pr[ 0 ] ).css( { width: data.width, height: data.height } );
4534 }
4535
4536 // Propagating resize, and updating values for each animation step
4537 that._updateCache( data );
4538 that._propagate( "resize", event );
4539
4540 }
4541 }
4542 );
4543 }
4544
4545 } );
4546
4547 $.ui.plugin.add( "resizable", "containment", {
4548
4549 start: function() {
4550 var element, p, co, ch, cw, width, height,
4551 that = $( this ).resizable( "instance" ),
4552 o = that.options,
4553 el = that.element,
4554 oc = o.containment,
4555 ce = ( oc instanceof $ ) ?
4556 oc.get( 0 ) :
4557 ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
4558
4559 if ( !ce ) {
4560 return;
4561 }
4562
4563 that.containerElement = $( ce );
4564
4565 if ( /document/.test( oc ) || oc === document ) {
4566 that.containerOffset = {
4567 left: 0,
4568 top: 0
4569 };
4570 that.containerPosition = {
4571 left: 0,
4572 top: 0
4573 };
4574
4575 that.parentData = {
4576 element: $( document ),
4577 left: 0,
4578 top: 0,
4579 width: $( document ).width(),
4580 height: $( document ).height() || document.body.parentNode.scrollHeight
4581 };
4582 } else {
4583 element = $( ce );
4584 p = [];
4585 $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
4586 p[ i ] = that._num( element.css( "padding" + name ) );
4587 } );
4588
4589 that.containerOffset = element.offset();
4590 that.containerPosition = element.position();
4591 that.containerSize = {
4592 height: ( element.innerHeight() - p[ 3 ] ),
4593 width: ( element.innerWidth() - p[ 1 ] )
4594 };
4595
4596 co = that.containerOffset;
4597 ch = that.containerSize.height;
4598 cw = that.containerSize.width;
4599 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
4600 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
4601
4602 that.parentData = {
4603 element: ce,
4604 left: co.left,
4605 top: co.top,
4606 width: width,
4607 height: height
4608 };
4609 }
4610 },
4611
4612 resize: function( event ) {
4613 var woset, hoset, isParent, isOffsetRelative,
4614 that = $( this ).resizable( "instance" ),
4615 o = that.options,
4616 co = that.containerOffset,
4617 cp = that.position,
4618 pRatio = that._aspectRatio || event.shiftKey,
4619 cop = {
4620 top: 0,
4621 left: 0
4622 },
4623 ce = that.containerElement,
4624 continueResize = true;
4625
4626 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
4627 cop = co;
4628 }
4629
4630 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
4631 that.size.width = that.size.width +
4632 ( that._helper ?
4633 ( that.position.left - co.left ) :
4634 ( that.position.left - cop.left ) );
4635
4636 if ( pRatio ) {
4637 that.size.height = that.size.width / that.aspectRatio;
4638 continueResize = false;
4639 }
4640 that.position.left = o.helper ? co.left : 0;
4641 }
4642
4643 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
4644 that.size.height = that.size.height +
4645 ( that._helper ?
4646 ( that.position.top - co.top ) :
4647 that.position.top );
4648
4649 if ( pRatio ) {
4650 that.size.width = that.size.height * that.aspectRatio;
4651 continueResize = false;
4652 }
4653 that.position.top = that._helper ? co.top : 0;
4654 }
4655
4656 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
4657 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
4658
4659 if ( isParent && isOffsetRelative ) {
4660 that.offset.left = that.parentData.left + that.position.left;
4661 that.offset.top = that.parentData.top + that.position.top;
4662 } else {
4663 that.offset.left = that.element.offset().left;
4664 that.offset.top = that.element.offset().top;
4665 }
4666
4667 woset = Math.abs( that.sizeDiff.width +
4668 ( that._helper ?
4669 that.offset.left - cop.left :
4670 ( that.offset.left - co.left ) ) );
4671
4672 hoset = Math.abs( that.sizeDiff.height +
4673 ( that._helper ?
4674 that.offset.top - cop.top :
4675 ( that.offset.top - co.top ) ) );
4676
4677 if ( woset + that.size.width >= that.parentData.width ) {
4678 that.size.width = that.parentData.width - woset;
4679 if ( pRatio ) {
4680 that.size.height = that.size.width / that.aspectRatio;
4681 continueResize = false;
4682 }
4683 }
4684
4685 if ( hoset + that.size.height >= that.parentData.height ) {
4686 that.size.height = that.parentData.height - hoset;
4687 if ( pRatio ) {
4688 that.size.width = that.size.height * that.aspectRatio;
4689 continueResize = false;
4690 }
4691 }
4692
4693 if ( !continueResize ) {
4694 that.position.left = that.prevPosition.left;
4695 that.position.top = that.prevPosition.top;
4696 that.size.width = that.prevSize.width;
4697 that.size.height = that.prevSize.height;
4698 }
4699 },
4700
4701 stop: function() {
4702 var that = $( this ).resizable( "instance" ),
4703 o = that.options,
4704 co = that.containerOffset,
4705 cop = that.containerPosition,
4706 ce = that.containerElement,
4707 helper = $( that.helper ),
4708 ho = helper.offset(),
4709 w = helper.outerWidth() - that.sizeDiff.width,
4710 h = helper.outerHeight() - that.sizeDiff.height;
4711
4712 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
4713 $( this ).css( {
4714 left: ho.left - cop.left - co.left,
4715 width: w,
4716 height: h
4717 } );
4718 }
4719
4720 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
4721 $( this ).css( {
4722 left: ho.left - cop.left - co.left,
4723 width: w,
4724 height: h
4725 } );
4726 }
4727 }
4728 } );
4729
4730 $.ui.plugin.add( "resizable", "alsoResize", {
4731
4732 start: function() {
4733 var that = $( this ).resizable( "instance" ),
4734 o = that.options;
4735
4736 $( o.alsoResize ).each( function() {
4737 var el = $( this );
4738 el.data( "ui-resizable-alsoresize", {
4739 width: parseFloat( el.width() ), height: parseFloat( el.height() ),
4740 left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
4741 } );
4742 } );
4743 },
4744
4745 resize: function( event, ui ) {
4746 var that = $( this ).resizable( "instance" ),
4747 o = that.options,
4748 os = that.originalSize,
4749 op = that.originalPosition,
4750 delta = {
4751 height: ( that.size.height - os.height ) || 0,
4752 width: ( that.size.width - os.width ) || 0,
4753 top: ( that.position.top - op.top ) || 0,
4754 left: ( that.position.left - op.left ) || 0
4755 };
4756
4757 $( o.alsoResize ).each( function() {
4758 var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
4759 css = el.parents( ui.originalElement[ 0 ] ).length ?
4760 [ "width", "height" ] :
4761 [ "width", "height", "top", "left" ];
4762
4763 $.each( css, function( i, prop ) {
4764 var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
4765 if ( sum && sum >= 0 ) {
4766 style[ prop ] = sum || null;
4767 }
4768 } );
4769
4770 el.css( style );
4771 } );
4772 },
4773
4774 stop: function() {
4775 $( this ).removeData( "ui-resizable-alsoresize" );
4776 }
4777 } );
4778
4779 $.ui.plugin.add( "resizable", "ghost", {
4780
4781 start: function() {
4782
4783 var that = $( this ).resizable( "instance" ), cs = that.size;
4784
4785 that.ghost = that.originalElement.clone();
4786 that.ghost.css( {
4787 opacity: 0.25,
4788 display: "block",
4789 position: "relative",
4790 height: cs.height,
4791 width: cs.width,
4792 margin: 0,
4793 left: 0,
4794 top: 0
4795 } );
4796
4797 that._addClass( that.ghost, "ui-resizable-ghost" );
4798
4799 // DEPRECATED
4800 // TODO: remove after 1.12
4801 if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
4802
4803 // Ghost option
4804 that.ghost.addClass( this.options.ghost );
4805 }
4806
4807 that.ghost.appendTo( that.helper );
4808
4809 },
4810
4811 resize: function() {
4812 var that = $( this ).resizable( "instance" );
4813 if ( that.ghost ) {
4814 that.ghost.css( {
4815 position: "relative",
4816 height: that.size.height,
4817 width: that.size.width
4818 } );
4819 }
4820 },
4821
4822 stop: function() {
4823 var that = $( this ).resizable( "instance" );
4824 if ( that.ghost && that.helper ) {
4825 that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
4826 }
4827 }
4828
4829 } );
4830
4831 $.ui.plugin.add( "resizable", "grid", {
4832
4833 resize: function() {
4834 var outerDimensions,
4835 that = $( this ).resizable( "instance" ),
4836 o = that.options,
4837 cs = that.size,
4838 os = that.originalSize,
4839 op = that.originalPosition,
4840 a = that.axis,
4841 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
4842 gridX = ( grid[ 0 ] || 1 ),
4843 gridY = ( grid[ 1 ] || 1 ),
4844 ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
4845 oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
4846 newWidth = os.width + ox,
4847 newHeight = os.height + oy,
4848 isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
4849 isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
4850 isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
4851 isMinHeight = o.minHeight && ( o.minHeight > newHeight );
4852
4853 o.grid = grid;
4854
4855 if ( isMinWidth ) {
4856 newWidth += gridX;
4857 }
4858 if ( isMinHeight ) {
4859 newHeight += gridY;
4860 }
4861 if ( isMaxWidth ) {
4862 newWidth -= gridX;
4863 }
4864 if ( isMaxHeight ) {
4865 newHeight -= gridY;
4866 }
4867
4868 if ( /^(se|s|e)$/.test( a ) ) {
4869 that.size.width = newWidth;
4870 that.size.height = newHeight;
4871 } else if ( /^(ne)$/.test( a ) ) {
4872 that.size.width = newWidth;
4873 that.size.height = newHeight;
4874 that.position.top = op.top - oy;
4875 } else if ( /^(sw)$/.test( a ) ) {
4876 that.size.width = newWidth;
4877 that.size.height = newHeight;
4878 that.position.left = op.left - ox;
4879 } else {
4880 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
4881 outerDimensions = that._getPaddingPlusBorderDimensions( this );
4882 }
4883
4884 if ( newHeight - gridY > 0 ) {
4885 that.size.height = newHeight;
4886 that.position.top = op.top - oy;
4887 } else {
4888 newHeight = gridY - outerDimensions.height;
4889 that.size.height = newHeight;
4890 that.position.top = op.top + os.height - newHeight;
4891 }
4892 if ( newWidth - gridX > 0 ) {
4893 that.size.width = newWidth;
4894 that.position.left = op.left - ox;
4895 } else {
4896 newWidth = gridX - outerDimensions.width;
4897 that.size.width = newWidth;
4898 that.position.left = op.left + os.width - newWidth;
4899 }
4900 }
4901 }
4902
4903 } );
4904
4905 var widgetsResizable = $.ui.resizable;
4906
4907
4908 /*!
4909 * jQuery UI Selectable 1.12.1
4910 * http://jqueryui.com
4911 *
4912 * Copyright jQuery Foundation and other contributors
4913 * Released under the MIT license.
4914 * http://jquery.org/license
4915 */
4916
4917 //>>label: Selectable
4918 //>>group: Interactions
4919 //>>description: Allows groups of elements to be selected with the mouse.
4920 //>>docs: http://api.jqueryui.com/selectable/
4921 //>>demos: http://jqueryui.com/selectable/
4922 //>>css.structure: ../../themes/base/selectable.css
4923
4924
4925
4926 var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
4927 version: "1.12.1",
4928 options: {
4929 appendTo: "body",
4930 autoRefresh: true,
4931 distance: 0,
4932 filter: "*",
4933 tolerance: "touch",
4934
4935 // Callbacks
4936 selected: null,
4937 selecting: null,
4938 start: null,
4939 stop: null,
4940 unselected: null,
4941 unselecting: null
4942 },
4943 _create: function() {
4944 var that = this;
4945
4946 this._addClass( "ui-selectable" );
4947
4948 this.dragged = false;
4949
4950 // Cache selectee children based on filter
4951 this.refresh = function() {
4952 that.elementPos = $( that.element[ 0 ] ).offset();
4953 that.selectees = $( that.options.filter, that.element[ 0 ] );
4954 that._addClass( that.selectees, "ui-selectee" );
4955 that.selectees.each( function() {
4956 var $this = $( this ),
4957 selecteeOffset = $this.offset(),
4958 pos = {
4959 left: selecteeOffset.left - that.elementPos.left,
4960 top: selecteeOffset.top - that.elementPos.top
4961 };
4962 $.data( this, "selectable-item", {
4963 element: this,
4964 $element: $this,
4965 left: pos.left,
4966 top: pos.top,
4967 right: pos.left + $this.outerWidth(),
4968 bottom: pos.top + $this.outerHeight(),
4969 startselected: false,
4970 selected: $this.hasClass( "ui-selected" ),
4971 selecting: $this.hasClass( "ui-selecting" ),
4972 unselecting: $this.hasClass( "ui-unselecting" )
4973 } );
4974 } );
4975 };
4976 this.refresh();
4977
4978 this._mouseInit();
4979
4980 this.helper = $( "<div>" );
4981 this._addClass( this.helper, "ui-selectable-helper" );
4982 },
4983
4984 _destroy: function() {
4985 this.selectees.removeData( "selectable-item" );
4986 this._mouseDestroy();
4987 },
4988
4989 _mouseStart: function( event ) {
4990 var that = this,
4991 options = this.options;
4992
4993 this.opos = [ event.pageX, event.pageY ];
4994 this.elementPos = $( this.element[ 0 ] ).offset();
4995
4996 if ( this.options.disabled ) {
4997 return;
4998 }
4999
5000 this.selectees = $( options.filter, this.element[ 0 ] );
5001
5002 this._trigger( "start", event );
5003
5004 $( options.appendTo ).append( this.helper );
5005
5006 // position helper (lasso)
5007 this.helper.css( {
5008 "left": event.pageX,
5009 "top": event.pageY,
5010 "width": 0,
5011 "height": 0
5012 } );
5013
5014 if ( options.autoRefresh ) {
5015 this.refresh();
5016 }
5017
5018 this.selectees.filter( ".ui-selected" ).each( function() {
5019 var selectee = $.data( this, "selectable-item" );
5020 selectee.startselected = true;
5021 if ( !event.metaKey && !event.ctrlKey ) {
5022 that._removeClass( selectee.$element, "ui-selected" );
5023 selectee.selected = false;
5024 that._addClass( selectee.$element, "ui-unselecting" );
5025 selectee.unselecting = true;
5026
5027 // selectable UNSELECTING callback
5028 that._trigger( "unselecting", event, {
5029 unselecting: selectee.element
5030 } );
5031 }
5032 } );
5033
5034 $( event.target ).parents().addBack().each( function() {
5035 var doSelect,
5036 selectee = $.data( this, "selectable-item" );
5037 if ( selectee ) {
5038 doSelect = ( !event.metaKey && !event.ctrlKey ) ||
5039 !selectee.$element.hasClass( "ui-selected" );
5040 that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
5041 ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
5042 selectee.unselecting = !doSelect;
5043 selectee.selecting = doSelect;
5044 selectee.selected = doSelect;
5045
5046 // selectable (UN)SELECTING callback
5047 if ( doSelect ) {
5048 that._trigger( "selecting", event, {
5049 selecting: selectee.element
5050 } );
5051 } else {
5052 that._trigger( "unselecting", event, {
5053 unselecting: selectee.element
5054 } );
5055 }
5056 return false;
5057 }
5058 } );
5059
5060 },
5061
5062 _mouseDrag: function( event ) {
5063
5064 this.dragged = true;
5065
5066 if ( this.options.disabled ) {
5067 return;
5068 }
5069
5070 var tmp,
5071 that = this,
5072 options = this.options,
5073 x1 = this.opos[ 0 ],
5074 y1 = this.opos[ 1 ],
5075 x2 = event.pageX,
5076 y2 = event.pageY;
5077
5078 if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; }
5079 if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; }
5080 this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
5081
5082 this.selectees.each( function() {
5083 var selectee = $.data( this, "selectable-item" ),
5084 hit = false,
5085 offset = {};
5086
5087 //prevent helper from being selected if appendTo: selectable
5088 if ( !selectee || selectee.element === that.element[ 0 ] ) {
5089 return;
5090 }
5091
5092 offset.left = selectee.left + that.elementPos.left;
5093 offset.right = selectee.right + that.elementPos.left;
5094 offset.top = selectee.top + that.elementPos.top;
5095 offset.bottom = selectee.bottom + that.elementPos.top;
5096
5097 if ( options.tolerance === "touch" ) {
5098 hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
5099 offset.bottom < y1 ) );
5100 } else if ( options.tolerance === "fit" ) {
5101 hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
5102 offset.bottom < y2 );
5103 }
5104
5105 if ( hit ) {
5106
5107 // SELECT
5108 if ( selectee.selected ) {
5109 that._removeClass( selectee.$element, "ui-selected" );
5110 selectee.selected = false;
5111 }
5112 if ( selectee.unselecting ) {
5113 that._removeClass( selectee.$element, "ui-unselecting" );
5114 selectee.unselecting = false;
5115 }
5116 if ( !selectee.selecting ) {
5117 that._addClass( selectee.$element, "ui-selecting" );
5118 selectee.selecting = true;
5119
5120 // selectable SELECTING callback
5121 that._trigger( "selecting", event, {
5122 selecting: selectee.element
5123 } );
5124 }
5125 } else {
5126
5127 // UNSELECT
5128 if ( selectee.selecting ) {
5129 if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
5130 that._removeClass( selectee.$element, "ui-selecting" );
5131 selectee.selecting = false;
5132 that._addClass( selectee.$element, "ui-selected" );
5133 selectee.selected = true;
5134 } else {
5135 that._removeClass( selectee.$element, "ui-selecting" );
5136 selectee.selecting = false;
5137 if ( selectee.startselected ) {
5138 that._addClass( selectee.$element, "ui-unselecting" );
5139 selectee.unselecting = true;
5140 }
5141
5142 // selectable UNSELECTING callback
5143 that._trigger( "unselecting", event, {
5144 unselecting: selectee.element
5145 } );
5146 }
5147 }
5148 if ( selectee.selected ) {
5149 if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
5150 that._removeClass( selectee.$element, "ui-selected" );
5151 selectee.selected = false;
5152
5153 that._addClass( selectee.$element, "ui-unselecting" );
5154 selectee.unselecting = true;
5155
5156 // selectable UNSELECTING callback
5157 that._trigger( "unselecting", event, {
5158 unselecting: selectee.element
5159 } );
5160 }
5161 }
5162 }
5163 } );
5164
5165 return false;
5166 },
5167
5168 _mouseStop: function( event ) {
5169 var that = this;
5170
5171 this.dragged = false;
5172
5173 $( ".ui-unselecting", this.element[ 0 ] ).each( function() {
5174 var selectee = $.data( this, "selectable-item" );
5175 that._removeClass( selectee.$element, "ui-unselecting" );
5176 selectee.unselecting = false;
5177 selectee.startselected = false;
5178 that._trigger( "unselected", event, {
5179 unselected: selectee.element
5180 } );
5181 } );
5182 $( ".ui-selecting", this.element[ 0 ] ).each( function() {
5183 var selectee = $.data( this, "selectable-item" );
5184 that._removeClass( selectee.$element, "ui-selecting" )
5185 ._addClass( selectee.$element, "ui-selected" );
5186 selectee.selecting = false;
5187 selectee.selected = true;
5188 selectee.startselected = true;
5189 that._trigger( "selected", event, {
5190 selected: selectee.element
5191 } );
5192 } );
5193 this._trigger( "stop", event );
5194
5195 this.helper.remove();
5196
5197 return false;
5198 }
5199
5200 } );
5201
5202
5203 /*!
5204 * jQuery UI Sortable 1.12.1
5205 * http://jqueryui.com
5206 *
5207 * Copyright jQuery Foundation and other contributors
5208 * Released under the MIT license.
5209 * http://jquery.org/license
5210 */
5211
5212 //>>label: Sortable
5213 //>>group: Interactions
5214 //>>description: Enables items in a list to be sorted using the mouse.
5215 //>>docs: http://api.jqueryui.com/sortable/
5216 //>>demos: http://jqueryui.com/sortable/
5217 //>>css.structure: ../../themes/base/sortable.css
5218
5219
5220
5221 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
5222 version: "1.12.1",
5223 widgetEventPrefix: "sort",
5224 ready: false,
5225 options: {
5226 appendTo: "parent",
5227 axis: false,
5228 connectWith: false,
5229 containment: false,
5230 cursor: "auto",
5231 cursorAt: false,
5232 dropOnEmpty: true,
5233 forcePlaceholderSize: false,
5234 forceHelperSize: false,
5235 grid: false,
5236 handle: false,
5237 helper: "original",
5238 items: "> *",
5239 opacity: false,
5240 placeholder: false,
5241 revert: false,
5242 scroll: true,
5243 scrollSensitivity: 20,
5244 scrollSpeed: 20,
5245 scope: "default",
5246 tolerance: "intersect",
5247 zIndex: 1000,
5248
5249 // Callbacks
5250 activate: null,
5251 beforeStop: null,
5252 change: null,
5253 deactivate: null,
5254 out: null,
5255 over: null,
5256 receive: null,
5257 remove: null,
5258 sort: null,
5259 start: null,
5260 stop: null,
5261 update: null
5262 },
5263
5264 _isOverAxis: function( x, reference, size ) {
5265 return ( x >= reference ) && ( x < ( reference + size ) );
5266 },
5267
5268 _isFloating: function( item ) {
5269 return ( /left|right/ ).test( item.css( "float" ) ) ||
5270 ( /inline|table-cell/ ).test( item.css( "display" ) );
5271 },
5272
5273 _create: function() {
5274 this.containerCache = {};
5275 this._addClass( "ui-sortable" );
5276
5277 //Get the items
5278 this.refresh();
5279
5280 //Let's determine the parent's offset
5281 this.offset = this.element.offset();
5282
5283 //Initialize mouse events for interaction
5284 this._mouseInit();
5285
5286 this._setHandleClassName();
5287
5288 //We're ready to go
5289 this.ready = true;
5290
5291 },
5292
5293 _setOption: function( key, value ) {
5294 this._super( key, value );
5295
5296 if ( key === "handle" ) {
5297 this._setHandleClassName();
5298 }
5299 },
5300
5301 _setHandleClassName: function() {
5302 var that = this;
5303 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
5304 $.each( this.items, function() {
5305 that._addClass(
5306 this.instance.options.handle ?
5307 this.item.find( this.instance.options.handle ) :
5308 this.item,
5309 "ui-sortable-handle"
5310 );
5311 } );
5312 },
5313
5314 _destroy: function() {
5315 this._mouseDestroy();
5316
5317 for ( var i = this.items.length - 1; i >= 0; i-- ) {
5318 this.items[ i ].item.removeData( this.widgetName + "-item" );
5319 }
5320
5321 return this;
5322 },
5323
5324 _mouseCapture: function( event, overrideHandle ) {
5325 var currentItem = null,
5326 validHandle = false,
5327 that = this;
5328
5329 if ( this.reverting ) {
5330 return false;
5331 }
5332
5333 if ( this.options.disabled || this.options.type === "static" ) {
5334 return false;
5335 }
5336
5337 //We have to refresh the items data once first
5338 this._refreshItems( event );
5339
5340 //Find out if the clicked node (or one of its parents) is a actual item in this.items
5341 $( event.target ).parents().each( function() {
5342 if ( $.data( this, that.widgetName + "-item" ) === that ) {
5343 currentItem = $( this );
5344 return false;
5345 }
5346 } );
5347 if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
5348 currentItem = $( event.target );
5349 }
5350
5351 if ( !currentItem ) {
5352 return false;
5353 }
5354 if ( this.options.handle && !overrideHandle ) {
5355 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
5356 if ( this === event.target ) {
5357 validHandle = true;
5358 }
5359 } );
5360 if ( !validHandle ) {
5361 return false;
5362 }
5363 }
5364
5365 this.currentItem = currentItem;
5366 this._removeCurrentsFromItems();
5367 return true;
5368
5369 },
5370
5371 _mouseStart: function( event, overrideHandle, noActivation ) {
5372
5373 var i, body,
5374 o = this.options;
5375
5376 this.currentContainer = this;
5377
5378 //We only need to call refreshPositions, because the refreshItems call has been moved to
5379 // mouseCapture
5380 this.refreshPositions();
5381
5382 //Create and append the visible helper
5383 this.helper = this._createHelper( event );
5384
5385 //Cache the helper size
5386 this._cacheHelperProportions();
5387
5388 /*
5389 * - Position generation -
5390 * This block generates everything position related - it's the core of draggables.
5391 */
5392
5393 //Cache the margins of the original element
5394 this._cacheMargins();
5395
5396 //Get the next scrolling parent
5397 this.scrollParent = this.helper.scrollParent();
5398
5399 //The element's absolute position on the page minus margins
5400 this.offset = this.currentItem.offset();
5401 this.offset = {
5402 top: this.offset.top - this.margins.top,
5403 left: this.offset.left - this.margins.left
5404 };
5405
5406 $.extend( this.offset, {
5407 click: { //Where the click happened, relative to the element
5408 left: event.pageX - this.offset.left,
5409 top: event.pageY - this.offset.top
5410 },
5411 parent: this._getParentOffset(),
5412
5413 // This is a relative to absolute position minus the actual position calculation -
5414 // only used for relative positioned helper
5415 relative: this._getRelativeOffset()
5416 } );
5417
5418 // Only after we got the offset, we can change the helper's position to absolute
5419 // TODO: Still need to figure out a way to make relative sorting possible
5420 this.helper.css( "position", "absolute" );
5421 this.cssPosition = this.helper.css( "position" );
5422
5423 //Generate the original position
5424 this.originalPosition = this._generatePosition( event );
5425 this.originalPageX = event.pageX;
5426 this.originalPageY = event.pageY;
5427
5428 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
5429 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
5430
5431 //Cache the former DOM position
5432 this.domPosition = {
5433 prev: this.currentItem.prev()[ 0 ],
5434 parent: this.currentItem.parent()[ 0 ]
5435 };
5436
5437 // If the helper is not the original, hide the original so it's not playing any role during
5438 // the drag, won't cause anything bad this way
5439 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
5440 this.currentItem.hide();
5441 }
5442
5443 //Create the placeholder
5444 this._createPlaceholder();
5445
5446 //Set a containment if given in the options
5447 if ( o.containment ) {
5448 this._setContainment();
5449 }
5450
5451 if ( o.cursor && o.cursor !== "auto" ) { // cursor option
5452 body = this.document.find( "body" );
5453
5454 // Support: IE
5455 this.storedCursor = body.css( "cursor" );
5456 body.css( "cursor", o.cursor );
5457
5458 this.storedStylesheet =
5459 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
5460 }
5461
5462 if ( o.opacity ) { // opacity option
5463 if ( this.helper.css( "opacity" ) ) {
5464 this._storedOpacity = this.helper.css( "opacity" );
5465 }
5466 this.helper.css( "opacity", o.opacity );
5467 }
5468
5469 if ( o.zIndex ) { // zIndex option
5470 if ( this.helper.css( "zIndex" ) ) {
5471 this._storedZIndex = this.helper.css( "zIndex" );
5472 }
5473 this.helper.css( "zIndex", o.zIndex );
5474 }
5475
5476 //Prepare scrolling
5477 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
5478 this.scrollParent[ 0 ].tagName !== "HTML" ) {
5479 this.overflowOffset = this.scrollParent.offset();
5480 }
5481
5482 //Call callbacks
5483 this._trigger( "start", event, this._uiHash() );
5484
5485 //Recache the helper size
5486 if ( !this._preserveHelperProportions ) {
5487 this._cacheHelperProportions();
5488 }
5489
5490 //Post "activate" events to possible containers
5491 if ( !noActivation ) {
5492 for ( i = this.containers.length - 1; i >= 0; i-- ) {
5493 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
5494 }
5495 }
5496
5497 //Prepare possible droppables
5498 if ( $.ui.ddmanager ) {
5499 $.ui.ddmanager.current = this;
5500 }
5501
5502 if ( $.ui.ddmanager && !o.dropBehaviour ) {
5503 $.ui.ddmanager.prepareOffsets( this, event );
5504 }
5505
5506 this.dragging = true;
5507
5508 this._addClass( this.helper, "ui-sortable-helper" );
5509
5510 // Execute the drag once - this causes the helper not to be visiblebefore getting its
5511 // correct position
5512 this._mouseDrag( event );
5513 return true;
5514
5515 },
5516
5517 _mouseDrag: function( event ) {
5518 var i, item, itemElement, intersection,
5519 o = this.options,
5520 scrolled = false;
5521
5522 //Compute the helpers position
5523 this.position = this._generatePosition( event );
5524 this.positionAbs = this._convertPositionTo( "absolute" );
5525
5526 if ( !this.lastPositionAbs ) {
5527 this.lastPositionAbs = this.positionAbs;
5528 }
5529
5530 //Do scrolling
5531 if ( this.options.scroll ) {
5532 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
5533 this.scrollParent[ 0 ].tagName !== "HTML" ) {
5534
5535 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
5536 event.pageY < o.scrollSensitivity ) {
5537 this.scrollParent[ 0 ].scrollTop =
5538 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
5539 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
5540 this.scrollParent[ 0 ].scrollTop =
5541 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
5542 }
5543
5544 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
5545 event.pageX < o.scrollSensitivity ) {
5546 this.scrollParent[ 0 ].scrollLeft = scrolled =
5547 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
5548 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
5549 this.scrollParent[ 0 ].scrollLeft = scrolled =
5550 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
5551 }
5552
5553 } else {
5554
5555 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
5556 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
5557 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
5558 o.scrollSensitivity ) {
5559 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
5560 }
5561
5562 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
5563 scrolled = this.document.scrollLeft(
5564 this.document.scrollLeft() - o.scrollSpeed
5565 );
5566 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
5567 o.scrollSensitivity ) {
5568 scrolled = this.document.scrollLeft(
5569 this.document.scrollLeft() + o.scrollSpeed
5570 );
5571 }
5572
5573 }
5574
5575 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
5576 $.ui.ddmanager.prepareOffsets( this, event );
5577 }
5578 }
5579
5580 //Regenerate the absolute position used for position checks
5581 this.positionAbs = this._convertPositionTo( "absolute" );
5582
5583 //Set the helper position
5584 if ( !this.options.axis || this.options.axis !== "y" ) {
5585 this.helper[ 0 ].style.left = this.position.left + "px";
5586 }
5587 if ( !this.options.axis || this.options.axis !== "x" ) {
5588 this.helper[ 0 ].style.top = this.position.top + "px";
5589 }
5590
5591 //Rearrange
5592 for ( i = this.items.length - 1; i >= 0; i-- ) {
5593
5594 //Cache variables and intersection, continue if no intersection
5595 item = this.items[ i ];
5596 itemElement = item.item[ 0 ];
5597 intersection = this._intersectsWithPointer( item );
5598 if ( !intersection ) {
5599 continue;
5600 }
5601
5602 // Only put the placeholder inside the current Container, skip all
5603 // items from other containers. This works because when moving
5604 // an item from one container to another the
5605 // currentContainer is switched before the placeholder is moved.
5606 //
5607 // Without this, moving items in "sub-sortables" can cause
5608 // the placeholder to jitter between the outer and inner container.
5609 if ( item.instance !== this.currentContainer ) {
5610 continue;
5611 }
5612
5613 // Cannot intersect with itself
5614 // no useless actions that have been done before
5615 // no action if the item moved is the parent of the item checked
5616 if ( itemElement !== this.currentItem[ 0 ] &&
5617 this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
5618 !$.contains( this.placeholder[ 0 ], itemElement ) &&
5619 ( this.options.type === "semi-dynamic" ?
5620 !$.contains( this.element[ 0 ], itemElement ) :
5621 true
5622 )
5623 ) {
5624
5625 this.direction = intersection === 1 ? "down" : "up";
5626
5627 if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
5628 this._rearrange( event, item );
5629 } else {
5630 break;
5631 }
5632
5633 this._trigger( "change", event, this._uiHash() );
5634 break;
5635 }
5636 }
5637
5638 //Post events to containers
5639 this._contactContainers( event );
5640
5641 //Interconnect with droppables
5642 if ( $.ui.ddmanager ) {
5643 $.ui.ddmanager.drag( this, event );
5644 }
5645
5646 //Call callbacks
5647 this._trigger( "sort", event, this._uiHash() );
5648
5649 this.lastPositionAbs = this.positionAbs;
5650 return false;
5651
5652 },
5653
5654 _mouseStop: function( event, noPropagation ) {
5655
5656 if ( !event ) {
5657 return;
5658 }
5659
5660 //If we are using droppables, inform the manager about the drop
5661 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
5662 $.ui.ddmanager.drop( this, event );
5663 }
5664
5665 if ( this.options.revert ) {
5666 var that = this,
5667 cur = this.placeholder.offset(),
5668 axis = this.options.axis,
5669 animation = {};
5670
5671 if ( !axis || axis === "x" ) {
5672 animation.left = cur.left - this.offset.parent.left - this.margins.left +
5673 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
5674 0 :
5675 this.offsetParent[ 0 ].scrollLeft
5676 );
5677 }
5678 if ( !axis || axis === "y" ) {
5679 animation.top = cur.top - this.offset.parent.top - this.margins.top +
5680 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
5681 0 :
5682 this.offsetParent[ 0 ].scrollTop
5683 );
5684 }
5685 this.reverting = true;
5686 $( this.helper ).animate(
5687 animation,
5688 parseInt( this.options.revert, 10 ) || 500,
5689 function() {
5690 that._clear( event );
5691 }
5692 );
5693 } else {
5694 this._clear( event, noPropagation );
5695 }
5696
5697 return false;
5698
5699 },
5700
5701 cancel: function() {
5702
5703 if ( this.dragging ) {
5704
5705 this._mouseUp( new $.Event( "mouseup", { target: null } ) );
5706
5707 if ( this.options.helper === "original" ) {
5708 this.currentItem.css( this._storedCSS );
5709 this._removeClass( this.currentItem, "ui-sortable-helper" );
5710 } else {
5711 this.currentItem.show();
5712 }
5713
5714 //Post deactivating events to containers
5715 for ( var i = this.containers.length - 1; i >= 0; i-- ) {
5716 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
5717 if ( this.containers[ i ].containerCache.over ) {
5718 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
5719 this.containers[ i ].containerCache.over = 0;
5720 }
5721 }
5722
5723 }
5724
5725 if ( this.placeholder ) {
5726
5727 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
5728 // it unbinds ALL events from the original node!
5729 if ( this.placeholder[ 0 ].parentNode ) {
5730 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
5731 }
5732 if ( this.options.helper !== "original" && this.helper &&
5733 this.helper[ 0 ].parentNode ) {
5734 this.helper.remove();
5735 }
5736
5737 $.extend( this, {
5738 helper: null,
5739 dragging: false,
5740 reverting: false,
5741 _noFinalSort: null
5742 } );
5743
5744 if ( this.domPosition.prev ) {
5745 $( this.domPosition.prev ).after( this.currentItem );
5746 } else {
5747 $( this.domPosition.parent ).prepend( this.currentItem );
5748 }
5749 }
5750
5751 return this;
5752
5753 },
5754
5755 serialize: function( o ) {
5756
5757 var items = this._getItemsAsjQuery( o && o.connected ),
5758 str = [];
5759 o = o || {};
5760
5761 $( items ).each( function() {
5762 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
5763 .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
5764 if ( res ) {
5765 str.push(
5766 ( o.key || res[ 1 ] + "[]" ) +
5767 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
5768 }
5769 } );
5770
5771 if ( !str.length && o.key ) {
5772 str.push( o.key + "=" );
5773 }
5774
5775 return str.join( "&" );
5776
5777 },
5778
5779 toArray: function( o ) {
5780
5781 var items = this._getItemsAsjQuery( o && o.connected ),
5782 ret = [];
5783
5784 o = o || {};
5785
5786 items.each( function() {
5787 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
5788 } );
5789 return ret;
5790
5791 },
5792
5793 /* Be careful with the following core functions */
5794 _intersectsWith: function( item ) {
5795
5796 var x1 = this.positionAbs.left,
5797 x2 = x1 + this.helperProportions.width,
5798 y1 = this.positionAbs.top,
5799 y2 = y1 + this.helperProportions.height,
5800 l = item.left,
5801 r = l + item.width,
5802 t = item.top,
5803 b = t + item.height,
5804 dyClick = this.offset.click.top,
5805 dxClick = this.offset.click.left,
5806 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
5807 ( y1 + dyClick ) < b ),
5808 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
5809 ( x1 + dxClick ) < r ),
5810 isOverElement = isOverElementHeight && isOverElementWidth;
5811
5812 if ( this.options.tolerance === "pointer" ||
5813 this.options.forcePointerForContainers ||
5814 ( this.options.tolerance !== "pointer" &&
5815 this.helperProportions[ this.floating ? "width" : "height" ] >
5816 item[ this.floating ? "width" : "height" ] )
5817 ) {
5818 return isOverElement;
5819 } else {
5820
5821 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
5822 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
5823 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
5824 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
5825
5826 }
5827 },
5828
5829 _intersectsWithPointer: function( item ) {
5830 var verticalDirection, horizontalDirection,
5831 isOverElementHeight = ( this.options.axis === "x" ) ||
5832 this._isOverAxis(
5833 this.positionAbs.top + this.offset.click.top, item.top, item.height ),
5834 isOverElementWidth = ( this.options.axis === "y" ) ||
5835 this._isOverAxis(
5836 this.positionAbs.left + this.offset.click.left, item.left, item.width ),
5837 isOverElement = isOverElementHeight && isOverElementWidth;
5838
5839 if ( !isOverElement ) {
5840 return false;
5841 }
5842
5843 verticalDirection = this._getDragVerticalDirection();
5844 horizontalDirection = this._getDragHorizontalDirection();
5845
5846 return this.floating ?
5847 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
5848 : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
5849
5850 },
5851
5852 _intersectsWithSides: function( item ) {
5853
5854 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
5855 this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
5856 isOverRightHalf = this._isOverAxis( this.positionAbs.left +
5857 this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
5858 verticalDirection = this._getDragVerticalDirection(),
5859 horizontalDirection = this._getDragHorizontalDirection();
5860
5861 if ( this.floating && horizontalDirection ) {
5862 return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
5863 ( horizontalDirection === "left" && !isOverRightHalf ) );
5864 } else {
5865 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
5866 ( verticalDirection === "up" && !isOverBottomHalf ) );
5867 }
5868
5869 },
5870
5871 _getDragVerticalDirection: function() {
5872 var delta = this.positionAbs.top - this.lastPositionAbs.top;
5873 return delta !== 0 && ( delta > 0 ? "down" : "up" );
5874 },
5875
5876 _getDragHorizontalDirection: function() {
5877 var delta = this.positionAbs.left - this.lastPositionAbs.left;
5878 return delta !== 0 && ( delta > 0 ? "right" : "left" );
5879 },
5880
5881 refresh: function( event ) {
5882 this._refreshItems( event );
5883 this._setHandleClassName();
5884 this.refreshPositions();
5885 return this;
5886 },
5887
5888 _connectWith: function() {
5889 var options = this.options;
5890 return options.connectWith.constructor === String ?
5891 [ options.connectWith ] :
5892 options.connectWith;
5893 },
5894
5895 _getItemsAsjQuery: function( connected ) {
5896
5897 var i, j, cur, inst,
5898 items = [],
5899 queries = [],
5900 connectWith = this._connectWith();
5901
5902 if ( connectWith && connected ) {
5903 for ( i = connectWith.length - 1; i >= 0; i-- ) {
5904 cur = $( connectWith[ i ], this.document[ 0 ] );
5905 for ( j = cur.length - 1; j >= 0; j-- ) {
5906 inst = $.data( cur[ j ], this.widgetFullName );
5907 if ( inst && inst !== this && !inst.options.disabled ) {
5908 queries.push( [ $.isFunction( inst.options.items ) ?
5909 inst.options.items.call( inst.element ) :
5910 $( inst.options.items, inst.element )
5911 .not( ".ui-sortable-helper" )
5912 .not( ".ui-sortable-placeholder" ), inst ] );
5913 }
5914 }
5915 }
5916 }
5917
5918 queries.push( [ $.isFunction( this.options.items ) ?
5919 this.options.items
5920 .call( this.element, null, { options: this.options, item: this.currentItem } ) :
5921 $( this.options.items, this.element )
5922 .not( ".ui-sortable-helper" )
5923 .not( ".ui-sortable-placeholder" ), this ] );
5924
5925 function addItems() {
5926 items.push( this );
5927 }
5928 for ( i = queries.length - 1; i >= 0; i-- ) {
5929 queries[ i ][ 0 ].each( addItems );
5930 }
5931
5932 return $( items );
5933
5934 },
5935
5936 _removeCurrentsFromItems: function() {
5937
5938 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
5939
5940 this.items = $.grep( this.items, function( item ) {
5941 for ( var j = 0; j < list.length; j++ ) {
5942 if ( list[ j ] === item.item[ 0 ] ) {
5943 return false;
5944 }
5945 }
5946 return true;
5947 } );
5948
5949 },
5950
5951 _refreshItems: function( event ) {
5952
5953 this.items = [];
5954 this.containers = [ this ];
5955
5956 var i, j, cur, inst, targetData, _queries, item, queriesLength,
5957 items = this.items,
5958 queries = [ [ $.isFunction( this.options.items ) ?
5959 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
5960 $( this.options.items, this.element ), this ] ],
5961 connectWith = this._connectWith();
5962
5963 //Shouldn't be run the first time through due to massive slow-down
5964 if ( connectWith && this.ready ) {
5965 for ( i = connectWith.length - 1; i >= 0; i-- ) {
5966 cur = $( connectWith[ i ], this.document[ 0 ] );
5967 for ( j = cur.length - 1; j >= 0; j-- ) {
5968 inst = $.data( cur[ j ], this.widgetFullName );
5969 if ( inst && inst !== this && !inst.options.disabled ) {
5970 queries.push( [ $.isFunction( inst.options.items ) ?
5971 inst.options.items
5972 .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
5973 $( inst.options.items, inst.element ), inst ] );
5974 this.containers.push( inst );
5975 }
5976 }
5977 }
5978 }
5979
5980 for ( i = queries.length - 1; i >= 0; i-- ) {
5981 targetData = queries[ i ][ 1 ];
5982 _queries = queries[ i ][ 0 ];
5983
5984 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
5985 item = $( _queries[ j ] );
5986
5987 // Data for target checking (mouse manager)
5988 item.data( this.widgetName + "-item", targetData );
5989
5990 items.push( {
5991 item: item,
5992 instance: targetData,
5993 width: 0, height: 0,
5994 left: 0, top: 0
5995 } );
5996 }
5997 }
5998
5999 },
6000
6001 refreshPositions: function( fast ) {
6002
6003 // Determine whether items are being displayed horizontally
6004 this.floating = this.items.length ?
6005 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
6006 false;
6007
6008 //This has to be redone because due to the item being moved out/into the offsetParent,
6009 // the offsetParent's position will change
6010 if ( this.offsetParent && this.helper ) {
6011 this.offset.parent = this._getParentOffset();
6012 }
6013
6014 var i, item, t, p;
6015
6016 for ( i = this.items.length - 1; i >= 0; i-- ) {
6017 item = this.items[ i ];
6018
6019 //We ignore calculating positions of all connected containers when we're not over them
6020 if ( item.instance !== this.currentContainer && this.currentContainer &&
6021 item.item[ 0 ] !== this.currentItem[ 0 ] ) {
6022 continue;
6023 }
6024
6025 t = this.options.toleranceElement ?
6026 $( this.options.toleranceElement, item.item ) :
6027 item.item;
6028
6029 if ( !fast ) {
6030 item.width = t.outerWidth();
6031 item.height = t.outerHeight();
6032 }
6033
6034 p = t.offset();
6035 item.left = p.left;
6036 item.top = p.top;
6037 }
6038
6039 if ( this.options.custom && this.options.custom.refreshContainers ) {
6040 this.options.custom.refreshContainers.call( this );
6041 } else {
6042 for ( i = this.containers.length - 1; i >= 0; i-- ) {
6043 p = this.containers[ i ].element.offset();
6044 this.containers[ i ].containerCache.left = p.left;
6045 this.containers[ i ].containerCache.top = p.top;
6046 this.containers[ i ].containerCache.width =
6047 this.containers[ i ].element.outerWidth();
6048 this.containers[ i ].containerCache.height =
6049 this.containers[ i ].element.outerHeight();
6050 }
6051 }
6052
6053 return this;
6054 },
6055
6056 _createPlaceholder: function( that ) {
6057 that = that || this;
6058 var className,
6059 o = that.options;
6060
6061 if ( !o.placeholder || o.placeholder.constructor === String ) {
6062 className = o.placeholder;
6063 o.placeholder = {
6064 element: function() {
6065
6066 var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
6067 element = $( "<" + nodeName + ">", that.document[ 0 ] );
6068
6069 that._addClass( element, "ui-sortable-placeholder",
6070 className || that.currentItem[ 0 ].className )
6071 ._removeClass( element, "ui-sortable-helper" );
6072
6073 if ( nodeName === "tbody" ) {
6074 that._createTrPlaceholder(
6075 that.currentItem.find( "tr" ).eq( 0 ),
6076 $( "<tr>", that.document[ 0 ] ).appendTo( element )
6077 );
6078 } else if ( nodeName === "tr" ) {
6079 that._createTrPlaceholder( that.currentItem, element );
6080 } else if ( nodeName === "img" ) {
6081 element.attr( "src", that.currentItem.attr( "src" ) );
6082 }
6083
6084 if ( !className ) {
6085 element.css( "visibility", "hidden" );
6086 }
6087
6088 return element;
6089 },
6090 update: function( container, p ) {
6091
6092 // 1. If a className is set as 'placeholder option, we don't force sizes -
6093 // the class is responsible for that
6094 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
6095 // class name is specified
6096 if ( className && !o.forcePlaceholderSize ) {
6097 return;
6098 }
6099
6100 //If the element doesn't have a actual height by itself (without styles coming
6101 // from a stylesheet), it receives the inline height from the dragged item
6102 if ( !p.height() ) {
6103 p.height(
6104 that.currentItem.innerHeight() -
6105 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
6106 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
6107 }
6108 if ( !p.width() ) {
6109 p.width(
6110 that.currentItem.innerWidth() -
6111 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
6112 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
6113 }
6114 }
6115 };
6116 }
6117
6118 //Create the placeholder
6119 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
6120
6121 //Append it after the actual current item
6122 that.currentItem.after( that.placeholder );
6123
6124 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
6125 o.placeholder.update( that, that.placeholder );
6126
6127 },
6128
6129 _createTrPlaceholder: function( sourceTr, targetTr ) {
6130 var that = this;
6131
6132 sourceTr.children().each( function() {
6133 $( "<td>&#160;</td>", that.document[ 0 ] )
6134 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
6135 .appendTo( targetTr );
6136 } );
6137 },
6138
6139 _contactContainers: function( event ) {
6140 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
6141 floating, axis,
6142 innermostContainer = null,
6143 innermostIndex = null;
6144
6145 // Get innermost container that intersects with item
6146 for ( i = this.containers.length - 1; i >= 0; i-- ) {
6147
6148 // Never consider a container that's located within the item itself
6149 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
6150 continue;
6151 }
6152
6153 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
6154
6155 // If we've already found a container and it's more "inner" than this, then continue
6156 if ( innermostContainer &&
6157 $.contains(
6158 this.containers[ i ].element[ 0 ],
6159 innermostContainer.element[ 0 ] ) ) {
6160 continue;
6161 }
6162
6163 innermostContainer = this.containers[ i ];
6164 innermostIndex = i;
6165
6166 } else {
6167
6168 // container doesn't intersect. trigger "out" event if necessary
6169 if ( this.containers[ i ].containerCache.over ) {
6170 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
6171 this.containers[ i ].containerCache.over = 0;
6172 }
6173 }
6174
6175 }
6176
6177 // If no intersecting containers found, return
6178 if ( !innermostContainer ) {
6179 return;
6180 }
6181
6182 // Move the item into the container if it's not there already
6183 if ( this.containers.length === 1 ) {
6184 if ( !this.containers[ innermostIndex ].containerCache.over ) {
6185 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
6186 this.containers[ innermostIndex ].containerCache.over = 1;
6187 }
6188 } else {
6189
6190 // When entering a new container, we will find the item with the least distance and
6191 // append our item near it
6192 dist = 10000;
6193 itemWithLeastDistance = null;
6194 floating = innermostContainer.floating || this._isFloating( this.currentItem );
6195 posProperty = floating ? "left" : "top";
6196 sizeProperty = floating ? "width" : "height";
6197 axis = floating ? "pageX" : "pageY";
6198
6199 for ( j = this.items.length - 1; j >= 0; j-- ) {
6200 if ( !$.contains(
6201 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
6202 ) {
6203 continue;
6204 }
6205 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
6206 continue;
6207 }
6208
6209 cur = this.items[ j ].item.offset()[ posProperty ];
6210 nearBottom = false;
6211 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
6212 nearBottom = true;
6213 }
6214
6215 if ( Math.abs( event[ axis ] - cur ) < dist ) {
6216 dist = Math.abs( event[ axis ] - cur );
6217 itemWithLeastDistance = this.items[ j ];
6218 this.direction = nearBottom ? "up" : "down";
6219 }
6220 }
6221
6222 //Check if dropOnEmpty is enabled
6223 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
6224 return;
6225 }
6226
6227 if ( this.currentContainer === this.containers[ innermostIndex ] ) {
6228 if ( !this.currentContainer.containerCache.over ) {
6229 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
6230 this.currentContainer.containerCache.over = 1;
6231 }
6232 return;
6233 }
6234
6235 itemWithLeastDistance ?
6236 this._rearrange( event, itemWithLeastDistance, null, true ) :
6237 this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
6238 this._trigger( "change", event, this._uiHash() );
6239 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
6240 this.currentContainer = this.containers[ innermostIndex ];
6241
6242 //Update the placeholder
6243 this.options.placeholder.update( this.currentContainer, this.placeholder );
6244
6245 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
6246 this.containers[ innermostIndex ].containerCache.over = 1;
6247 }
6248
6249 },
6250
6251 _createHelper: function( event ) {
6252
6253 var o = this.options,
6254 helper = $.isFunction( o.helper ) ?
6255 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
6256 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
6257
6258 //Add the helper to the DOM if that didn't happen already
6259 if ( !helper.parents( "body" ).length ) {
6260 $( o.appendTo !== "parent" ?
6261 o.appendTo :
6262 this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
6263 }
6264
6265 if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
6266 this._storedCSS = {
6267 width: this.currentItem[ 0 ].style.width,
6268 height: this.currentItem[ 0 ].style.height,
6269 position: this.currentItem.css( "position" ),
6270 top: this.currentItem.css( "top" ),
6271 left: this.currentItem.css( "left" )
6272 };
6273 }
6274
6275 if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
6276 helper.width( this.currentItem.width() );
6277 }
6278 if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
6279 helper.height( this.currentItem.height() );
6280 }
6281
6282 return helper;
6283
6284 },
6285
6286 _adjustOffsetFromHelper: function( obj ) {
6287 if ( typeof obj === "string" ) {
6288 obj = obj.split( " " );
6289 }
6290 if ( $.isArray( obj ) ) {
6291 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
6292 }
6293 if ( "left" in obj ) {
6294 this.offset.click.left = obj.left + this.margins.left;
6295 }
6296 if ( "right" in obj ) {
6297 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6298 }
6299 if ( "top" in obj ) {
6300 this.offset.click.top = obj.top + this.margins.top;
6301 }
6302 if ( "bottom" in obj ) {
6303 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6304 }
6305 },
6306
6307 _getParentOffset: function() {
6308
6309 //Get the offsetParent and cache its position
6310 this.offsetParent = this.helper.offsetParent();
6311 var po = this.offsetParent.offset();
6312
6313 // This is a special case where we need to modify a offset calculated on start, since the
6314 // following happened:
6315 // 1. The position of the helper is absolute, so it's position is calculated based on the
6316 // next positioned parent
6317 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
6318 // the document, which means that the scroll is included in the initial calculation of the
6319 // offset of the parent, and never recalculated upon drag
6320 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
6321 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
6322 po.left += this.scrollParent.scrollLeft();
6323 po.top += this.scrollParent.scrollTop();
6324 }
6325
6326 // This needs to be actually done for all browsers, since pageX/pageY includes this
6327 // information with an ugly IE fix
6328 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
6329 ( this.offsetParent[ 0 ].tagName &&
6330 this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
6331 po = { top: 0, left: 0 };
6332 }
6333
6334 return {
6335 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
6336 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
6337 };
6338
6339 },
6340
6341 _getRelativeOffset: function() {
6342
6343 if ( this.cssPosition === "relative" ) {
6344 var p = this.currentItem.position();
6345 return {
6346 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
6347 this.scrollParent.scrollTop(),
6348 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
6349 this.scrollParent.scrollLeft()
6350 };
6351 } else {
6352 return { top: 0, left: 0 };
6353 }
6354
6355 },
6356
6357 _cacheMargins: function() {
6358 this.margins = {
6359 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
6360 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
6361 };
6362 },
6363
6364 _cacheHelperProportions: function() {
6365 this.helperProportions = {
6366 width: this.helper.outerWidth(),
6367 height: this.helper.outerHeight()
6368 };
6369 },
6370
6371 _setContainment: function() {
6372
6373 var ce, co, over,
6374 o = this.options;
6375 if ( o.containment === "parent" ) {
6376 o.containment = this.helper[ 0 ].parentNode;
6377 }
6378 if ( o.containment === "document" || o.containment === "window" ) {
6379 this.containment = [
6380 0 - this.offset.relative.left - this.offset.parent.left,
6381 0 - this.offset.relative.top - this.offset.parent.top,
6382 o.containment === "document" ?
6383 this.document.width() :
6384 this.window.width() - this.helperProportions.width - this.margins.left,
6385 ( o.containment === "document" ?
6386 ( this.document.height() || document.body.parentNode.scrollHeight ) :
6387 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
6388 ) - this.helperProportions.height - this.margins.top
6389 ];
6390 }
6391
6392 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
6393 ce = $( o.containment )[ 0 ];
6394 co = $( o.containment ).offset();
6395 over = ( $( ce ).css( "overflow" ) !== "hidden" );
6396
6397 this.containment = [
6398 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
6399 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
6400 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
6401 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
6402 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
6403 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
6404 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
6405 this.helperProportions.width - this.margins.left,
6406 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
6407 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
6408 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
6409 this.helperProportions.height - this.margins.top
6410 ];
6411 }
6412
6413 },
6414
6415 _convertPositionTo: function( d, pos ) {
6416
6417 if ( !pos ) {
6418 pos = this.position;
6419 }
6420 var mod = d === "absolute" ? 1 : -1,
6421 scroll = this.cssPosition === "absolute" &&
6422 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
6423 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
6424 this.offsetParent :
6425 this.scrollParent,
6426 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
6427
6428 return {
6429 top: (
6430
6431 // The absolute mouse position
6432 pos.top +
6433
6434 // Only for relative positioned nodes: Relative offset from element to offset parent
6435 this.offset.relative.top * mod +
6436
6437 // The offsetParent's offset without borders (offset + border)
6438 this.offset.parent.top * mod -
6439 ( ( this.cssPosition === "fixed" ?
6440 -this.scrollParent.scrollTop() :
6441 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
6442 ),
6443 left: (
6444
6445 // The absolute mouse position
6446 pos.left +
6447
6448 // Only for relative positioned nodes: Relative offset from element to offset parent
6449 this.offset.relative.left * mod +
6450
6451 // The offsetParent's offset without borders (offset + border)
6452 this.offset.parent.left * mod -
6453 ( ( this.cssPosition === "fixed" ?
6454 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
6455 scroll.scrollLeft() ) * mod )
6456 )
6457 };
6458
6459 },
6460
6461 _generatePosition: function( event ) {
6462
6463 var top, left,
6464 o = this.options,
6465 pageX = event.pageX,
6466 pageY = event.pageY,
6467 scroll = this.cssPosition === "absolute" &&
6468 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
6469 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
6470 this.offsetParent :
6471 this.scrollParent,
6472 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
6473
6474 // This is another very weird special case that only happens for relative elements:
6475 // 1. If the css position is relative
6476 // 2. and the scroll parent is the document or similar to the offset parent
6477 // we have to refresh the relative offset during the scroll so there are no jumps
6478 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
6479 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
6480 this.offset.relative = this._getRelativeOffset();
6481 }
6482
6483 /*
6484 * - Position constraining -
6485 * Constrain the position to a mix of grid, containment.
6486 */
6487
6488 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
6489
6490 if ( this.containment ) {
6491 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
6492 pageX = this.containment[ 0 ] + this.offset.click.left;
6493 }
6494 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
6495 pageY = this.containment[ 1 ] + this.offset.click.top;
6496 }
6497 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
6498 pageX = this.containment[ 2 ] + this.offset.click.left;
6499 }
6500 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
6501 pageY = this.containment[ 3 ] + this.offset.click.top;
6502 }
6503 }
6504
6505 if ( o.grid ) {
6506 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
6507 o.grid[ 1 ] ) * o.grid[ 1 ];
6508 pageY = this.containment ?
6509 ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
6510 top - this.offset.click.top <= this.containment[ 3 ] ) ?
6511 top :
6512 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
6513 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
6514 top;
6515
6516 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
6517 o.grid[ 0 ] ) * o.grid[ 0 ];
6518 pageX = this.containment ?
6519 ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
6520 left - this.offset.click.left <= this.containment[ 2 ] ) ?
6521 left :
6522 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
6523 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
6524 left;
6525 }
6526
6527 }
6528
6529 return {
6530 top: (
6531
6532 // The absolute mouse position
6533 pageY -
6534
6535 // Click offset (relative to the element)
6536 this.offset.click.top -
6537
6538 // Only for relative positioned nodes: Relative offset from element to offset parent
6539 this.offset.relative.top -
6540
6541 // The offsetParent's offset without borders (offset + border)
6542 this.offset.parent.top +
6543 ( ( this.cssPosition === "fixed" ?
6544 -this.scrollParent.scrollTop() :
6545 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
6546 ),
6547 left: (
6548
6549 // The absolute mouse position
6550 pageX -
6551
6552 // Click offset (relative to the element)
6553 this.offset.click.left -
6554
6555 // Only for relative positioned nodes: Relative offset from element to offset parent
6556 this.offset.relative.left -
6557
6558 // The offsetParent's offset without borders (offset + border)
6559 this.offset.parent.left +
6560 ( ( this.cssPosition === "fixed" ?
6561 -this.scrollParent.scrollLeft() :
6562 scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
6563 )
6564 };
6565
6566 },
6567
6568 _rearrange: function( event, i, a, hardRefresh ) {
6569
6570 a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
6571 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
6572 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
6573
6574 //Various things done here to improve the performance:
6575 // 1. we create a setTimeout, that calls refreshPositions
6576 // 2. on the instance, we have a counter variable, that get's higher after every append
6577 // 3. on the local scope, we copy the counter variable, and check in the timeout,
6578 // if it's still the same
6579 // 4. this lets only the last addition to the timeout stack through
6580 this.counter = this.counter ? ++this.counter : 1;
6581 var counter = this.counter;
6582
6583 this._delay( function() {
6584 if ( counter === this.counter ) {
6585
6586 //Precompute after each DOM insertion, NOT on mousemove
6587 this.refreshPositions( !hardRefresh );
6588 }
6589 } );
6590
6591 },
6592
6593 _clear: function( event, noPropagation ) {
6594
6595 this.reverting = false;
6596
6597 // We delay all events that have to be triggered to after the point where the placeholder
6598 // has been removed and everything else normalized again
6599 var i,
6600 delayedTriggers = [];
6601
6602 // We first have to update the dom position of the actual currentItem
6603 // Note: don't do it if the current item is already removed (by a user), or it gets
6604 // reappended (see #4088)
6605 if ( !this._noFinalSort && this.currentItem.parent().length ) {
6606 this.placeholder.before( this.currentItem );
6607 }
6608 this._noFinalSort = null;
6609
6610 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
6611 for ( i in this._storedCSS ) {
6612 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
6613 this._storedCSS[ i ] = "";
6614 }
6615 }
6616 this.currentItem.css( this._storedCSS );
6617 this._removeClass( this.currentItem, "ui-sortable-helper" );
6618 } else {
6619 this.currentItem.show();
6620 }
6621
6622 if ( this.fromOutside && !noPropagation ) {
6623 delayedTriggers.push( function( event ) {
6624 this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
6625 } );
6626 }
6627 if ( ( this.fromOutside ||
6628 this.domPosition.prev !==
6629 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
6630 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
6631
6632 // Trigger update callback if the DOM position has changed
6633 delayedTriggers.push( function( event ) {
6634 this._trigger( "update", event, this._uiHash() );
6635 } );
6636 }
6637
6638 // Check if the items Container has Changed and trigger appropriate
6639 // events.
6640 if ( this !== this.currentContainer ) {
6641 if ( !noPropagation ) {
6642 delayedTriggers.push( function( event ) {
6643 this._trigger( "remove", event, this._uiHash() );
6644 } );
6645 delayedTriggers.push( ( function( c ) {
6646 return function( event ) {
6647 c._trigger( "receive", event, this._uiHash( this ) );
6648 };
6649 } ).call( this, this.currentContainer ) );
6650 delayedTriggers.push( ( function( c ) {
6651 return function( event ) {
6652 c._trigger( "update", event, this._uiHash( this ) );
6653 };
6654 } ).call( this, this.currentContainer ) );
6655 }
6656 }
6657
6658 //Post events to containers
6659 function delayEvent( type, instance, container ) {
6660 return function( event ) {
6661 container._trigger( type, event, instance._uiHash( instance ) );
6662 };
6663 }
6664 for ( i = this.containers.length - 1; i >= 0; i-- ) {
6665 if ( !noPropagation ) {
6666 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
6667 }
6668 if ( this.containers[ i ].containerCache.over ) {
6669 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
6670 this.containers[ i ].containerCache.over = 0;
6671 }
6672 }
6673
6674 //Do what was originally in plugins
6675 if ( this.storedCursor ) {
6676 this.document.find( "body" ).css( "cursor", this.storedCursor );
6677 this.storedStylesheet.remove();
6678 }
6679 if ( this._storedOpacity ) {
6680 this.helper.css( "opacity", this._storedOpacity );
6681 }
6682 if ( this._storedZIndex ) {
6683 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
6684 }
6685
6686 this.dragging = false;
6687
6688 if ( !noPropagation ) {
6689 this._trigger( "beforeStop", event, this._uiHash() );
6690 }
6691
6692 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
6693 // it unbinds ALL events from the original node!
6694 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
6695
6696 if ( !this.cancelHelperRemoval ) {
6697 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
6698 this.helper.remove();
6699 }
6700 this.helper = null;
6701 }
6702
6703 if ( !noPropagation ) {
6704 for ( i = 0; i < delayedTriggers.length; i++ ) {
6705
6706 // Trigger all delayed events
6707 delayedTriggers[ i ].call( this, event );
6708 }
6709 this._trigger( "stop", event, this._uiHash() );
6710 }
6711
6712 this.fromOutside = false;
6713 return !this.cancelHelperRemoval;
6714
6715 },
6716
6717 _trigger: function() {
6718 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
6719 this.cancel();
6720 }
6721 },
6722
6723 _uiHash: function( _inst ) {
6724 var inst = _inst || this;
6725 return {
6726 helper: inst.helper,
6727 placeholder: inst.placeholder || $( [] ),
6728 position: inst.position,
6729 originalPosition: inst.originalPosition,
6730 offset: inst.positionAbs,
6731 item: inst.currentItem,
6732 sender: _inst ? _inst.element : null
6733 };
6734 }
6735
6736 } );
6737
6738
6739 /*!
6740 * jQuery UI Accordion 1.12.1
6741 * http://jqueryui.com
6742 *
6743 * Copyright jQuery Foundation and other contributors
6744 * Released under the MIT license.
6745 * http://jquery.org/license
6746 */
6747
6748 //>>label: Accordion
6749 //>>group: Widgets
6750 // jscs:disable maximumLineLength
6751 //>>description: Displays collapsible content panels for presenting information in a limited amount of space.
6752 // jscs:enable maximumLineLength
6753 //>>docs: http://api.jqueryui.com/accordion/
6754 //>>demos: http://jqueryui.com/accordion/
6755 //>>css.structure: ../../themes/base/core.css
6756 //>>css.structure: ../../themes/base/accordion.css
6757 //>>css.theme: ../../themes/base/theme.css
6758
6759
6760
6761 var widgetsAccordion = $.widget( "ui.accordion", {
6762 version: "1.12.1",
6763 options: {
6764 active: 0,
6765 animate: {},
6766 classes: {
6767 "ui-accordion-header": "ui-corner-top",
6768 "ui-accordion-header-collapsed": "ui-corner-all",
6769 "ui-accordion-content": "ui-corner-bottom"
6770 },
6771 collapsible: false,
6772 event: "click",
6773 header: "> li > :first-child, > :not(li):even",
6774 heightStyle: "auto",
6775 icons: {
6776 activeHeader: "ui-icon-triangle-1-s",
6777 header: "ui-icon-triangle-1-e"
6778 },
6779
6780 // Callbacks
6781 activate: null,
6782 beforeActivate: null
6783 },
6784
6785 hideProps: {
6786 borderTopWidth: "hide",
6787 borderBottomWidth: "hide",
6788 paddingTop: "hide",
6789 paddingBottom: "hide",
6790 height: "hide"
6791 },
6792
6793 showProps: {
6794 borderTopWidth: "show",
6795 borderBottomWidth: "show",
6796 paddingTop: "show",
6797 paddingBottom: "show",
6798 height: "show"
6799 },
6800
6801 _create: function() {
6802 var options = this.options;
6803
6804 this.prevShow = this.prevHide = $();
6805 this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
6806 this.element.attr( "role", "tablist" );
6807
6808 // Don't allow collapsible: false and active: false / null
6809 if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
6810 options.active = 0;
6811 }
6812
6813 this._processPanels();
6814
6815 // handle negative values
6816 if ( options.active < 0 ) {
6817 options.active += this.headers.length;
6818 }
6819 this._refresh();
6820 },
6821
6822 _getCreateEventData: function() {
6823 return {
6824 header: this.active,
6825 panel: !this.active.length ? $() : this.active.next()
6826 };
6827 },
6828
6829 _createIcons: function() {
6830 var icon, children,
6831 icons = this.options.icons;
6832
6833 if ( icons ) {
6834 icon = $( "<span>" );
6835 this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
6836 icon.prependTo( this.headers );
6837 children = this.active.children( ".ui-accordion-header-icon" );
6838 this._removeClass( children, icons.header )
6839 ._addClass( children, null, icons.activeHeader )
6840 ._addClass( this.headers, "ui-accordion-icons" );
6841 }
6842 },
6843
6844 _destroyIcons: function() {
6845 this._removeClass( this.headers, "ui-accordion-icons" );
6846 this.headers.children( ".ui-accordion-header-icon" ).remove();
6847 },
6848
6849 _destroy: function() {
6850 var contents;
6851
6852 // Clean up main element
6853 this.element.removeAttr( "role" );
6854
6855 // Clean up headers
6856 this.headers
6857 .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
6858 .removeUniqueId();
6859
6860 this._destroyIcons();
6861
6862 // Clean up content panels
6863 contents = this.headers.next()
6864 .css( "display", "" )
6865 .removeAttr( "role aria-hidden aria-labelledby" )
6866 .removeUniqueId();
6867
6868 if ( this.options.heightStyle !== "content" ) {
6869 contents.css( "height", "" );
6870 }
6871 },
6872
6873 _setOption: function( key, value ) {
6874 if ( key === "active" ) {
6875
6876 // _activate() will handle invalid values and update this.options
6877 this._activate( value );
6878 return;
6879 }
6880
6881 if ( key === "event" ) {
6882 if ( this.options.event ) {
6883 this._off( this.headers, this.options.event );
6884 }
6885 this._setupEvents( value );
6886 }
6887
6888 this._super( key, value );
6889
6890 // Setting collapsible: false while collapsed; open first panel
6891 if ( key === "collapsible" && !value && this.options.active === false ) {
6892 this._activate( 0 );
6893 }
6894
6895 if ( key === "icons" ) {
6896 this._destroyIcons();
6897 if ( value ) {
6898 this._createIcons();
6899 }
6900 }
6901 },
6902
6903 _setOptionDisabled: function( value ) {
6904 this._super( value );
6905
6906 this.element.attr( "aria-disabled", value );
6907
6908 // Support: IE8 Only
6909 // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
6910 // so we need to add the disabled class to the headers and panels
6911 this._toggleClass( null, "ui-state-disabled", !!value );
6912 this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
6913 !!value );
6914 },
6915
6916 _keydown: function( event ) {
6917 if ( event.altKey || event.ctrlKey ) {
6918 return;
6919 }
6920
6921 var keyCode = $.ui.keyCode,
6922 length = this.headers.length,
6923 currentIndex = this.headers.index( event.target ),
6924 toFocus = false;
6925
6926 switch ( event.keyCode ) {
6927 case keyCode.RIGHT:
6928 case keyCode.DOWN:
6929 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
6930 break;
6931 case keyCode.LEFT:
6932 case keyCode.UP:
6933 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
6934 break;
6935 case keyCode.SPACE:
6936 case keyCode.ENTER:
6937 this._eventHandler( event );
6938 break;
6939 case keyCode.HOME:
6940 toFocus = this.headers[ 0 ];
6941 break;
6942 case keyCode.END:
6943 toFocus = this.headers[ length - 1 ];
6944 break;
6945 }
6946
6947 if ( toFocus ) {
6948 $( event.target ).attr( "tabIndex", -1 );
6949 $( toFocus ).attr( "tabIndex", 0 );
6950 $( toFocus ).trigger( "focus" );
6951 event.preventDefault();
6952 }
6953 },
6954
6955 _panelKeyDown: function( event ) {
6956 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
6957 $( event.currentTarget ).prev().trigger( "focus" );
6958 }
6959 },
6960
6961 refresh: function() {
6962 var options = this.options;
6963 this._processPanels();
6964
6965 // Was collapsed or no panel
6966 if ( ( options.active === false && options.collapsible === true ) ||
6967 !this.headers.length ) {
6968 options.active = false;
6969 this.active = $();
6970
6971 // active false only when collapsible is true
6972 } else if ( options.active === false ) {
6973 this._activate( 0 );
6974
6975 // was active, but active panel is gone
6976 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
6977
6978 // all remaining panel are disabled
6979 if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
6980 options.active = false;
6981 this.active = $();
6982
6983 // activate previous panel
6984 } else {
6985 this._activate( Math.max( 0, options.active - 1 ) );
6986 }
6987
6988 // was active, active panel still exists
6989 } else {
6990
6991 // make sure active index is correct
6992 options.active = this.headers.index( this.active );
6993 }
6994
6995 this._destroyIcons();
6996
6997 this._refresh();
6998 },
6999
7000 _processPanels: function() {
7001 var prevHeaders = this.headers,
7002 prevPanels = this.panels;
7003
7004 this.headers = this.element.find( this.options.header );
7005 this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
7006 "ui-state-default" );
7007
7008 this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
7009 this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
7010
7011 // Avoid memory leaks (#10056)
7012 if ( prevPanels ) {
7013 this._off( prevHeaders.not( this.headers ) );
7014 this._off( prevPanels.not( this.panels ) );
7015 }
7016 },
7017
7018 _refresh: function() {
7019 var maxHeight,
7020 options = this.options,
7021 heightStyle = options.heightStyle,
7022 parent = this.element.parent();
7023
7024 this.active = this._findActive( options.active );
7025 this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
7026 ._removeClass( this.active, "ui-accordion-header-collapsed" );
7027 this._addClass( this.active.next(), "ui-accordion-content-active" );
7028 this.active.next().show();
7029
7030 this.headers
7031 .attr( "role", "tab" )
7032 .each( function() {
7033 var header = $( this ),
7034 headerId = header.uniqueId().attr( "id" ),
7035 panel = header.next(),
7036 panelId = panel.uniqueId().attr( "id" );
7037 header.attr( "aria-controls", panelId );
7038 panel.attr( "aria-labelledby", headerId );
7039 } )
7040 .next()
7041 .attr( "role", "tabpanel" );
7042
7043 this.headers
7044 .not( this.active )
7045 .attr( {
7046 "aria-selected": "false",
7047 "aria-expanded": "false",
7048 tabIndex: -1
7049 } )
7050 .next()
7051 .attr( {
7052 "aria-hidden": "true"
7053 } )
7054 .hide();
7055
7056 // Make sure at least one header is in the tab order
7057 if ( !this.active.length ) {
7058 this.headers.eq( 0 ).attr( "tabIndex", 0 );
7059 } else {
7060 this.active.attr( {
7061 "aria-selected": "true",
7062 "aria-expanded": "true",
7063 tabIndex: 0
7064 } )
7065 .next()
7066 .attr( {
7067 "aria-hidden": "false"
7068 } );
7069 }
7070
7071 this._createIcons();
7072
7073 this._setupEvents( options.event );
7074
7075 if ( heightStyle === "fill" ) {
7076 maxHeight = parent.height();
7077 this.element.siblings( ":visible" ).each( function() {
7078 var elem = $( this ),
7079 position = elem.css( "position" );
7080
7081 if ( position === "absolute" || position === "fixed" ) {
7082 return;
7083 }
7084 maxHeight -= elem.outerHeight( true );
7085 } );
7086
7087 this.headers.each( function() {
7088 maxHeight -= $( this ).outerHeight( true );
7089 } );
7090
7091 this.headers.next()
7092 .each( function() {
7093 $( this ).height( Math.max( 0, maxHeight -
7094 $( this ).innerHeight() + $( this ).height() ) );
7095 } )
7096 .css( "overflow", "auto" );
7097 } else if ( heightStyle === "auto" ) {
7098 maxHeight = 0;
7099 this.headers.next()
7100 .each( function() {
7101 var isVisible = $( this ).is( ":visible" );
7102 if ( !isVisible ) {
7103 $( this ).show();
7104 }
7105 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
7106 if ( !isVisible ) {
7107 $( this ).hide();
7108 }
7109 } )
7110 .height( maxHeight );
7111 }
7112 },
7113
7114 _activate: function( index ) {
7115 var active = this._findActive( index )[ 0 ];
7116
7117 // Trying to activate the already active panel
7118 if ( active === this.active[ 0 ] ) {
7119 return;
7120 }
7121
7122 // Trying to collapse, simulate a click on the currently active header
7123 active = active || this.active[ 0 ];
7124
7125 this._eventHandler( {
7126 target: active,
7127 currentTarget: active,
7128 preventDefault: $.noop
7129 } );
7130 },
7131
7132 _findActive: function( selector ) {
7133 return typeof selector === "number" ? this.headers.eq( selector ) : $();
7134 },
7135
7136 _setupEvents: function( event ) {
7137 var events = {
7138 keydown: "_keydown"
7139 };
7140 if ( event ) {
7141 $.each( event.split( " " ), function( index, eventName ) {
7142 events[ eventName ] = "_eventHandler";
7143 } );
7144 }
7145
7146 this._off( this.headers.add( this.headers.next() ) );
7147 this._on( this.headers, events );
7148 this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
7149 this._hoverable( this.headers );
7150 this._focusable( this.headers );
7151 },
7152
7153 _eventHandler: function( event ) {
7154 var activeChildren, clickedChildren,
7155 options = this.options,
7156 active = this.active,
7157 clicked = $( event.currentTarget ),
7158 clickedIsActive = clicked[ 0 ] === active[ 0 ],
7159 collapsing = clickedIsActive && options.collapsible,
7160 toShow = collapsing ? $() : clicked.next(),
7161 toHide = active.next(),
7162 eventData = {
7163 oldHeader: active,
7164 oldPanel: toHide,
7165 newHeader: collapsing ? $() : clicked,
7166 newPanel: toShow
7167 };
7168
7169 event.preventDefault();
7170
7171 if (
7172
7173 // click on active header, but not collapsible
7174 ( clickedIsActive && !options.collapsible ) ||
7175
7176 // allow canceling activation
7177 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
7178 return;
7179 }
7180
7181 options.active = collapsing ? false : this.headers.index( clicked );
7182
7183 // When the call to ._toggle() comes after the class changes
7184 // it causes a very odd bug in IE 8 (see #6720)
7185 this.active = clickedIsActive ? $() : clicked;
7186 this._toggle( eventData );
7187
7188 // Switch classes
7189 // corner classes on the previously active header stay after the animation
7190 this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
7191 if ( options.icons ) {
7192 activeChildren = active.children( ".ui-accordion-header-icon" );
7193 this._removeClass( activeChildren, null, options.icons.activeHeader )
7194 ._addClass( activeChildren, null, options.icons.header );
7195 }
7196
7197 if ( !clickedIsActive ) {
7198 this._removeClass( clicked, "ui-accordion-header-collapsed" )
7199 ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
7200 if ( options.icons ) {
7201 clickedChildren = clicked.children( ".ui-accordion-header-icon" );
7202 this._removeClass( clickedChildren, null, options.icons.header )
7203 ._addClass( clickedChildren, null, options.icons.activeHeader );
7204 }
7205
7206 this._addClass( clicked.next(), "ui-accordion-content-active" );
7207 }
7208 },
7209
7210 _toggle: function( data ) {
7211 var toShow = data.newPanel,
7212 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
7213
7214 // Handle activating a panel during the animation for another activation
7215 this.prevShow.add( this.prevHide ).stop( true, true );
7216 this.prevShow = toShow;
7217 this.prevHide = toHide;
7218
7219 if ( this.options.animate ) {
7220 this._animate( toShow, toHide, data );
7221 } else {
7222 toHide.hide();
7223 toShow.show();
7224 this._toggleComplete( data );
7225 }
7226
7227 toHide.attr( {
7228 "aria-hidden": "true"
7229 } );
7230 toHide.prev().attr( {
7231 "aria-selected": "false",
7232 "aria-expanded": "false"
7233 } );
7234
7235 // if we're switching panels, remove the old header from the tab order
7236 // if we're opening from collapsed state, remove the previous header from the tab order
7237 // if we're collapsing, then keep the collapsing header in the tab order
7238 if ( toShow.length && toHide.length ) {
7239 toHide.prev().attr( {
7240 "tabIndex": -1,
7241 "aria-expanded": "false"
7242 } );
7243 } else if ( toShow.length ) {
7244 this.headers.filter( function() {
7245 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
7246 } )
7247 .attr( "tabIndex", -1 );
7248 }
7249
7250 toShow
7251 .attr( "aria-hidden", "false" )
7252 .prev()
7253 .attr( {
7254 "aria-selected": "true",
7255 "aria-expanded": "true",
7256 tabIndex: 0
7257 } );
7258 },
7259
7260 _animate: function( toShow, toHide, data ) {
7261 var total, easing, duration,
7262 that = this,
7263 adjust = 0,
7264 boxSizing = toShow.css( "box-sizing" ),
7265 down = toShow.length &&
7266 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
7267 animate = this.options.animate || {},
7268 options = down && animate.down || animate,
7269 complete = function() {
7270 that._toggleComplete( data );
7271 };
7272
7273 if ( typeof options === "number" ) {
7274 duration = options;
7275 }
7276 if ( typeof options === "string" ) {
7277 easing = options;
7278 }
7279
7280 // fall back from options to animation in case of partial down settings
7281 easing = easing || options.easing || animate.easing;
7282 duration = duration || options.duration || animate.duration;
7283
7284 if ( !toHide.length ) {
7285 return toShow.animate( this.showProps, duration, easing, complete );
7286 }
7287 if ( !toShow.length ) {
7288 return toHide.animate( this.hideProps, duration, easing, complete );
7289 }
7290
7291 total = toShow.show().outerHeight();
7292 toHide.animate( this.hideProps, {
7293 duration: duration,
7294 easing: easing,
7295 step: function( now, fx ) {
7296 fx.now = Math.round( now );
7297 }
7298 } );
7299 toShow
7300 .hide()
7301 .animate( this.showProps, {
7302 duration: duration,
7303 easing: easing,
7304 complete: complete,
7305 step: function( now, fx ) {
7306 fx.now = Math.round( now );
7307 if ( fx.prop !== "height" ) {
7308 if ( boxSizing === "content-box" ) {
7309 adjust += fx.now;
7310 }
7311 } else if ( that.options.heightStyle !== "content" ) {
7312 fx.now = Math.round( total - toHide.outerHeight() - adjust );
7313 adjust = 0;
7314 }
7315 }
7316 } );
7317 },
7318
7319 _toggleComplete: function( data ) {
7320 var toHide = data.oldPanel,
7321 prev = toHide.prev();
7322
7323 this._removeClass( toHide, "ui-accordion-content-active" );
7324 this._removeClass( prev, "ui-accordion-header-active" )
7325 ._addClass( prev, "ui-accordion-header-collapsed" );
7326
7327 // Work around for rendering bug in IE (#5421)
7328 if ( toHide.length ) {
7329 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
7330 }
7331 this._trigger( "activate", null, data );
7332 }
7333 } );
7334
7335
7336 /*!
7337 * jQuery UI Menu 1.12.1
7338 * http://jqueryui.com
7339 *
7340 * Copyright jQuery Foundation and other contributors
7341 * Released under the MIT license.
7342 * http://jquery.org/license
7343 */
7344
7345 //>>label: Menu
7346 //>>group: Widgets
7347 //>>description: Creates nestable menus.
7348 //>>docs: http://api.jqueryui.com/menu/
7349 //>>demos: http://jqueryui.com/menu/
7350 //>>css.structure: ../../themes/base/core.css
7351 //>>css.structure: ../../themes/base/menu.css
7352 //>>css.theme: ../../themes/base/theme.css
7353
7354
7355
7356 var widgetsMenu = $.widget( "ui.menu", {
7357 version: "1.12.1",
7358 defaultElement: "<ul>",
7359 delay: 300,
7360 options: {
7361 icons: {
7362 submenu: "ui-icon-caret-1-e"
7363 },
7364 items: "> *",
7365 menus: "ul",
7366 position: {
7367 my: "left top",
7368 at: "right top"
7369 },
7370 role: "menu",
7371
7372 // Callbacks
7373 blur: null,
7374 focus: null,
7375 select: null
7376 },
7377
7378 _create: function() {
7379 this.activeMenu = this.element;
7380
7381 // Flag used to prevent firing of the click handler
7382 // as the event bubbles up through nested menus
7383 this.mouseHandled = false;
7384 this.element
7385 .uniqueId()
7386 .attr( {
7387 role: this.options.role,
7388 tabIndex: 0
7389 } );
7390
7391 this._addClass( "ui-menu", "ui-widget ui-widget-content" );
7392 this._on( {
7393
7394 // Prevent focus from sticking to links inside menu after clicking
7395 // them (focus should always stay on UL during navigation).
7396 "mousedown .ui-menu-item": function( event ) {
7397 event.preventDefault();
7398 },
7399 "click .ui-menu-item": function( event ) {
7400 var target = $( event.target );
7401 var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
7402 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
7403 this.select( event );
7404
7405 // Only set the mouseHandled flag if the event will bubble, see #9469.
7406 if ( !event.isPropagationStopped() ) {
7407 this.mouseHandled = true;
7408 }
7409
7410 // Open submenu on click
7411 if ( target.has( ".ui-menu" ).length ) {
7412 this.expand( event );
7413 } else if ( !this.element.is( ":focus" ) &&
7414 active.closest( ".ui-menu" ).length ) {
7415
7416 // Redirect focus to the menu
7417 this.element.trigger( "focus", [ true ] );
7418
7419 // If the active item is on the top level, let it stay active.
7420 // Otherwise, blur the active item since it is no longer visible.
7421 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
7422 clearTimeout( this.timer );
7423 }
7424 }
7425 }
7426 },
7427 "mouseenter .ui-menu-item": function( event ) {
7428
7429 // Ignore mouse events while typeahead is active, see #10458.
7430 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
7431 // is over an item in the menu
7432 if ( this.previousFilter ) {
7433 return;
7434 }
7435
7436 var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
7437 target = $( event.currentTarget );
7438
7439 // Ignore bubbled events on parent items, see #11641
7440 if ( actualTarget[ 0 ] !== target[ 0 ] ) {
7441 return;
7442 }
7443
7444 // Remove ui-state-active class from siblings of the newly focused menu item
7445 // to avoid a jump caused by adjacent elements both having a class with a border
7446 this._removeClass( target.siblings().children( ".ui-state-active" ),
7447 null, "ui-state-active" );
7448 this.focus( event, target );
7449 },
7450 mouseleave: "collapseAll",
7451 "mouseleave .ui-menu": "collapseAll",
7452 focus: function( event, keepActiveItem ) {
7453
7454 // If there's already an active item, keep it active
7455 // If not, activate the first item
7456 var item = this.active || this.element.find( this.options.items ).eq( 0 );
7457
7458 if ( !keepActiveItem ) {
7459 this.focus( event, item );
7460 }
7461 },
7462 blur: function( event ) {
7463 this._delay( function() {
7464 var notContained = !$.contains(
7465 this.element[ 0 ],
7466 $.ui.safeActiveElement( this.document[ 0 ] )
7467 );
7468 if ( notContained ) {
7469 this.collapseAll( event );
7470 }
7471 } );
7472 },
7473 keydown: "_keydown"
7474 } );
7475
7476 this.refresh();
7477
7478 // Clicks outside of a menu collapse any open menus
7479 this._on( this.document, {
7480 click: function( event ) {
7481 if ( this._closeOnDocumentClick( event ) ) {
7482 this.collapseAll( event );
7483 }
7484
7485 // Reset the mouseHandled flag
7486 this.mouseHandled = false;
7487 }
7488 } );
7489 },
7490
7491 _destroy: function() {
7492 var items = this.element.find( ".ui-menu-item" )
7493 .removeAttr( "role aria-disabled" ),
7494 submenus = items.children( ".ui-menu-item-wrapper" )
7495 .removeUniqueId()
7496 .removeAttr( "tabIndex role aria-haspopup" );
7497
7498 // Destroy (sub)menus
7499 this.element
7500 .removeAttr( "aria-activedescendant" )
7501 .find( ".ui-menu" ).addBack()
7502 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
7503 "tabIndex" )
7504 .removeUniqueId()
7505 .show();
7506
7507 submenus.children().each( function() {
7508 var elem = $( this );
7509 if ( elem.data( "ui-menu-submenu-caret" ) ) {
7510 elem.remove();
7511 }
7512 } );
7513 },
7514
7515 _keydown: function( event ) {
7516 var match, prev, character, skip,
7517 preventDefault = true;
7518
7519 switch ( event.keyCode ) {
7520 case $.ui.keyCode.PAGE_UP:
7521 this.previousPage( event );
7522 break;
7523 case $.ui.keyCode.PAGE_DOWN:
7524 this.nextPage( event );
7525 break;
7526 case $.ui.keyCode.HOME:
7527 this._move( "first", "first", event );
7528 break;
7529 case $.ui.keyCode.END:
7530 this._move( "last", "last", event );
7531 break;
7532 case $.ui.keyCode.UP:
7533 this.previous( event );
7534 break;
7535 case $.ui.keyCode.DOWN:
7536 this.next( event );
7537 break;
7538 case $.ui.keyCode.LEFT:
7539 this.collapse( event );
7540 break;
7541 case $.ui.keyCode.RIGHT:
7542 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
7543 this.expand( event );
7544 }
7545 break;
7546 case $.ui.keyCode.ENTER:
7547 case $.ui.keyCode.SPACE:
7548 this._activate( event );
7549 break;
7550 case $.ui.keyCode.ESCAPE:
7551 this.collapse( event );
7552 break;
7553 default:
7554 preventDefault = false;
7555 prev = this.previousFilter || "";
7556 skip = false;
7557
7558 // Support number pad values
7559 character = event.keyCode >= 96 && event.keyCode <= 105 ?
7560 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
7561
7562 clearTimeout( this.filterTimer );
7563
7564 if ( character === prev ) {
7565 skip = true;
7566 } else {
7567 character = prev + character;
7568 }
7569
7570 match = this._filterMenuItems( character );
7571 match = skip && match.index( this.active.next() ) !== -1 ?
7572 this.active.nextAll( ".ui-menu-item" ) :
7573 match;
7574
7575 // If no matches on the current filter, reset to the last character pressed
7576 // to move down the menu to the first item that starts with that character
7577 if ( !match.length ) {
7578 character = String.fromCharCode( event.keyCode );
7579 match = this._filterMenuItems( character );
7580 }
7581
7582 if ( match.length ) {
7583 this.focus( event, match );
7584 this.previousFilter = character;
7585 this.filterTimer = this._delay( function() {
7586 delete this.previousFilter;
7587 }, 1000 );
7588 } else {
7589 delete this.previousFilter;
7590 }
7591 }
7592
7593 if ( preventDefault ) {
7594 event.preventDefault();
7595 }
7596 },
7597
7598 _activate: function( event ) {
7599 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
7600 if ( this.active.children( "[aria-haspopup='true']" ).length ) {
7601 this.expand( event );
7602 } else {
7603 this.select( event );
7604 }
7605 }
7606 },
7607
7608 refresh: function() {
7609 var menus, items, newSubmenus, newItems, newWrappers,
7610 that = this,
7611 icon = this.options.icons.submenu,
7612 submenus = this.element.find( this.options.menus );
7613
7614 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
7615
7616 // Initialize nested menus
7617 newSubmenus = submenus.filter( ":not(.ui-menu)" )
7618 .hide()
7619 .attr( {
7620 role: this.options.role,
7621 "aria-hidden": "true",
7622 "aria-expanded": "false"
7623 } )
7624 .each( function() {
7625 var menu = $( this ),
7626 item = menu.prev(),
7627 submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
7628
7629 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
7630 item
7631 .attr( "aria-haspopup", "true" )
7632 .prepend( submenuCaret );
7633 menu.attr( "aria-labelledby", item.attr( "id" ) );
7634 } );
7635
7636 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
7637
7638 menus = submenus.add( this.element );
7639 items = menus.find( this.options.items );
7640
7641 // Initialize menu-items containing spaces and/or dashes only as dividers
7642 items.not( ".ui-menu-item" ).each( function() {
7643 var item = $( this );
7644 if ( that._isDivider( item ) ) {
7645 that._addClass( item, "ui-menu-divider", "ui-widget-content" );
7646 }
7647 } );
7648
7649 // Don't refresh list items that are already adapted
7650 newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
7651 newWrappers = newItems.children()
7652 .not( ".ui-menu" )
7653 .uniqueId()
7654 .attr( {
7655 tabIndex: -1,
7656 role: this._itemRole()
7657 } );
7658 this._addClass( newItems, "ui-menu-item" )
7659 ._addClass( newWrappers, "ui-menu-item-wrapper" );
7660
7661 // Add aria-disabled attribute to any disabled menu item
7662 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
7663
7664 // If the active item has been removed, blur the menu
7665 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
7666 this.blur();
7667 }
7668 },
7669
7670 _itemRole: function() {
7671 return {
7672 menu: "menuitem",
7673 listbox: "option"
7674 }[ this.options.role ];
7675 },
7676
7677 _setOption: function( key, value ) {
7678 if ( key === "icons" ) {
7679 var icons = this.element.find( ".ui-menu-icon" );
7680 this._removeClass( icons, null, this.options.icons.submenu )
7681 ._addClass( icons, null, value.submenu );
7682 }
7683 this._super( key, value );
7684 },
7685
7686 _setOptionDisabled: function( value ) {
7687 this._super( value );
7688
7689 this.element.attr( "aria-disabled", String( value ) );
7690 this._toggleClass( null, "ui-state-disabled", !!value );
7691 },
7692
7693 focus: function( event, item ) {
7694 var nested, focused, activeParent;
7695 this.blur( event, event && event.type === "focus" );
7696
7697 this._scrollIntoView( item );
7698
7699 this.active = item.first();
7700
7701 focused = this.active.children( ".ui-menu-item-wrapper" );
7702 this._addClass( focused, null, "ui-state-active" );
7703
7704 // Only update aria-activedescendant if there's a role
7705 // otherwise we assume focus is managed elsewhere
7706 if ( this.options.role ) {
7707 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
7708 }
7709
7710 // Highlight active parent menu item, if any
7711 activeParent = this.active
7712 .parent()
7713 .closest( ".ui-menu-item" )
7714 .children( ".ui-menu-item-wrapper" );
7715 this._addClass( activeParent, null, "ui-state-active" );
7716
7717 if ( event && event.type === "keydown" ) {
7718 this._close();
7719 } else {
7720 this.timer = this._delay( function() {
7721 this._close();
7722 }, this.delay );
7723 }
7724
7725 nested = item.children( ".ui-menu" );
7726 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
7727 this._startOpening( nested );
7728 }
7729 this.activeMenu = item.parent();
7730
7731 this._trigger( "focus", event, { item: item } );
7732 },
7733
7734 _scrollIntoView: function( item ) {
7735 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
7736 if ( this._hasScroll() ) {
7737 borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
7738 paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
7739 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
7740 scroll = this.activeMenu.scrollTop();
7741 elementHeight = this.activeMenu.height();
7742 itemHeight = item.outerHeight();
7743
7744 if ( offset < 0 ) {
7745 this.activeMenu.scrollTop( scroll + offset );
7746 } else if ( offset + itemHeight > elementHeight ) {
7747 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
7748 }
7749 }
7750 },
7751
7752 blur: function( event, fromFocus ) {
7753 if ( !fromFocus ) {
7754 clearTimeout( this.timer );
7755 }
7756
7757 if ( !this.active ) {
7758 return;
7759 }
7760
7761 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
7762 null, "ui-state-active" );
7763
7764 this._trigger( "blur", event, { item: this.active } );
7765 this.active = null;
7766 },
7767
7768 _startOpening: function( submenu ) {
7769 clearTimeout( this.timer );
7770
7771 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
7772 // shift in the submenu position when mousing over the caret icon
7773 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
7774 return;
7775 }
7776
7777 this.timer = this._delay( function() {
7778 this._close();
7779 this._open( submenu );
7780 }, this.delay );
7781 },
7782
7783 _open: function( submenu ) {
7784 var position = $.extend( {
7785 of: this.active
7786 }, this.options.position );
7787
7788 clearTimeout( this.timer );
7789 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
7790 .hide()
7791 .attr( "aria-hidden", "true" );
7792
7793 submenu
7794 .show()
7795 .removeAttr( "aria-hidden" )
7796 .attr( "aria-expanded", "true" )
7797 .position( position );
7798 },
7799
7800 collapseAll: function( event, all ) {
7801 clearTimeout( this.timer );
7802 this.timer = this._delay( function() {
7803
7804 // If we were passed an event, look for the submenu that contains the event
7805 var currentMenu = all ? this.element :
7806 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
7807
7808 // If we found no valid submenu ancestor, use the main menu to close all
7809 // sub menus anyway
7810 if ( !currentMenu.length ) {
7811 currentMenu = this.element;
7812 }
7813
7814 this._close( currentMenu );
7815
7816 this.blur( event );
7817
7818 // Work around active item staying active after menu is blurred
7819 this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
7820
7821 this.activeMenu = currentMenu;
7822 }, this.delay );
7823 },
7824
7825 // With no arguments, closes the currently active menu - if nothing is active
7826 // it closes all menus. If passed an argument, it will search for menus BELOW
7827 _close: function( startMenu ) {
7828 if ( !startMenu ) {
7829 startMenu = this.active ? this.active.parent() : this.element;
7830 }
7831
7832 startMenu.find( ".ui-menu" )
7833 .hide()
7834 .attr( "aria-hidden", "true" )
7835 .attr( "aria-expanded", "false" );
7836 },
7837
7838 _closeOnDocumentClick: function( event ) {
7839 return !$( event.target ).closest( ".ui-menu" ).length;
7840 },
7841
7842 _isDivider: function( item ) {
7843
7844 // Match hyphen, em dash, en dash
7845 return !/[^\-\u2014\u2013\s]/.test( item.text() );
7846 },
7847
7848 collapse: function( event ) {
7849 var newItem = this.active &&
7850 this.active.parent().closest( ".ui-menu-item", this.element );
7851 if ( newItem && newItem.length ) {
7852 this._close();
7853 this.focus( event, newItem );
7854 }
7855 },
7856
7857 expand: function( event ) {
7858 var newItem = this.active &&
7859 this.active
7860 .children( ".ui-menu " )
7861 .find( this.options.items )
7862 .first();
7863
7864 if ( newItem && newItem.length ) {
7865 this._open( newItem.parent() );
7866
7867 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
7868 this._delay( function() {
7869 this.focus( event, newItem );
7870 } );
7871 }
7872 },
7873
7874 next: function( event ) {
7875 this._move( "next", "first", event );
7876 },
7877
7878 previous: function( event ) {
7879 this._move( "prev", "last", event );
7880 },
7881
7882 isFirstItem: function() {
7883 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
7884 },
7885
7886 isLastItem: function() {
7887 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
7888 },
7889
7890 _move: function( direction, filter, event ) {
7891 var next;
7892 if ( this.active ) {
7893 if ( direction === "first" || direction === "last" ) {
7894 next = this.active
7895 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
7896 .eq( -1 );
7897 } else {
7898 next = this.active
7899 [ direction + "All" ]( ".ui-menu-item" )
7900 .eq( 0 );
7901 }
7902 }
7903 if ( !next || !next.length || !this.active ) {
7904 next = this.activeMenu.find( this.options.items )[ filter ]();
7905 }
7906
7907 this.focus( event, next );
7908 },
7909
7910 nextPage: function( event ) {
7911 var item, base, height;
7912
7913 if ( !this.active ) {
7914 this.next( event );
7915 return;
7916 }
7917 if ( this.isLastItem() ) {
7918 return;
7919 }
7920 if ( this._hasScroll() ) {
7921 base = this.active.offset().top;
7922 height = this.element.height();
7923 this.active.nextAll( ".ui-menu-item" ).each( function() {
7924 item = $( this );
7925 return item.offset().top - base - height < 0;
7926 } );
7927
7928 this.focus( event, item );
7929 } else {
7930 this.focus( event, this.activeMenu.find( this.options.items )
7931 [ !this.active ? "first" : "last" ]() );
7932 }
7933 },
7934
7935 previousPage: function( event ) {
7936 var item, base, height;
7937 if ( !this.active ) {
7938 this.next( event );
7939 return;
7940 }
7941 if ( this.isFirstItem() ) {
7942 return;
7943 }
7944 if ( this._hasScroll() ) {
7945 base = this.active.offset().top;
7946 height = this.element.height();
7947 this.active.prevAll( ".ui-menu-item" ).each( function() {
7948 item = $( this );
7949 return item.offset().top - base + height > 0;
7950 } );
7951
7952 this.focus( event, item );
7953 } else {
7954 this.focus( event, this.activeMenu.find( this.options.items ).first() );
7955 }
7956 },
7957
7958 _hasScroll: function() {
7959 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
7960 },
7961
7962 select: function( event ) {
7963
7964 // TODO: It should never be possible to not have an active item at this
7965 // point, but the tests don't trigger mouseenter before click.
7966 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
7967 var ui = { item: this.active };
7968 if ( !this.active.has( ".ui-menu" ).length ) {
7969 this.collapseAll( event, true );
7970 }
7971 this._trigger( "select", event, ui );
7972 },
7973
7974 _filterMenuItems: function( character ) {
7975 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
7976 regex = new RegExp( "^" + escapedCharacter, "i" );
7977
7978 return this.activeMenu
7979 .find( this.options.items )
7980
7981 // Only match on items, not dividers or other content (#10571)
7982 .filter( ".ui-menu-item" )
7983 .filter( function() {
7984 return regex.test(
7985 $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
7986 } );
7987 }
7988 } );
7989
7990
7991 /*!
7992 * jQuery UI Autocomplete 1.12.1
7993 * http://jqueryui.com
7994 *
7995 * Copyright jQuery Foundation and other contributors
7996 * Released under the MIT license.
7997 * http://jquery.org/license
7998 */
7999
8000 //>>label: Autocomplete
8001 //>>group: Widgets
8002 //>>description: Lists suggested words as the user is typing.
8003 //>>docs: http://api.jqueryui.com/autocomplete/
8004 //>>demos: http://jqueryui.com/autocomplete/
8005 //>>css.structure: ../../themes/base/core.css
8006 //>>css.structure: ../../themes/base/autocomplete.css
8007 //>>css.theme: ../../themes/base/theme.css
8008
8009
8010
8011 $.widget( "ui.autocomplete", {
8012 version: "1.12.1",
8013 defaultElement: "<input>",
8014 options: {
8015 appendTo: null,
8016 autoFocus: false,
8017 delay: 300,
8018 minLength: 1,
8019 position: {
8020 my: "left top",
8021 at: "left bottom",
8022 collision: "none"
8023 },
8024 source: null,
8025
8026 // Callbacks
8027 change: null,
8028 close: null,
8029 focus: null,
8030 open: null,
8031 response: null,
8032 search: null,
8033 select: null
8034 },
8035
8036 requestIndex: 0,
8037 pending: 0,
8038
8039 _create: function() {
8040
8041 // Some browsers only repeat keydown events, not keypress events,
8042 // so we use the suppressKeyPress flag to determine if we've already
8043 // handled the keydown event. #7269
8044 // Unfortunately the code for & in keypress is the same as the up arrow,
8045 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
8046 // events when we know the keydown event was used to modify the
8047 // search term. #7799
8048 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
8049 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
8050 isTextarea = nodeName === "textarea",
8051 isInput = nodeName === "input";
8052
8053 // Textareas are always multi-line
8054 // Inputs are always single-line, even if inside a contentEditable element
8055 // IE also treats inputs as contentEditable
8056 // All other element types are determined by whether or not they're contentEditable
8057 this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
8058
8059 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
8060 this.isNewMenu = true;
8061
8062 this._addClass( "ui-autocomplete-input" );
8063 this.element.attr( "autocomplete", "off" );
8064
8065 this._on( this.element, {
8066 keydown: function( event ) {
8067 if ( this.element.prop( "readOnly" ) ) {
8068 suppressKeyPress = true;
8069 suppressInput = true;
8070 suppressKeyPressRepeat = true;
8071 return;
8072 }
8073
8074 suppressKeyPress = false;
8075 suppressInput = false;
8076 suppressKeyPressRepeat = false;
8077 var keyCode = $.ui.keyCode;
8078 switch ( event.keyCode ) {
8079 case keyCode.PAGE_UP:
8080 suppressKeyPress = true;
8081 this._move( "previousPage", event );
8082 break;
8083 case keyCode.PAGE_DOWN:
8084 suppressKeyPress = true;
8085 this._move( "nextPage", event );
8086 break;
8087 case keyCode.UP:
8088 suppressKeyPress = true;
8089 this._keyEvent( "previous", event );
8090 break;
8091 case keyCode.DOWN:
8092 suppressKeyPress = true;
8093 this._keyEvent( "next", event );
8094 break;
8095 case keyCode.ENTER:
8096
8097 // when menu is open and has focus
8098 if ( this.menu.active ) {
8099
8100 // #6055 - Opera still allows the keypress to occur
8101 // which causes forms to submit
8102 suppressKeyPress = true;
8103 event.preventDefault();
8104 this.menu.select( event );
8105 }
8106 break;
8107 case keyCode.TAB:
8108 if ( this.menu.active ) {
8109 this.menu.select( event );
8110 }
8111 break;
8112 case keyCode.ESCAPE:
8113 if ( this.menu.element.is( ":visible" ) ) {
8114 if ( !this.isMultiLine ) {
8115 this._value( this.term );
8116 }
8117 this.close( event );
8118
8119 // Different browsers have different default behavior for escape
8120 // Single press can mean undo or clear
8121 // Double press in IE means clear the whole form
8122 event.preventDefault();
8123 }
8124 break;
8125 default:
8126 suppressKeyPressRepeat = true;
8127
8128 // search timeout should be triggered before the input value is changed
8129 this._searchTimeout( event );
8130 break;
8131 }
8132 },
8133 keypress: function( event ) {
8134 if ( suppressKeyPress ) {
8135 suppressKeyPress = false;
8136 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
8137 event.preventDefault();
8138 }
8139 return;
8140 }
8141 if ( suppressKeyPressRepeat ) {
8142 return;
8143 }
8144
8145 // Replicate some key handlers to allow them to repeat in Firefox and Opera
8146 var keyCode = $.ui.keyCode;
8147 switch ( event.keyCode ) {
8148 case keyCode.PAGE_UP:
8149 this._move( "previousPage", event );
8150 break;
8151 case keyCode.PAGE_DOWN:
8152 this._move( "nextPage", event );
8153 break;
8154 case keyCode.UP:
8155 this._keyEvent( "previous", event );
8156 break;
8157 case keyCode.DOWN:
8158 this._keyEvent( "next", event );
8159 break;
8160 }
8161 },
8162 input: function( event ) {
8163 if ( suppressInput ) {
8164 suppressInput = false;
8165 event.preventDefault();
8166 return;
8167 }
8168 this._searchTimeout( event );
8169 },
8170 focus: function() {
8171 this.selectedItem = null;
8172 this.previous = this._value();
8173 },
8174 blur: function( event ) {
8175 if ( this.cancelBlur ) {
8176 delete this.cancelBlur;
8177 return;
8178 }
8179
8180 clearTimeout( this.searching );
8181 this.close( event );
8182 this._change( event );
8183 }
8184 } );
8185
8186 this._initSource();
8187 this.menu = $( "<ul>" )
8188 .appendTo( this._appendTo() )
8189 .menu( {
8190
8191 // disable ARIA support, the live region takes care of that
8192 role: null
8193 } )
8194 .hide()
8195 .menu( "instance" );
8196
8197 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
8198 this._on( this.menu.element, {
8199 mousedown: function( event ) {
8200
8201 // prevent moving focus out of the text field
8202 event.preventDefault();
8203
8204 // IE doesn't prevent moving focus even with event.preventDefault()
8205 // so we set a flag to know when we should ignore the blur event
8206 this.cancelBlur = true;
8207 this._delay( function() {
8208 delete this.cancelBlur;
8209
8210 // Support: IE 8 only
8211 // Right clicking a menu item or selecting text from the menu items will
8212 // result in focus moving out of the input. However, we've already received
8213 // and ignored the blur event because of the cancelBlur flag set above. So
8214 // we restore focus to ensure that the menu closes properly based on the user's
8215 // next actions.
8216 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
8217 this.element.trigger( "focus" );
8218 }
8219 } );
8220 },
8221 menufocus: function( event, ui ) {
8222 var label, item;
8223
8224 // support: Firefox
8225 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
8226 if ( this.isNewMenu ) {
8227 this.isNewMenu = false;
8228 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
8229 this.menu.blur();
8230
8231 this.document.one( "mousemove", function() {
8232 $( event.target ).trigger( event.originalEvent );
8233 } );
8234
8235 return;
8236 }
8237 }
8238
8239 item = ui.item.data( "ui-autocomplete-item" );
8240 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
8241
8242 // use value to match what will end up in the input, if it was a key event
8243 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
8244 this._value( item.value );
8245 }
8246 }
8247
8248 // Announce the value in the liveRegion
8249 label = ui.item.attr( "aria-label" ) || item.value;
8250 if ( label && $.trim( label ).length ) {
8251 this.liveRegion.children().hide();
8252 $( "<div>" ).text( label ).appendTo( this.liveRegion );
8253 }
8254 },
8255 menuselect: function( event, ui ) {
8256 var item = ui.item.data( "ui-autocomplete-item" ),
8257 previous = this.previous;
8258
8259 // Only trigger when focus was lost (click on menu)
8260 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
8261 this.element.trigger( "focus" );
8262 this.previous = previous;
8263
8264 // #6109 - IE triggers two focus events and the second
8265 // is asynchronous, so we need to reset the previous
8266 // term synchronously and asynchronously :-(
8267 this._delay( function() {
8268 this.previous = previous;
8269 this.selectedItem = item;
8270 } );
8271 }
8272
8273 if ( false !== this._trigger( "select", event, { item: item } ) ) {
8274 this._value( item.value );
8275 }
8276
8277 // reset the term after the select event
8278 // this allows custom select handling to work properly
8279 this.term = this._value();
8280
8281 this.close( event );
8282 this.selectedItem = item;
8283 }
8284 } );
8285
8286 this.liveRegion = $( "<div>", {
8287 role: "status",
8288 "aria-live": "assertive",
8289 "aria-relevant": "additions"
8290 } )
8291 .appendTo( this.document[ 0 ].body );
8292
8293 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
8294
8295 // Turning off autocomplete prevents the browser from remembering the
8296 // value when navigating through history, so we re-enable autocomplete
8297 // if the page is unloaded before the widget is destroyed. #7790
8298 this._on( this.window, {
8299 beforeunload: function() {
8300 this.element.removeAttr( "autocomplete" );
8301 }
8302 } );
8303 },
8304
8305 _destroy: function() {
8306 clearTimeout( this.searching );
8307 this.element.removeAttr( "autocomplete" );
8308 this.menu.element.remove();
8309 this.liveRegion.remove();
8310 },
8311
8312 _setOption: function( key, value ) {
8313 this._super( key, value );
8314 if ( key === "source" ) {
8315 this._initSource();
8316 }
8317 if ( key === "appendTo" ) {
8318 this.menu.element.appendTo( this._appendTo() );
8319 }
8320 if ( key === "disabled" && value && this.xhr ) {
8321 this.xhr.abort();
8322 }
8323 },
8324
8325 _isEventTargetInWidget: function( event ) {
8326 var menuElement = this.menu.element[ 0 ];
8327
8328 return event.target === this.element[ 0 ] ||
8329 event.target === menuElement ||
8330 $.contains( menuElement, event.target );
8331 },
8332
8333 _closeOnClickOutside: function( event ) {
8334 if ( !this._isEventTargetInWidget( event ) ) {
8335 this.close();
8336 }
8337 },
8338
8339 _appendTo: function() {
8340 var element = this.options.appendTo;
8341
8342 if ( element ) {
8343 element = element.jquery || element.nodeType ?
8344 $( element ) :
8345 this.document.find( element ).eq( 0 );
8346 }
8347
8348 if ( !element || !element[ 0 ] ) {
8349 element = this.element.closest( ".ui-front, dialog" );
8350 }
8351
8352 if ( !element.length ) {
8353 element = this.document[ 0 ].body;
8354 }
8355
8356 return element;
8357 },
8358
8359 _initSource: function() {
8360 var array, url,
8361 that = this;
8362 if ( $.isArray( this.options.source ) ) {
8363 array = this.options.source;
8364 this.source = function( request, response ) {
8365 response( $.ui.autocomplete.filter( array, request.term ) );
8366 };
8367 } else if ( typeof this.options.source === "string" ) {
8368 url = this.options.source;
8369 this.source = function( request, response ) {
8370 if ( that.xhr ) {
8371 that.xhr.abort();
8372 }
8373 that.xhr = $.ajax( {
8374 url: url,
8375 data: request,
8376 dataType: "json",
8377 success: function( data ) {
8378 response( data );
8379 },
8380 error: function() {
8381 response( [] );
8382 }
8383 } );
8384 };
8385 } else {
8386 this.source = this.options.source;
8387 }
8388 },
8389
8390 _searchTimeout: function( event ) {
8391 clearTimeout( this.searching );
8392 this.searching = this._delay( function() {
8393
8394 // Search if the value has changed, or if the user retypes the same value (see #7434)
8395 var equalValues = this.term === this._value(),
8396 menuVisible = this.menu.element.is( ":visible" ),
8397 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
8398
8399 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
8400 this.selectedItem = null;
8401 this.search( null, event );
8402 }
8403 }, this.options.delay );
8404 },
8405
8406 search: function( value, event ) {
8407 value = value != null ? value : this._value();
8408
8409 // Always save the actual value, not the one passed as an argument
8410 this.term = this._value();
8411
8412 if ( value.length < this.options.minLength ) {
8413 return this.close( event );
8414 }
8415
8416 if ( this._trigger( "search", event ) === false ) {
8417 return;
8418 }
8419
8420 return this._search( value );
8421 },
8422
8423 _search: function( value ) {
8424 this.pending++;
8425 this._addClass( "ui-autocomplete-loading" );
8426 this.cancelSearch = false;
8427
8428 this.source( { term: value }, this._response() );
8429 },
8430
8431 _response: function() {
8432 var index = ++this.requestIndex;
8433
8434 return $.proxy( function( content ) {
8435 if ( index === this.requestIndex ) {
8436 this.__response( content );
8437 }
8438
8439 this.pending--;
8440 if ( !this.pending ) {
8441 this._removeClass( "ui-autocomplete-loading" );
8442 }
8443 }, this );
8444 },
8445
8446 __response: function( content ) {
8447 if ( content ) {
8448 content = this._normalize( content );
8449 }
8450 this._trigger( "response", null, { content: content } );
8451 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
8452 this._suggest( content );
8453 this._trigger( "open" );
8454 } else {
8455
8456 // use ._close() instead of .close() so we don't cancel future searches
8457 this._close();
8458 }
8459 },
8460
8461 close: function( event ) {
8462 this.cancelSearch = true;
8463 this._close( event );
8464 },
8465
8466 _close: function( event ) {
8467
8468 // Remove the handler that closes the menu on outside clicks
8469 this._off( this.document, "mousedown" );
8470
8471 if ( this.menu.element.is( ":visible" ) ) {
8472 this.menu.element.hide();
8473 this.menu.blur();
8474 this.isNewMenu = true;
8475 this._trigger( "close", event );
8476 }
8477 },
8478
8479 _change: function( event ) {
8480 if ( this.previous !== this._value() ) {
8481 this._trigger( "change", event, { item: this.selectedItem } );
8482 }
8483 },
8484
8485 _normalize: function( items ) {
8486
8487 // assume all items have the right format when the first item is complete
8488 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
8489 return items;
8490 }
8491 return $.map( items, function( item ) {
8492 if ( typeof item === "string" ) {
8493 return {
8494 label: item,
8495 value: item
8496 };
8497 }
8498 return $.extend( {}, item, {
8499 label: item.label || item.value,
8500 value: item.value || item.label
8501 } );
8502 } );
8503 },
8504
8505 _suggest: function( items ) {
8506 var ul = this.menu.element.empty();
8507 this._renderMenu( ul, items );
8508 this.isNewMenu = true;
8509 this.menu.refresh();
8510
8511 // Size and position menu
8512 ul.show();
8513 this._resizeMenu();
8514 ul.position( $.extend( {
8515 of: this.element
8516 }, this.options.position ) );
8517
8518 if ( this.options.autoFocus ) {
8519 this.menu.next();
8520 }
8521
8522 // Listen for interactions outside of the widget (#6642)
8523 this._on( this.document, {
8524 mousedown: "_closeOnClickOutside"
8525 } );
8526 },
8527
8528 _resizeMenu: function() {
8529 var ul = this.menu.element;
8530 ul.outerWidth( Math.max(
8531
8532 // Firefox wraps long text (possibly a rounding bug)
8533 // so we add 1px to avoid the wrapping (#7513)
8534 ul.width( "" ).outerWidth() + 1,
8535 this.element.outerWidth()
8536 ) );
8537 },
8538
8539 _renderMenu: function( ul, items ) {
8540 var that = this;
8541 $.each( items, function( index, item ) {
8542 that._renderItemData( ul, item );
8543 } );
8544 },
8545
8546 _renderItemData: function( ul, item ) {
8547 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
8548 },
8549
8550 _renderItem: function( ul, item ) {
8551 return $( "<li>" )
8552 .append( $( "<div>" ).text( item.label ) )
8553 .appendTo( ul );
8554 },
8555
8556 _move: function( direction, event ) {
8557 if ( !this.menu.element.is( ":visible" ) ) {
8558 this.search( null, event );
8559 return;
8560 }
8561 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
8562 this.menu.isLastItem() && /^next/.test( direction ) ) {
8563
8564 if ( !this.isMultiLine ) {
8565 this._value( this.term );
8566 }
8567
8568 this.menu.blur();
8569 return;
8570 }
8571 this.menu[ direction ]( event );
8572 },
8573
8574 widget: function() {
8575 return this.menu.element;
8576 },
8577
8578 _value: function() {
8579 return this.valueMethod.apply( this.element, arguments );
8580 },
8581
8582 _keyEvent: function( keyEvent, event ) {
8583 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
8584 this._move( keyEvent, event );
8585
8586 // Prevents moving cursor to beginning/end of the text field in some browsers
8587 event.preventDefault();
8588 }
8589 },
8590
8591 // Support: Chrome <=50
8592 // We should be able to just use this.element.prop( "isContentEditable" )
8593 // but hidden elements always report false in Chrome.
8594 // https://code.google.com/p/chromium/issues/detail?id=313082
8595 _isContentEditable: function( element ) {
8596 if ( !element.length ) {
8597 return false;
8598 }
8599
8600 var editable = element.prop( "contentEditable" );
8601
8602 if ( editable === "inherit" ) {
8603 return this._isContentEditable( element.parent() );
8604 }
8605
8606 return editable === "true";
8607 }
8608 } );
8609
8610 $.extend( $.ui.autocomplete, {
8611 escapeRegex: function( value ) {
8612 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
8613 },
8614 filter: function( array, term ) {
8615 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
8616 return $.grep( array, function( value ) {
8617 return matcher.test( value.label || value.value || value );
8618 } );
8619 }
8620 } );
8621
8622 // Live region extension, adding a `messages` option
8623 // NOTE: This is an experimental API. We are still investigating
8624 // a full solution for string manipulation and internationalization.
8625 $.widget( "ui.autocomplete", $.ui.autocomplete, {
8626 options: {
8627 messages: {
8628 noResults: "No search results.",
8629 results: function( amount ) {
8630 return amount + ( amount > 1 ? " results are" : " result is" ) +
8631 " available, use up and down arrow keys to navigate.";
8632 }
8633 }
8634 },
8635
8636 __response: function( content ) {
8637 var message;
8638 this._superApply( arguments );
8639 if ( this.options.disabled || this.cancelSearch ) {
8640 return;
8641 }
8642 if ( content && content.length ) {
8643 message = this.options.messages.results( content.length );
8644 } else {
8645 message = this.options.messages.noResults;
8646 }
8647 this.liveRegion.children().hide();
8648 $( "<div>" ).text( message ).appendTo( this.liveRegion );
8649 }
8650 } );
8651
8652 var widgetsAutocomplete = $.ui.autocomplete;
8653
8654
8655 /*!
8656 * jQuery UI Controlgroup 1.12.1
8657 * http://jqueryui.com
8658 *
8659 * Copyright jQuery Foundation and other contributors
8660 * Released under the MIT license.
8661 * http://jquery.org/license
8662 */
8663
8664 //>>label: Controlgroup
8665 //>>group: Widgets
8666 //>>description: Visually groups form control widgets
8667 //>>docs: http://api.jqueryui.com/controlgroup/
8668 //>>demos: http://jqueryui.com/controlgroup/
8669 //>>css.structure: ../../themes/base/core.css
8670 //>>css.structure: ../../themes/base/controlgroup.css
8671 //>>css.theme: ../../themes/base/theme.css
8672
8673
8674 var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
8675
8676 var widgetsControlgroup = $.widget( "ui.controlgroup", {
8677 version: "1.12.1",
8678 defaultElement: "<div>",
8679 options: {
8680 direction: "horizontal",
8681 disabled: null,
8682 onlyVisible: true,
8683 items: {
8684 "button": "input[type=button], input[type=submit], input[type=reset], button, a",
8685 "controlgroupLabel": ".ui-controlgroup-label",
8686 "checkboxradio": "input[type='checkbox'], input[type='radio']",
8687 "selectmenu": "select",
8688 "spinner": ".ui-spinner-input"
8689 }
8690 },
8691
8692 _create: function() {
8693 this._enhance();
8694 },
8695
8696 // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
8697 _enhance: function() {
8698 this.element.attr( "role", "toolbar" );
8699 this.refresh();
8700 },
8701
8702 _destroy: function() {
8703 this._callChildMethod( "destroy" );
8704 this.childWidgets.removeData( "ui-controlgroup-data" );
8705 this.element.removeAttr( "role" );
8706 if ( this.options.items.controlgroupLabel ) {
8707 this.element
8708 .find( this.options.items.controlgroupLabel )
8709 .find( ".ui-controlgroup-label-contents" )
8710 .contents().unwrap();
8711 }
8712 },
8713
8714 _initWidgets: function() {
8715 var that = this,
8716 childWidgets = [];
8717
8718 // First we iterate over each of the items options
8719 $.each( this.options.items, function( widget, selector ) {
8720 var labels;
8721 var options = {};
8722
8723 // Make sure the widget has a selector set
8724 if ( !selector ) {
8725 return;
8726 }
8727
8728 if ( widget === "controlgroupLabel" ) {
8729 labels = that.element.find( selector );
8730 labels.each( function() {
8731 var element = $( this );
8732
8733 if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
8734 return;
8735 }
8736 element.contents()
8737 .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
8738 } );
8739 that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
8740 childWidgets = childWidgets.concat( labels.get() );
8741 return;
8742 }
8743
8744 // Make sure the widget actually exists
8745 if ( !$.fn[ widget ] ) {
8746 return;
8747 }
8748
8749 // We assume everything is in the middle to start because we can't determine
8750 // first / last elements until all enhancments are done.
8751 if ( that[ "_" + widget + "Options" ] ) {
8752 options = that[ "_" + widget + "Options" ]( "middle" );
8753 } else {
8754 options = { classes: {} };
8755 }
8756
8757 // Find instances of this widget inside controlgroup and init them
8758 that.element
8759 .find( selector )
8760 .each( function() {
8761 var element = $( this );
8762 var instance = element[ widget ]( "instance" );
8763
8764 // We need to clone the default options for this type of widget to avoid
8765 // polluting the variable options which has a wider scope than a single widget.
8766 var instanceOptions = $.widget.extend( {}, options );
8767
8768 // If the button is the child of a spinner ignore it
8769 // TODO: Find a more generic solution
8770 if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
8771 return;
8772 }
8773
8774 // Create the widget if it doesn't exist
8775 if ( !instance ) {
8776 instance = element[ widget ]()[ widget ]( "instance" );
8777 }
8778 if ( instance ) {
8779 instanceOptions.classes =
8780 that._resolveClassesValues( instanceOptions.classes, instance );
8781 }
8782 element[ widget ]( instanceOptions );
8783
8784 // Store an instance of the controlgroup to be able to reference
8785 // from the outermost element for changing options and refresh
8786 var widgetElement = element[ widget ]( "widget" );
8787 $.data( widgetElement[ 0 ], "ui-controlgroup-data",
8788 instance ? instance : element[ widget ]( "instance" ) );
8789
8790 childWidgets.push( widgetElement[ 0 ] );
8791 } );
8792 } );
8793
8794 this.childWidgets = $( $.unique( childWidgets ) );
8795 this._addClass( this.childWidgets, "ui-controlgroup-item" );
8796 },
8797
8798 _callChildMethod: function( method ) {
8799 this.childWidgets.each( function() {
8800 var element = $( this ),
8801 data = element.data( "ui-controlgroup-data" );
8802 if ( data && data[ method ] ) {
8803 data[ method ]();
8804 }
8805 } );
8806 },
8807
8808 _updateCornerClass: function( element, position ) {
8809 var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
8810 var add = this._buildSimpleOptions( position, "label" ).classes.label;
8811
8812 this._removeClass( element, null, remove );
8813 this._addClass( element, null, add );
8814 },
8815
8816 _buildSimpleOptions: function( position, key ) {
8817 var direction = this.options.direction === "vertical";
8818 var result = {
8819 classes: {}
8820 };
8821 result.classes[ key ] = {
8822 "middle": "",
8823 "first": "ui-corner-" + ( direction ? "top" : "left" ),
8824 "last": "ui-corner-" + ( direction ? "bottom" : "right" ),
8825 "only": "ui-corner-all"
8826 }[ position ];
8827
8828 return result;
8829 },
8830
8831 _spinnerOptions: function( position ) {
8832 var options = this._buildSimpleOptions( position, "ui-spinner" );
8833
8834 options.classes[ "ui-spinner-up" ] = "";
8835 options.classes[ "ui-spinner-down" ] = "";
8836
8837 return options;
8838 },
8839
8840 _buttonOptions: function( position ) {
8841 return this._buildSimpleOptions( position, "ui-button" );
8842 },
8843
8844 _checkboxradioOptions: function( position ) {
8845 return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
8846 },
8847
8848 _selectmenuOptions: function( position ) {
8849 var direction = this.options.direction === "vertical";
8850 return {
8851 width: direction ? "auto" : false,
8852 classes: {
8853 middle: {
8854 "ui-selectmenu-button-open": "",
8855 "ui-selectmenu-button-closed": ""
8856 },
8857 first: {
8858 "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
8859 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
8860 },
8861 last: {
8862 "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
8863 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
8864 },
8865 only: {
8866 "ui-selectmenu-button-open": "ui-corner-top",
8867 "ui-selectmenu-button-closed": "ui-corner-all"
8868 }
8869
8870 }[ position ]
8871 };
8872 },
8873
8874 _resolveClassesValues: function( classes, instance ) {
8875 var result = {};
8876 $.each( classes, function( key ) {
8877 var current = instance.options.classes[ key ] || "";
8878 current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
8879 result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
8880 } );
8881 return result;
8882 },
8883
8884 _setOption: function( key, value ) {
8885 if ( key === "direction" ) {
8886 this._removeClass( "ui-controlgroup-" + this.options.direction );
8887 }
8888
8889 this._super( key, value );
8890 if ( key === "disabled" ) {
8891 this._callChildMethod( value ? "disable" : "enable" );
8892 return;
8893 }
8894
8895 this.refresh();
8896 },
8897
8898 refresh: function() {
8899 var children,
8900 that = this;
8901
8902 this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
8903
8904 if ( this.options.direction === "horizontal" ) {
8905 this._addClass( null, "ui-helper-clearfix" );
8906 }
8907 this._initWidgets();
8908
8909 children = this.childWidgets;
8910
8911 // We filter here because we need to track all childWidgets not just the visible ones
8912 if ( this.options.onlyVisible ) {
8913 children = children.filter( ":visible" );
8914 }
8915
8916 if ( children.length ) {
8917
8918 // We do this last because we need to make sure all enhancment is done
8919 // before determining first and last
8920 $.each( [ "first", "last" ], function( index, value ) {
8921 var instance = children[ value ]().data( "ui-controlgroup-data" );
8922
8923 if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
8924 var options = that[ "_" + instance.widgetName + "Options" ](
8925 children.length === 1 ? "only" : value
8926 );
8927 options.classes = that._resolveClassesValues( options.classes, instance );
8928 instance.element[ instance.widgetName ]( options );
8929 } else {
8930 that._updateCornerClass( children[ value ](), value );
8931 }
8932 } );
8933
8934 // Finally call the refresh method on each of the child widgets.
8935 this._callChildMethod( "refresh" );
8936 }
8937 }
8938 } );
8939
8940 /*!
8941 * jQuery UI Checkboxradio 1.12.1
8942 * http://jqueryui.com
8943 *
8944 * Copyright jQuery Foundation and other contributors
8945 * Released under the MIT license.
8946 * http://jquery.org/license
8947 */
8948
8949 //>>label: Checkboxradio
8950 //>>group: Widgets
8951 //>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
8952 //>>docs: http://api.jqueryui.com/checkboxradio/
8953 //>>demos: http://jqueryui.com/checkboxradio/
8954 //>>css.structure: ../../themes/base/core.css
8955 //>>css.structure: ../../themes/base/button.css
8956 //>>css.structure: ../../themes/base/checkboxradio.css
8957 //>>css.theme: ../../themes/base/theme.css
8958
8959
8960
8961 $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
8962 version: "1.12.1",
8963 options: {
8964 disabled: null,
8965 label: null,
8966 icon: true,
8967 classes: {
8968 "ui-checkboxradio-label": "ui-corner-all",
8969 "ui-checkboxradio-icon": "ui-corner-all"
8970 }
8971 },
8972
8973 _getCreateOptions: function() {
8974 var disabled, labels;
8975 var that = this;
8976 var options = this._super() || {};
8977
8978 // We read the type here, because it makes more sense to throw a element type error first,
8979 // rather then the error for lack of a label. Often if its the wrong type, it
8980 // won't have a label (e.g. calling on a div, btn, etc)
8981 this._readType();
8982
8983 labels = this.element.labels();
8984
8985 // If there are multiple labels, use the last one
8986 this.label = $( labels[ labels.length - 1 ] );
8987 if ( !this.label.length ) {
8988 $.error( "No label found for checkboxradio widget" );
8989 }
8990
8991 this.originalLabel = "";
8992
8993 // We need to get the label text but this may also need to make sure it does not contain the
8994 // input itself.
8995 this.label.contents().not( this.element[ 0 ] ).each( function() {
8996
8997 // The label contents could be text, html, or a mix. We concat each element to get a
8998 // string representation of the label, without the input as part of it.
8999 that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
9000 } );
9001
9002 // Set the label option if we found label text
9003 if ( this.originalLabel ) {
9004 options.label = this.originalLabel;
9005 }
9006
9007 disabled = this.element[ 0 ].disabled;
9008 if ( disabled != null ) {
9009 options.disabled = disabled;
9010 }
9011 return options;
9012 },
9013
9014 _create: function() {
9015 var checked = this.element[ 0 ].checked;
9016
9017 this._bindFormResetHandler();
9018
9019 if ( this.options.disabled == null ) {
9020 this.options.disabled = this.element[ 0 ].disabled;
9021 }
9022
9023 this._setOption( "disabled", this.options.disabled );
9024 this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
9025 this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
9026
9027 if ( this.type === "radio" ) {
9028 this._addClass( this.label, "ui-checkboxradio-radio-label" );
9029 }
9030
9031 if ( this.options.label && this.options.label !== this.originalLabel ) {
9032 this._updateLabel();
9033 } else if ( this.originalLabel ) {
9034 this.options.label = this.originalLabel;
9035 }
9036
9037 this._enhance();
9038
9039 if ( checked ) {
9040 this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
9041 if ( this.icon ) {
9042 this._addClass( this.icon, null, "ui-state-hover" );
9043 }
9044 }
9045
9046 this._on( {
9047 change: "_toggleClasses",
9048 focus: function() {
9049 this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
9050 },
9051 blur: function() {
9052 this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
9053 }
9054 } );
9055 },
9056
9057 _readType: function() {
9058 var nodeName = this.element[ 0 ].nodeName.toLowerCase();
9059 this.type = this.element[ 0 ].type;
9060 if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
9061 $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
9062 " and element.type=" + this.type );
9063 }
9064 },
9065
9066 // Support jQuery Mobile enhanced option
9067 _enhance: function() {
9068 this._updateIcon( this.element[ 0 ].checked );
9069 },
9070
9071 widget: function() {
9072 return this.label;
9073 },
9074
9075 _getRadioGroup: function() {
9076 var group;
9077 var name = this.element[ 0 ].name;
9078 var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
9079
9080 if ( !name ) {
9081 return $( [] );
9082 }
9083
9084 if ( this.form.length ) {
9085 group = $( this.form[ 0 ].elements ).filter( nameSelector );
9086 } else {
9087
9088 // Not inside a form, check all inputs that also are not inside a form
9089 group = $( nameSelector ).filter( function() {
9090 return $( this ).form().length === 0;
9091 } );
9092 }
9093
9094 return group.not( this.element );
9095 },
9096
9097 _toggleClasses: function() {
9098 var checked = this.element[ 0 ].checked;
9099 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
9100
9101 if ( this.options.icon && this.type === "checkbox" ) {
9102 this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
9103 ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
9104 }
9105
9106 if ( this.type === "radio" ) {
9107 this._getRadioGroup()
9108 .each( function() {
9109 var instance = $( this ).checkboxradio( "instance" );
9110
9111 if ( instance ) {
9112 instance._removeClass( instance.label,
9113 "ui-checkboxradio-checked", "ui-state-active" );
9114 }
9115 } );
9116 }
9117 },
9118
9119 _destroy: function() {
9120 this._unbindFormResetHandler();
9121
9122 if ( this.icon ) {
9123 this.icon.remove();
9124 this.iconSpace.remove();
9125 }
9126 },
9127
9128 _setOption: function( key, value ) {
9129
9130 // We don't allow the value to be set to nothing
9131 if ( key === "label" && !value ) {
9132 return;
9133 }
9134
9135 this._super( key, value );
9136
9137 if ( key === "disabled" ) {
9138 this._toggleClass( this.label, null, "ui-state-disabled", value );
9139 this.element[ 0 ].disabled = value;
9140
9141 // Don't refresh when setting disabled
9142 return;
9143 }
9144 this.refresh();
9145 },
9146
9147 _updateIcon: function( checked ) {
9148 var toAdd = "ui-icon ui-icon-background ";
9149
9150 if ( this.options.icon ) {
9151 if ( !this.icon ) {
9152 this.icon = $( "<span>" );
9153 this.iconSpace = $( "<span> </span>" );
9154 this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
9155 }
9156
9157 if ( this.type === "checkbox" ) {
9158 toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
9159 this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
9160 } else {
9161 toAdd += "ui-icon-blank";
9162 }
9163 this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
9164 if ( !checked ) {
9165 this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
9166 }
9167 this.icon.prependTo( this.label ).after( this.iconSpace );
9168 } else if ( this.icon !== undefined ) {
9169 this.icon.remove();
9170 this.iconSpace.remove();
9171 delete this.icon;
9172 }
9173 },
9174
9175 _updateLabel: function() {
9176
9177 // Remove the contents of the label ( minus the icon, icon space, and input )
9178 var contents = this.label.contents().not( this.element[ 0 ] );
9179 if ( this.icon ) {
9180 contents = contents.not( this.icon[ 0 ] );
9181 }
9182 if ( this.iconSpace ) {
9183 contents = contents.not( this.iconSpace[ 0 ] );
9184 }
9185 contents.remove();
9186
9187 this.label.append( this.options.label );
9188 },
9189
9190 refresh: function() {
9191 var checked = this.element[ 0 ].checked,
9192 isDisabled = this.element[ 0 ].disabled;
9193
9194 this._updateIcon( checked );
9195 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
9196 if ( this.options.label !== null ) {
9197 this._updateLabel();
9198 }
9199
9200 if ( isDisabled !== this.options.disabled ) {
9201 this._setOptions( { "disabled": isDisabled } );
9202 }
9203 }
9204
9205 } ] );
9206
9207 var widgetsCheckboxradio = $.ui.checkboxradio;
9208
9209
9210 /*!
9211 * jQuery UI Button 1.12.1
9212 * http://jqueryui.com
9213 *
9214 * Copyright jQuery Foundation and other contributors
9215 * Released under the MIT license.
9216 * http://jquery.org/license
9217 */
9218
9219 //>>label: Button
9220 //>>group: Widgets
9221 //>>description: Enhances a form with themeable buttons.
9222 //>>docs: http://api.jqueryui.com/button/
9223 //>>demos: http://jqueryui.com/button/
9224 //>>css.structure: ../../themes/base/core.css
9225 //>>css.structure: ../../themes/base/button.css
9226 //>>css.theme: ../../themes/base/theme.css
9227
9228
9229
9230 $.widget( "ui.button", {
9231 version: "1.12.1",
9232 defaultElement: "<button>",
9233 options: {
9234 classes: {
9235 "ui-button": "ui-corner-all"
9236 },
9237 disabled: null,
9238 icon: null,
9239 iconPosition: "beginning",
9240 label: null,
9241 showLabel: true
9242 },
9243
9244 _getCreateOptions: function() {
9245 var disabled,
9246
9247 // This is to support cases like in jQuery Mobile where the base widget does have
9248 // an implementation of _getCreateOptions
9249 options = this._super() || {};
9250
9251 this.isInput = this.element.is( "input" );
9252
9253 disabled = this.element[ 0 ].disabled;
9254 if ( disabled != null ) {
9255 options.disabled = disabled;
9256 }
9257
9258 this.originalLabel = this.isInput ? this.element.val() : this.element.html();
9259 if ( this.originalLabel ) {
9260 options.label = this.originalLabel;
9261 }
9262
9263 return options;
9264 },
9265
9266 _create: function() {
9267 if ( !this.option.showLabel & !this.options.icon ) {
9268 this.options.showLabel = true;
9269 }
9270
9271 // We have to check the option again here even though we did in _getCreateOptions,
9272 // because null may have been passed on init which would override what was set in
9273 // _getCreateOptions
9274 if ( this.options.disabled == null ) {
9275 this.options.disabled = this.element[ 0 ].disabled || false;
9276 }
9277
9278 this.hasTitle = !!this.element.attr( "title" );
9279
9280 // Check to see if the label needs to be set or if its already correct
9281 if ( this.options.label && this.options.label !== this.originalLabel ) {
9282 if ( this.isInput ) {
9283 this.element.val( this.options.label );
9284 } else {
9285 this.element.html( this.options.label );
9286 }
9287 }
9288 this._addClass( "ui-button", "ui-widget" );
9289 this._setOption( "disabled", this.options.disabled );
9290 this._enhance();
9291
9292 if ( this.element.is( "a" ) ) {
9293 this._on( {
9294 "keyup": function( event ) {
9295 if ( event.keyCode === $.ui.keyCode.SPACE ) {
9296 event.preventDefault();
9297
9298 // Support: PhantomJS <= 1.9, IE 8 Only
9299 // If a native click is available use it so we actually cause navigation
9300 // otherwise just trigger a click event
9301 if ( this.element[ 0 ].click ) {
9302 this.element[ 0 ].click();
9303 } else {
9304 this.element.trigger( "click" );
9305 }
9306 }
9307 }
9308 } );
9309 }
9310 },
9311
9312 _enhance: function() {
9313 if ( !this.element.is( "button" ) ) {
9314 this.element.attr( "role", "button" );
9315 }
9316
9317 if ( this.options.icon ) {
9318 this._updateIcon( "icon", this.options.icon );
9319 this._updateTooltip();
9320 }
9321 },
9322
9323 _updateTooltip: function() {
9324 this.title = this.element.attr( "title" );
9325
9326 if ( !this.options.showLabel && !this.title ) {
9327 this.element.attr( "title", this.options.label );
9328 }
9329 },
9330
9331 _updateIcon: function( option, value ) {
9332 var icon = option !== "iconPosition",
9333 position = icon ? this.options.iconPosition : value,
9334 displayBlock = position === "top" || position === "bottom";
9335
9336 // Create icon
9337 if ( !this.icon ) {
9338 this.icon = $( "<span>" );
9339
9340 this._addClass( this.icon, "ui-button-icon", "ui-icon" );
9341
9342 if ( !this.options.showLabel ) {
9343 this._addClass( "ui-button-icon-only" );
9344 }
9345 } else if ( icon ) {
9346
9347 // If we are updating the icon remove the old icon class
9348 this._removeClass( this.icon, null, this.options.icon );
9349 }
9350
9351 // If we are updating the icon add the new icon class
9352 if ( icon ) {
9353 this._addClass( this.icon, null, value );
9354 }
9355
9356 this._attachIcon( position );
9357
9358 // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
9359 // the iconSpace if there is one.
9360 if ( displayBlock ) {
9361 this._addClass( this.icon, null, "ui-widget-icon-block" );
9362 if ( this.iconSpace ) {
9363 this.iconSpace.remove();
9364 }
9365 } else {
9366
9367 // Position is beginning or end so remove the ui-widget-icon-block class and add the
9368 // space if it does not exist
9369 if ( !this.iconSpace ) {
9370 this.iconSpace = $( "<span> </span>" );
9371 this._addClass( this.iconSpace, "ui-button-icon-space" );
9372 }
9373 this._removeClass( this.icon, null, "ui-wiget-icon-block" );
9374 this._attachIconSpace( position );
9375 }
9376 },
9377
9378 _destroy: function() {
9379 this.element.removeAttr( "role" );
9380
9381 if ( this.icon ) {
9382 this.icon.remove();
9383 }
9384 if ( this.iconSpace ) {
9385 this.iconSpace.remove();
9386 }
9387 if ( !this.hasTitle ) {
9388 this.element.removeAttr( "title" );
9389 }
9390 },
9391
9392 _attachIconSpace: function( iconPosition ) {
9393 this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
9394 },
9395
9396 _attachIcon: function( iconPosition ) {
9397 this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
9398 },
9399
9400 _setOptions: function( options ) {
9401 var newShowLabel = options.showLabel === undefined ?
9402 this.options.showLabel :
9403 options.showLabel,
9404 newIcon = options.icon === undefined ? this.options.icon : options.icon;
9405
9406 if ( !newShowLabel && !newIcon ) {
9407 options.showLabel = true;
9408 }
9409 this._super( options );
9410 },
9411
9412 _setOption: function( key, value ) {
9413 if ( key === "icon" ) {
9414 if ( value ) {
9415 this._updateIcon( key, value );
9416 } else if ( this.icon ) {
9417 this.icon.remove();
9418 if ( this.iconSpace ) {
9419 this.iconSpace.remove();
9420 }
9421 }
9422 }
9423
9424 if ( key === "iconPosition" ) {
9425 this._updateIcon( key, value );
9426 }
9427
9428 // Make sure we can't end up with a button that has neither text nor icon
9429 if ( key === "showLabel" ) {
9430 this._toggleClass( "ui-button-icon-only", null, !value );
9431 this._updateTooltip();
9432 }
9433
9434 if ( key === "label" ) {
9435 if ( this.isInput ) {
9436 this.element.val( value );
9437 } else {
9438
9439 // If there is an icon, append it, else nothing then append the value
9440 // this avoids removal of the icon when setting label text
9441 this.element.html( value );
9442 if ( this.icon ) {
9443 this._attachIcon( this.options.iconPosition );
9444 this._attachIconSpace( this.options.iconPosition );
9445 }
9446 }
9447 }
9448
9449 this._super( key, value );
9450
9451 if ( key === "disabled" ) {
9452 this._toggleClass( null, "ui-state-disabled", value );
9453 this.element[ 0 ].disabled = value;
9454 if ( value ) {
9455 this.element.blur();
9456 }
9457 }
9458 },
9459
9460 refresh: function() {
9461
9462 // Make sure to only check disabled if its an element that supports this otherwise
9463 // check for the disabled class to determine state
9464 var isDisabled = this.element.is( "input, button" ) ?
9465 this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
9466
9467 if ( isDisabled !== this.options.disabled ) {
9468 this._setOptions( { disabled: isDisabled } );
9469 }
9470
9471 this._updateTooltip();
9472 }
9473 } );
9474
9475 // DEPRECATED
9476 if ( $.uiBackCompat !== false ) {
9477
9478 // Text and Icons options
9479 $.widget( "ui.button", $.ui.button, {
9480 options: {
9481 text: true,
9482 icons: {
9483 primary: null,
9484 secondary: null
9485 }
9486 },
9487
9488 _create: function() {
9489 if ( this.options.showLabel && !this.options.text ) {
9490 this.options.showLabel = this.options.text;
9491 }
9492 if ( !this.options.showLabel && this.options.text ) {
9493 this.options.text = this.options.showLabel;
9494 }
9495 if ( !this.options.icon && ( this.options.icons.primary ||
9496 this.options.icons.secondary ) ) {
9497 if ( this.options.icons.primary ) {
9498 this.options.icon = this.options.icons.primary;
9499 } else {
9500 this.options.icon = this.options.icons.secondary;
9501 this.options.iconPosition = "end";
9502 }
9503 } else if ( this.options.icon ) {
9504 this.options.icons.primary = this.options.icon;
9505 }
9506 this._super();
9507 },
9508
9509 _setOption: function( key, value ) {
9510 if ( key === "text" ) {
9511 this._super( "showLabel", value );
9512 return;
9513 }
9514 if ( key === "showLabel" ) {
9515 this.options.text = value;
9516 }
9517 if ( key === "icon" ) {
9518 this.options.icons.primary = value;
9519 }
9520 if ( key === "icons" ) {
9521 if ( value.primary ) {
9522 this._super( "icon", value.primary );
9523 this._super( "iconPosition", "beginning" );
9524 } else if ( value.secondary ) {
9525 this._super( "icon", value.secondary );
9526 this._super( "iconPosition", "end" );
9527 }
9528 }
9529 this._superApply( arguments );
9530 }
9531 } );
9532
9533 $.fn.button = ( function( orig ) {
9534 return function() {
9535 if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
9536 ( this.length && this[ 0 ].tagName === "INPUT" && (
9537 this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
9538 ) ) ) {
9539 return orig.apply( this, arguments );
9540 }
9541 if ( !$.ui.checkboxradio ) {
9542 $.error( "Checkboxradio widget missing" );
9543 }
9544 if ( arguments.length === 0 ) {
9545 return this.checkboxradio( {
9546 "icon": false
9547 } );
9548 }
9549 return this.checkboxradio.apply( this, arguments );
9550 };
9551 } )( $.fn.button );
9552
9553 $.fn.buttonset = function() {
9554 if ( !$.ui.controlgroup ) {
9555 $.error( "Controlgroup widget missing" );
9556 }
9557 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
9558 return this.controlgroup.apply( this,
9559 [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
9560 }
9561 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
9562 return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
9563 }
9564 if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
9565 arguments[ 0 ].items = {
9566 button: arguments[ 0 ].items
9567 };
9568 }
9569 return this.controlgroup.apply( this, arguments );
9570 };
9571 }
9572
9573 var widgetsButton = $.ui.button;
9574
9575
9576 // jscs:disable maximumLineLength
9577 /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
9578 /*!
9579 * jQuery UI Datepicker 1.12.1
9580 * http://jqueryui.com
9581 *
9582 * Copyright jQuery Foundation and other contributors
9583 * Released under the MIT license.
9584 * http://jquery.org/license
9585 */
9586
9587 //>>label: Datepicker
9588 //>>group: Widgets
9589 //>>description: Displays a calendar from an input or inline for selecting dates.
9590 //>>docs: http://api.jqueryui.com/datepicker/
9591 //>>demos: http://jqueryui.com/datepicker/
9592 //>>css.structure: ../../themes/base/core.css
9593 //>>css.structure: ../../themes/base/datepicker.css
9594 //>>css.theme: ../../themes/base/theme.css
9595
9596
9597
9598 $.extend( $.ui, { datepicker: { version: "1.12.1" } } );
9599
9600 var datepicker_instActive;
9601
9602 function datepicker_getZindex( elem ) {
9603 var position, value;
9604 while ( elem.length && elem[ 0 ] !== document ) {
9605
9606 // Ignore z-index if position is set to a value where z-index is ignored by the browser
9607 // This makes behavior of this function consistent across browsers
9608 // WebKit always returns auto if the element is positioned
9609 position = elem.css( "position" );
9610 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
9611
9612 // IE returns 0 when zIndex is not specified
9613 // other browsers return a string
9614 // we ignore the case of nested elements with an explicit value of 0
9615 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
9616 value = parseInt( elem.css( "zIndex" ), 10 );
9617 if ( !isNaN( value ) && value !== 0 ) {
9618 return value;
9619 }
9620 }
9621 elem = elem.parent();
9622 }
9623
9624 return 0;
9625 }
9626 /* Date picker manager.
9627 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
9628 Settings for (groups of) date pickers are maintained in an instance object,
9629 allowing multiple different settings on the same page. */
9630
9631 function Datepicker() {
9632 this._curInst = null; // The current instance in use
9633 this._keyEvent = false; // If the last event was a key event
9634 this._disabledInputs = []; // List of date picker inputs that have been disabled
9635 this._datepickerShowing = false; // True if the popup picker is showing , false if not
9636 this._inDialog = false; // True if showing within a "dialog", false if not
9637 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
9638 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
9639 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
9640 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
9641 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
9642 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
9643 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
9644 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
9645 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
9646 this.regional = []; // Available regional settings, indexed by language code
9647 this.regional[ "" ] = { // Default regional settings
9648 closeText: "Done", // Display text for close link
9649 prevText: "Prev", // Display text for previous month link
9650 nextText: "Next", // Display text for next month link
9651 currentText: "Today", // Display text for current month link
9652 monthNames: [ "January","February","March","April","May","June",
9653 "July","August","September","October","November","December" ], // Names of months for drop-down and formatting
9654 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
9655 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
9656 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
9657 dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
9658 weekHeader: "Wk", // Column header for week of the year
9659 dateFormat: "mm/dd/yy", // See format options on parseDate
9660 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
9661 isRTL: false, // True if right-to-left language, false if left-to-right
9662 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
9663 yearSuffix: "" // Additional text to append to the year in the month headers
9664 };
9665 this._defaults = { // Global defaults for all the date picker instances
9666 showOn: "focus", // "focus" for popup on focus,
9667 // "button" for trigger button, or "both" for either
9668 showAnim: "fadeIn", // Name of jQuery animation for popup
9669 showOptions: {}, // Options for enhanced animations
9670 defaultDate: null, // Used when field is blank: actual date,
9671 // +/-number for offset from today, null for today
9672 appendText: "", // Display text following the input box, e.g. showing the format
9673 buttonText: "...", // Text for trigger button
9674 buttonImage: "", // URL for trigger button image
9675 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
9676 hideIfNoPrevNext: false, // True to hide next/previous month links
9677 // if not applicable, false to just disable them
9678 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
9679 gotoCurrent: false, // True if today link goes back to current selection instead
9680 changeMonth: false, // True if month can be selected directly, false if only prev/next
9681 changeYear: false, // True if year can be selected directly, false if only prev/next
9682 yearRange: "c-10:c+10", // Range of years to display in drop-down,
9683 // either relative to today's year (-nn:+nn), relative to currently displayed year
9684 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
9685 showOtherMonths: false, // True to show dates in other months, false to leave blank
9686 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
9687 showWeek: false, // True to show week of the year, false to not show it
9688 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
9689 // takes a Date and returns the number of the week for it
9690 shortYearCutoff: "+10", // Short year values < this are in the current century,
9691 // > this are in the previous century,
9692 // string value starting with "+" for current year + value
9693 minDate: null, // The earliest selectable date, or null for no limit
9694 maxDate: null, // The latest selectable date, or null for no limit
9695 duration: "fast", // Duration of display/closure
9696 beforeShowDay: null, // Function that takes a date and returns an array with
9697 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
9698 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
9699 beforeShow: null, // Function that takes an input field and
9700 // returns a set of custom settings for the date picker
9701 onSelect: null, // Define a callback function when a date is selected
9702 onChangeMonthYear: null, // Define a callback function when the month or year is changed
9703 onClose: null, // Define a callback function when the datepicker is closed
9704 numberOfMonths: 1, // Number of months to show at a time
9705 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
9706 stepMonths: 1, // Number of months to step back/forward
9707 stepBigMonths: 12, // Number of months to step back/forward for the big links
9708 altField: "", // Selector for an alternate field to store selected dates into
9709 altFormat: "", // The date format to use for the alternate field
9710 constrainInput: true, // The input is constrained by the current date format
9711 showButtonPanel: false, // True to show button panel, false to not show it
9712 autoSize: false, // True to size the input for the date format, false to leave as is
9713 disabled: false // The initial disabled state
9714 };
9715 $.extend( this._defaults, this.regional[ "" ] );
9716 this.regional.en = $.extend( true, {}, this.regional[ "" ] );
9717 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
9718 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
9719 }
9720
9721 $.extend( Datepicker.prototype, {
9722 /* Class name added to elements to indicate already configured with a date picker. */
9723 markerClassName: "hasDatepicker",
9724
9725 //Keep track of the maximum number of rows displayed (see #7043)
9726 maxRows: 4,
9727
9728 // TODO rename to "widget" when switching to widget factory
9729 _widgetDatepicker: function() {
9730 return this.dpDiv;
9731 },
9732
9733 /* Override the default settings for all instances of the date picker.
9734 * @param settings object - the new settings to use as defaults (anonymous object)
9735 * @return the manager object
9736 */
9737 setDefaults: function( settings ) {
9738 datepicker_extendRemove( this._defaults, settings || {} );
9739 return this;
9740 },
9741
9742 /* Attach the date picker to a jQuery selection.
9743 * @param target element - the target input field or division or span
9744 * @param settings object - the new settings to use for this date picker instance (anonymous)
9745 */
9746 _attachDatepicker: function( target, settings ) {
9747 var nodeName, inline, inst;
9748 nodeName = target.nodeName.toLowerCase();
9749 inline = ( nodeName === "div" || nodeName === "span" );
9750 if ( !target.id ) {
9751 this.uuid += 1;
9752 target.id = "dp" + this.uuid;
9753 }
9754 inst = this._newInst( $( target ), inline );
9755 inst.settings = $.extend( {}, settings || {} );
9756 if ( nodeName === "input" ) {
9757 this._connectDatepicker( target, inst );
9758 } else if ( inline ) {
9759 this._inlineDatepicker( target, inst );
9760 }
9761 },
9762
9763 /* Create a new instance object. */
9764 _newInst: function( target, inline ) {
9765 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
9766 return { id: id, input: target, // associated target
9767 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
9768 drawMonth: 0, drawYear: 0, // month being drawn
9769 inline: inline, // is datepicker inline or not
9770 dpDiv: ( !inline ? this.dpDiv : // presentation div
9771 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
9772 },
9773
9774 /* Attach the date picker to an input field. */
9775 _connectDatepicker: function( target, inst ) {
9776 var input = $( target );
9777 inst.append = $( [] );
9778 inst.trigger = $( [] );
9779 if ( input.hasClass( this.markerClassName ) ) {
9780 return;
9781 }
9782 this._attachments( input, inst );
9783 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
9784 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
9785 this._autoSize( inst );
9786 $.data( target, "datepicker", inst );
9787
9788 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
9789 if ( inst.settings.disabled ) {
9790 this._disableDatepicker( target );
9791 }
9792 },
9793
9794 /* Make attachments based on settings. */
9795 _attachments: function( input, inst ) {
9796 var showOn, buttonText, buttonImage,
9797 appendText = this._get( inst, "appendText" ),
9798 isRTL = this._get( inst, "isRTL" );
9799
9800 if ( inst.append ) {
9801 inst.append.remove();
9802 }
9803 if ( appendText ) {
9804 inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
9805 input[ isRTL ? "before" : "after" ]( inst.append );
9806 }
9807
9808 input.off( "focus", this._showDatepicker );
9809
9810 if ( inst.trigger ) {
9811 inst.trigger.remove();
9812 }
9813
9814 showOn = this._get( inst, "showOn" );
9815 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
9816 input.on( "focus", this._showDatepicker );
9817 }
9818 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
9819 buttonText = this._get( inst, "buttonText" );
9820 buttonImage = this._get( inst, "buttonImage" );
9821 inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
9822 $( "<img/>" ).addClass( this._triggerClass ).
9823 attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
9824 $( "<button type='button'></button>" ).addClass( this._triggerClass ).
9825 html( !buttonImage ? buttonText : $( "<img/>" ).attr(
9826 { src:buttonImage, alt:buttonText, title:buttonText } ) ) );
9827 input[ isRTL ? "before" : "after" ]( inst.trigger );
9828 inst.trigger.on( "click", function() {
9829 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
9830 $.datepicker._hideDatepicker();
9831 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
9832 $.datepicker._hideDatepicker();
9833 $.datepicker._showDatepicker( input[ 0 ] );
9834 } else {
9835 $.datepicker._showDatepicker( input[ 0 ] );
9836 }
9837 return false;
9838 } );
9839 }
9840 },
9841
9842 /* Apply the maximum length for the date format. */
9843 _autoSize: function( inst ) {
9844 if ( this._get( inst, "autoSize" ) && !inst.inline ) {
9845 var findMax, max, maxI, i,
9846 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
9847 dateFormat = this._get( inst, "dateFormat" );
9848
9849 if ( dateFormat.match( /[DM]/ ) ) {
9850 findMax = function( names ) {
9851 max = 0;
9852 maxI = 0;
9853 for ( i = 0; i < names.length; i++ ) {
9854 if ( names[ i ].length > max ) {
9855 max = names[ i ].length;
9856 maxI = i;
9857 }
9858 }
9859 return maxI;
9860 };
9861 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
9862 "monthNames" : "monthNamesShort" ) ) ) );
9863 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
9864 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
9865 }
9866 inst.input.attr( "size", this._formatDate( inst, date ).length );
9867 }
9868 },
9869
9870 /* Attach an inline date picker to a div. */
9871 _inlineDatepicker: function( target, inst ) {
9872 var divSpan = $( target );
9873 if ( divSpan.hasClass( this.markerClassName ) ) {
9874 return;
9875 }
9876 divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
9877 $.data( target, "datepicker", inst );
9878 this._setDate( inst, this._getDefaultDate( inst ), true );
9879 this._updateDatepicker( inst );
9880 this._updateAlternate( inst );
9881
9882 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
9883 if ( inst.settings.disabled ) {
9884 this._disableDatepicker( target );
9885 }
9886
9887 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
9888 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
9889 inst.dpDiv.css( "display", "block" );
9890 },
9891
9892 /* Pop-up the date picker in a "dialog" box.
9893 * @param input element - ignored
9894 * @param date string or Date - the initial date to display
9895 * @param onSelect function - the function to call when a date is selected
9896 * @param settings object - update the dialog date picker instance's settings (anonymous object)
9897 * @param pos int[2] - coordinates for the dialog's position within the screen or
9898 * event - with x/y coordinates or
9899 * leave empty for default (screen centre)
9900 * @return the manager object
9901 */
9902 _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
9903 var id, browserWidth, browserHeight, scrollX, scrollY,
9904 inst = this._dialogInst; // internal instance
9905
9906 if ( !inst ) {
9907 this.uuid += 1;
9908 id = "dp" + this.uuid;
9909 this._dialogInput = $( "<input type='text' id='" + id +
9910 "' style='position: absolute; top: -100px; width: 0px;'/>" );
9911 this._dialogInput.on( "keydown", this._doKeyDown );
9912 $( "body" ).append( this._dialogInput );
9913 inst = this._dialogInst = this._newInst( this._dialogInput, false );
9914 inst.settings = {};
9915 $.data( this._dialogInput[ 0 ], "datepicker", inst );
9916 }
9917 datepicker_extendRemove( inst.settings, settings || {} );
9918 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
9919 this._dialogInput.val( date );
9920
9921 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
9922 if ( !this._pos ) {
9923 browserWidth = document.documentElement.clientWidth;
9924 browserHeight = document.documentElement.clientHeight;
9925 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
9926 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
9927 this._pos = // should use actual width/height below
9928 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
9929 }
9930
9931 // Move input on screen for focus, but hidden behind dialog
9932 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
9933 inst.settings.onSelect = onSelect;
9934 this._inDialog = true;
9935 this.dpDiv.addClass( this._dialogClass );
9936 this._showDatepicker( this._dialogInput[ 0 ] );
9937 if ( $.blockUI ) {
9938 $.blockUI( this.dpDiv );
9939 }
9940 $.data( this._dialogInput[ 0 ], "datepicker", inst );
9941 return this;
9942 },
9943
9944 /* Detach a datepicker from its control.
9945 * @param target element - the target input field or division or span
9946 */
9947 _destroyDatepicker: function( target ) {
9948 var nodeName,
9949 $target = $( target ),
9950 inst = $.data( target, "datepicker" );
9951
9952 if ( !$target.hasClass( this.markerClassName ) ) {
9953 return;
9954 }
9955
9956 nodeName = target.nodeName.toLowerCase();
9957 $.removeData( target, "datepicker" );
9958 if ( nodeName === "input" ) {
9959 inst.append.remove();
9960 inst.trigger.remove();
9961 $target.removeClass( this.markerClassName ).
9962 off( "focus", this._showDatepicker ).
9963 off( "keydown", this._doKeyDown ).
9964 off( "keypress", this._doKeyPress ).
9965 off( "keyup", this._doKeyUp );
9966 } else if ( nodeName === "div" || nodeName === "span" ) {
9967 $target.removeClass( this.markerClassName ).empty();
9968 }
9969
9970 if ( datepicker_instActive === inst ) {
9971 datepicker_instActive = null;
9972 }
9973 },
9974
9975 /* Enable the date picker to a jQuery selection.
9976 * @param target element - the target input field or division or span
9977 */
9978 _enableDatepicker: function( target ) {
9979 var nodeName, inline,
9980 $target = $( target ),
9981 inst = $.data( target, "datepicker" );
9982
9983 if ( !$target.hasClass( this.markerClassName ) ) {
9984 return;
9985 }
9986
9987 nodeName = target.nodeName.toLowerCase();
9988 if ( nodeName === "input" ) {
9989 target.disabled = false;
9990 inst.trigger.filter( "button" ).
9991 each( function() { this.disabled = false; } ).end().
9992 filter( "img" ).css( { opacity: "1.0", cursor: "" } );
9993 } else if ( nodeName === "div" || nodeName === "span" ) {
9994 inline = $target.children( "." + this._inlineClass );
9995 inline.children().removeClass( "ui-state-disabled" );
9996 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
9997 prop( "disabled", false );
9998 }
9999 this._disabledInputs = $.map( this._disabledInputs,
10000 function( value ) { return ( value === target ? null : value ); } ); // delete entry
10001 },
10002
10003 /* Disable the date picker to a jQuery selection.
10004 * @param target element - the target input field or division or span
10005 */
10006 _disableDatepicker: function( target ) {
10007 var nodeName, inline,
10008 $target = $( target ),
10009 inst = $.data( target, "datepicker" );
10010
10011 if ( !$target.hasClass( this.markerClassName ) ) {
10012 return;
10013 }
10014
10015 nodeName = target.nodeName.toLowerCase();
10016 if ( nodeName === "input" ) {
10017 target.disabled = true;
10018 inst.trigger.filter( "button" ).
10019 each( function() { this.disabled = true; } ).end().
10020 filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
10021 } else if ( nodeName === "div" || nodeName === "span" ) {
10022 inline = $target.children( "." + this._inlineClass );
10023 inline.children().addClass( "ui-state-disabled" );
10024 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
10025 prop( "disabled", true );
10026 }
10027 this._disabledInputs = $.map( this._disabledInputs,
10028 function( value ) { return ( value === target ? null : value ); } ); // delete entry
10029 this._disabledInputs[ this._disabledInputs.length ] = target;
10030 },
10031
10032 /* Is the first field in a jQuery collection disabled as a datepicker?
10033 * @param target element - the target input field or division or span
10034 * @return boolean - true if disabled, false if enabled
10035 */
10036 _isDisabledDatepicker: function( target ) {
10037 if ( !target ) {
10038 return false;
10039 }
10040 for ( var i = 0; i < this._disabledInputs.length; i++ ) {
10041 if ( this._disabledInputs[ i ] === target ) {
10042 return true;
10043 }
10044 }
10045 return false;
10046 },
10047
10048 /* Retrieve the instance data for the target control.
10049 * @param target element - the target input field or division or span
10050 * @return object - the associated instance data
10051 * @throws error if a jQuery problem getting data
10052 */
10053 _getInst: function( target ) {
10054 try {
10055 return $.data( target, "datepicker" );
10056 }
10057 catch ( err ) {
10058 throw "Missing instance data for this datepicker";
10059 }
10060 },
10061
10062 /* Update or retrieve the settings for a date picker attached to an input field or division.
10063 * @param target element - the target input field or division or span
10064 * @param name object - the new settings to update or
10065 * string - the name of the setting to change or retrieve,
10066 * when retrieving also "all" for all instance settings or
10067 * "defaults" for all global defaults
10068 * @param value any - the new value for the setting
10069 * (omit if above is an object or to retrieve a value)
10070 */
10071 _optionDatepicker: function( target, name, value ) {
10072 var settings, date, minDate, maxDate,
10073 inst = this._getInst( target );
10074
10075 if ( arguments.length === 2 && typeof name === "string" ) {
10076 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
10077 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
10078 this._get( inst, name ) ) : null ) );
10079 }
10080
10081 settings = name || {};
10082 if ( typeof name === "string" ) {
10083 settings = {};
10084 settings[ name ] = value;
10085 }
10086
10087 if ( inst ) {
10088 if ( this._curInst === inst ) {
10089 this._hideDatepicker();
10090 }
10091
10092 date = this._getDateDatepicker( target, true );
10093 minDate = this._getMinMaxDate( inst, "min" );
10094 maxDate = this._getMinMaxDate( inst, "max" );
10095 datepicker_extendRemove( inst.settings, settings );
10096
10097 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
10098 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
10099 inst.settings.minDate = this._formatDate( inst, minDate );
10100 }
10101 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
10102 inst.settings.maxDate = this._formatDate( inst, maxDate );
10103 }
10104 if ( "disabled" in settings ) {
10105 if ( settings.disabled ) {
10106 this._disableDatepicker( target );
10107 } else {
10108 this._enableDatepicker( target );
10109 }
10110 }
10111 this._attachments( $( target ), inst );
10112 this._autoSize( inst );
10113 this._setDate( inst, date );
10114 this._updateAlternate( inst );
10115 this._updateDatepicker( inst );
10116 }
10117 },
10118
10119 // Change method deprecated
10120 _changeDatepicker: function( target, name, value ) {
10121 this._optionDatepicker( target, name, value );
10122 },
10123
10124 /* Redraw the date picker attached to an input field or division.
10125 * @param target element - the target input field or division or span
10126 */
10127 _refreshDatepicker: function( target ) {
10128 var inst = this._getInst( target );
10129 if ( inst ) {
10130 this._updateDatepicker( inst );
10131 }
10132 },
10133
10134 /* Set the dates for a jQuery selection.
10135 * @param target element - the target input field or division or span
10136 * @param date Date - the new date
10137 */
10138 _setDateDatepicker: function( target, date ) {
10139 var inst = this._getInst( target );
10140 if ( inst ) {
10141 this._setDate( inst, date );
10142 this._updateDatepicker( inst );
10143 this._updateAlternate( inst );
10144 }
10145 },
10146
10147 /* Get the date(s) for the first entry in a jQuery selection.
10148 * @param target element - the target input field or division or span
10149 * @param noDefault boolean - true if no default date is to be used
10150 * @return Date - the current date
10151 */
10152 _getDateDatepicker: function( target, noDefault ) {
10153 var inst = this._getInst( target );
10154 if ( inst && !inst.inline ) {
10155 this._setDateFromField( inst, noDefault );
10156 }
10157 return ( inst ? this._getDate( inst ) : null );
10158 },
10159
10160 /* Handle keystrokes. */
10161 _doKeyDown: function( event ) {
10162 var onSelect, dateStr, sel,
10163 inst = $.datepicker._getInst( event.target ),
10164 handled = true,
10165 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
10166
10167 inst._keyEvent = true;
10168 if ( $.datepicker._datepickerShowing ) {
10169 switch ( event.keyCode ) {
10170 case 9: $.datepicker._hideDatepicker();
10171 handled = false;
10172 break; // hide on tab out
10173 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
10174 $.datepicker._currentClass + ")", inst.dpDiv );
10175 if ( sel[ 0 ] ) {
10176 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
10177 }
10178
10179 onSelect = $.datepicker._get( inst, "onSelect" );
10180 if ( onSelect ) {
10181 dateStr = $.datepicker._formatDate( inst );
10182
10183 // Trigger custom callback
10184 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
10185 } else {
10186 $.datepicker._hideDatepicker();
10187 }
10188
10189 return false; // don't submit the form
10190 case 27: $.datepicker._hideDatepicker();
10191 break; // hide on escape
10192 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
10193 -$.datepicker._get( inst, "stepBigMonths" ) :
10194 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
10195 break; // previous month/year on page up/+ ctrl
10196 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
10197 +$.datepicker._get( inst, "stepBigMonths" ) :
10198 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
10199 break; // next month/year on page down/+ ctrl
10200 case 35: if ( event.ctrlKey || event.metaKey ) {
10201 $.datepicker._clearDate( event.target );
10202 }
10203 handled = event.ctrlKey || event.metaKey;
10204 break; // clear on ctrl or command +end
10205 case 36: if ( event.ctrlKey || event.metaKey ) {
10206 $.datepicker._gotoToday( event.target );
10207 }
10208 handled = event.ctrlKey || event.metaKey;
10209 break; // current on ctrl or command +home
10210 case 37: if ( event.ctrlKey || event.metaKey ) {
10211 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
10212 }
10213 handled = event.ctrlKey || event.metaKey;
10214
10215 // -1 day on ctrl or command +left
10216 if ( event.originalEvent.altKey ) {
10217 $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
10218 -$.datepicker._get( inst, "stepBigMonths" ) :
10219 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
10220 }
10221
10222 // next month/year on alt +left on Mac
10223 break;
10224 case 38: if ( event.ctrlKey || event.metaKey ) {
10225 $.datepicker._adjustDate( event.target, -7, "D" );
10226 }
10227 handled = event.ctrlKey || event.metaKey;
10228 break; // -1 week on ctrl or command +up
10229 case 39: if ( event.ctrlKey || event.metaKey ) {
10230 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
10231 }
10232 handled = event.ctrlKey || event.metaKey;
10233
10234 // +1 day on ctrl or command +right
10235 if ( event.originalEvent.altKey ) {
10236 $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
10237 +$.datepicker._get( inst, "stepBigMonths" ) :
10238 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
10239 }
10240
10241 // next month/year on alt +right
10242 break;
10243 case 40: if ( event.ctrlKey || event.metaKey ) {
10244 $.datepicker._adjustDate( event.target, +7, "D" );
10245 }
10246 handled = event.ctrlKey || event.metaKey;
10247 break; // +1 week on ctrl or command +down
10248 default: handled = false;
10249 }
10250 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
10251 $.datepicker._showDatepicker( this );
10252 } else {
10253 handled = false;
10254 }
10255
10256 if ( handled ) {
10257 event.preventDefault();
10258 event.stopPropagation();
10259 }
10260 },
10261
10262 /* Filter entered characters - based on date format. */
10263 _doKeyPress: function( event ) {
10264 var chars, chr,
10265 inst = $.datepicker._getInst( event.target );
10266
10267 if ( $.datepicker._get( inst, "constrainInput" ) ) {
10268 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
10269 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
10270 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
10271 }
10272 },
10273
10274 /* Synchronise manual entry and field/alternate field. */
10275 _doKeyUp: function( event ) {
10276 var date,
10277 inst = $.datepicker._getInst( event.target );
10278
10279 if ( inst.input.val() !== inst.lastVal ) {
10280 try {
10281 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
10282 ( inst.input ? inst.input.val() : null ),
10283 $.datepicker._getFormatConfig( inst ) );
10284
10285 if ( date ) { // only if valid
10286 $.datepicker._setDateFromField( inst );
10287 $.datepicker._updateAlternate( inst );
10288 $.datepicker._updateDatepicker( inst );
10289 }
10290 }
10291 catch ( err ) {
10292 }
10293 }
10294 return true;
10295 },
10296
10297 /* Pop-up the date picker for a given input field.
10298 * If false returned from beforeShow event handler do not show.
10299 * @param input element - the input field attached to the date picker or
10300 * event - if triggered by focus
10301 */
10302 _showDatepicker: function( input ) {
10303 input = input.target || input;
10304 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
10305 input = $( "input", input.parentNode )[ 0 ];
10306 }
10307
10308 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
10309 return;
10310 }
10311
10312 var inst, beforeShow, beforeShowSettings, isFixed,
10313 offset, showAnim, duration;
10314
10315 inst = $.datepicker._getInst( input );
10316 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
10317 $.datepicker._curInst.dpDiv.stop( true, true );
10318 if ( inst && $.datepicker._datepickerShowing ) {
10319 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
10320 }
10321 }
10322
10323 beforeShow = $.datepicker._get( inst, "beforeShow" );
10324 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
10325 if ( beforeShowSettings === false ) {
10326 return;
10327 }
10328 datepicker_extendRemove( inst.settings, beforeShowSettings );
10329
10330 inst.lastVal = null;
10331 $.datepicker._lastInput = input;
10332 $.datepicker._setDateFromField( inst );
10333
10334 if ( $.datepicker._inDialog ) { // hide cursor
10335 input.value = "";
10336 }
10337 if ( !$.datepicker._pos ) { // position below input
10338 $.datepicker._pos = $.datepicker._findPos( input );
10339 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
10340 }
10341
10342 isFixed = false;
10343 $( input ).parents().each( function() {
10344 isFixed |= $( this ).css( "position" ) === "fixed";
10345 return !isFixed;
10346 } );
10347
10348 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
10349 $.datepicker._pos = null;
10350
10351 //to avoid flashes on Firefox
10352 inst.dpDiv.empty();
10353
10354 // determine sizing offscreen
10355 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
10356 $.datepicker._updateDatepicker( inst );
10357
10358 // fix width for dynamic number of date pickers
10359 // and adjust position before showing
10360 offset = $.datepicker._checkOffset( inst, offset, isFixed );
10361 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
10362 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
10363 left: offset.left + "px", top: offset.top + "px" } );
10364
10365 if ( !inst.inline ) {
10366 showAnim = $.datepicker._get( inst, "showAnim" );
10367 duration = $.datepicker._get( inst, "duration" );
10368 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
10369 $.datepicker._datepickerShowing = true;
10370
10371 if ( $.effects && $.effects.effect[ showAnim ] ) {
10372 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
10373 } else {
10374 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
10375 }
10376
10377 if ( $.datepicker._shouldFocusInput( inst ) ) {
10378 inst.input.trigger( "focus" );
10379 }
10380
10381 $.datepicker._curInst = inst;
10382 }
10383 },
10384
10385 /* Generate the date picker content. */
10386 _updateDatepicker: function( inst ) {
10387 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
10388 datepicker_instActive = inst; // for delegate hover events
10389 inst.dpDiv.empty().append( this._generateHTML( inst ) );
10390 this._attachHandlers( inst );
10391
10392 var origyearshtml,
10393 numMonths = this._getNumberOfMonths( inst ),
10394 cols = numMonths[ 1 ],
10395 width = 17,
10396 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
10397
10398 if ( activeCell.length > 0 ) {
10399 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
10400 }
10401
10402 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
10403 if ( cols > 1 ) {
10404 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
10405 }
10406 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
10407 "Class" ]( "ui-datepicker-multi" );
10408 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
10409 "Class" ]( "ui-datepicker-rtl" );
10410
10411 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
10412 inst.input.trigger( "focus" );
10413 }
10414
10415 // Deffered render of the years select (to avoid flashes on Firefox)
10416 if ( inst.yearshtml ) {
10417 origyearshtml = inst.yearshtml;
10418 setTimeout( function() {
10419
10420 //assure that inst.yearshtml didn't change.
10421 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
10422 inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
10423 }
10424 origyearshtml = inst.yearshtml = null;
10425 }, 0 );
10426 }
10427 },
10428
10429 // #6694 - don't focus the input if it's already focused
10430 // this breaks the change event in IE
10431 // Support: IE and jQuery <1.9
10432 _shouldFocusInput: function( inst ) {
10433 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
10434 },
10435
10436 /* Check positioning to remain on screen. */
10437 _checkOffset: function( inst, offset, isFixed ) {
10438 var dpWidth = inst.dpDiv.outerWidth(),
10439 dpHeight = inst.dpDiv.outerHeight(),
10440 inputWidth = inst.input ? inst.input.outerWidth() : 0,
10441 inputHeight = inst.input ? inst.input.outerHeight() : 0,
10442 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
10443 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
10444
10445 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
10446 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
10447 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
10448
10449 // Now check if datepicker is showing outside window viewport - move to a better place if so.
10450 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
10451 Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
10452 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
10453 Math.abs( dpHeight + inputHeight ) : 0 );
10454
10455 return offset;
10456 },
10457
10458 /* Find an object's position on the screen. */
10459 _findPos: function( obj ) {
10460 var position,
10461 inst = this._getInst( obj ),
10462 isRTL = this._get( inst, "isRTL" );
10463
10464 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
10465 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
10466 }
10467
10468 position = $( obj ).offset();
10469 return [ position.left, position.top ];
10470 },
10471
10472 /* Hide the date picker from view.
10473 * @param input element - the input field attached to the date picker
10474 */
10475 _hideDatepicker: function( input ) {
10476 var showAnim, duration, postProcess, onClose,
10477 inst = this._curInst;
10478
10479 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
10480 return;
10481 }
10482
10483 if ( this._datepickerShowing ) {
10484 showAnim = this._get( inst, "showAnim" );
10485 duration = this._get( inst, "duration" );
10486 postProcess = function() {
10487 $.datepicker._tidyDialog( inst );
10488 };
10489
10490 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
10491 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
10492 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
10493 } else {
10494 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
10495 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
10496 }
10497
10498 if ( !showAnim ) {
10499 postProcess();
10500 }
10501 this._datepickerShowing = false;
10502
10503 onClose = this._get( inst, "onClose" );
10504 if ( onClose ) {
10505 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
10506 }
10507
10508 this._lastInput = null;
10509 if ( this._inDialog ) {
10510 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
10511 if ( $.blockUI ) {
10512 $.unblockUI();
10513 $( "body" ).append( this.dpDiv );
10514 }
10515 }
10516 this._inDialog = false;
10517 }
10518 },
10519
10520 /* Tidy up after a dialog display. */
10521 _tidyDialog: function( inst ) {
10522 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
10523 },
10524
10525 /* Close date picker if clicked elsewhere. */
10526 _checkExternalClick: function( event ) {
10527 if ( !$.datepicker._curInst ) {
10528 return;
10529 }
10530
10531 var $target = $( event.target ),
10532 inst = $.datepicker._getInst( $target[ 0 ] );
10533
10534 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
10535 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
10536 !$target.hasClass( $.datepicker.markerClassName ) &&
10537 !$target.closest( "." + $.datepicker._triggerClass ).length &&
10538 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
10539 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
10540 $.datepicker._hideDatepicker();
10541 }
10542 },
10543
10544 /* Adjust one of the date sub-fields. */
10545 _adjustDate: function( id, offset, period ) {
10546 var target = $( id ),
10547 inst = this._getInst( target[ 0 ] );
10548
10549 if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
10550 return;
10551 }
10552 this._adjustInstDate( inst, offset +
10553 ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
10554 period );
10555 this._updateDatepicker( inst );
10556 },
10557
10558 /* Action for current link. */
10559 _gotoToday: function( id ) {
10560 var date,
10561 target = $( id ),
10562 inst = this._getInst( target[ 0 ] );
10563
10564 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
10565 inst.selectedDay = inst.currentDay;
10566 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
10567 inst.drawYear = inst.selectedYear = inst.currentYear;
10568 } else {
10569 date = new Date();
10570 inst.selectedDay = date.getDate();
10571 inst.drawMonth = inst.selectedMonth = date.getMonth();
10572 inst.drawYear = inst.selectedYear = date.getFullYear();
10573 }
10574 this._notifyChange( inst );
10575 this._adjustDate( target );
10576 },
10577
10578 /* Action for selecting a new month/year. */
10579 _selectMonthYear: function( id, select, period ) {
10580 var target = $( id ),
10581 inst = this._getInst( target[ 0 ] );
10582
10583 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
10584 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
10585 parseInt( select.options[ select.selectedIndex ].value, 10 );
10586
10587 this._notifyChange( inst );
10588 this._adjustDate( target );
10589 },
10590
10591 /* Action for selecting a day. */
10592 _selectDay: function( id, month, year, td ) {
10593 var inst,
10594 target = $( id );
10595
10596 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
10597 return;
10598 }
10599
10600 inst = this._getInst( target[ 0 ] );
10601 inst.selectedDay = inst.currentDay = $( "a", td ).html();
10602 inst.selectedMonth = inst.currentMonth = month;
10603 inst.selectedYear = inst.currentYear = year;
10604 this._selectDate( id, this._formatDate( inst,
10605 inst.currentDay, inst.currentMonth, inst.currentYear ) );
10606 },
10607
10608 /* Erase the input field and hide the date picker. */
10609 _clearDate: function( id ) {
10610 var target = $( id );
10611 this._selectDate( target, "" );
10612 },
10613
10614 /* Update the input field with the selected date. */
10615 _selectDate: function( id, dateStr ) {
10616 var onSelect,
10617 target = $( id ),
10618 inst = this._getInst( target[ 0 ] );
10619
10620 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
10621 if ( inst.input ) {
10622 inst.input.val( dateStr );
10623 }
10624 this._updateAlternate( inst );
10625
10626 onSelect = this._get( inst, "onSelect" );
10627 if ( onSelect ) {
10628 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
10629 } else if ( inst.input ) {
10630 inst.input.trigger( "change" ); // fire the change event
10631 }
10632
10633 if ( inst.inline ) {
10634 this._updateDatepicker( inst );
10635 } else {
10636 this._hideDatepicker();
10637 this._lastInput = inst.input[ 0 ];
10638 if ( typeof( inst.input[ 0 ] ) !== "object" ) {
10639 inst.input.trigger( "focus" ); // restore focus
10640 }
10641 this._lastInput = null;
10642 }
10643 },
10644
10645 /* Update any alternate field to synchronise with the main field. */
10646 _updateAlternate: function( inst ) {
10647 var altFormat, date, dateStr,
10648 altField = this._get( inst, "altField" );
10649
10650 if ( altField ) { // update alternate field too
10651 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
10652 date = this._getDate( inst );
10653 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
10654 $( altField ).val( dateStr );
10655 }
10656 },
10657
10658 /* Set as beforeShowDay function to prevent selection of weekends.
10659 * @param date Date - the date to customise
10660 * @return [boolean, string] - is this date selectable?, what is its CSS class?
10661 */
10662 noWeekends: function( date ) {
10663 var day = date.getDay();
10664 return [ ( day > 0 && day < 6 ), "" ];
10665 },
10666
10667 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
10668 * @param date Date - the date to get the week for
10669 * @return number - the number of the week within the year that contains this date
10670 */
10671 iso8601Week: function( date ) {
10672 var time,
10673 checkDate = new Date( date.getTime() );
10674
10675 // Find Thursday of this week starting on Monday
10676 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
10677
10678 time = checkDate.getTime();
10679 checkDate.setMonth( 0 ); // Compare with Jan 1
10680 checkDate.setDate( 1 );
10681 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
10682 },
10683
10684 /* Parse a string value into a date object.
10685 * See formatDate below for the possible formats.
10686 *
10687 * @param format string - the expected format of the date
10688 * @param value string - the date in the above format
10689 * @param settings Object - attributes include:
10690 * shortYearCutoff number - the cutoff year for determining the century (optional)
10691 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
10692 * dayNames string[7] - names of the days from Sunday (optional)
10693 * monthNamesShort string[12] - abbreviated names of the months (optional)
10694 * monthNames string[12] - names of the months (optional)
10695 * @return Date - the extracted date value or null if value is blank
10696 */
10697 parseDate: function( format, value, settings ) {
10698 if ( format == null || value == null ) {
10699 throw "Invalid arguments";
10700 }
10701
10702 value = ( typeof value === "object" ? value.toString() : value + "" );
10703 if ( value === "" ) {
10704 return null;
10705 }
10706
10707 var iFormat, dim, extra,
10708 iValue = 0,
10709 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
10710 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
10711 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
10712 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
10713 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
10714 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
10715 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
10716 year = -1,
10717 month = -1,
10718 day = -1,
10719 doy = -1,
10720 literal = false,
10721 date,
10722
10723 // Check whether a format character is doubled
10724 lookAhead = function( match ) {
10725 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
10726 if ( matches ) {
10727 iFormat++;
10728 }
10729 return matches;
10730 },
10731
10732 // Extract a number from the string value
10733 getNumber = function( match ) {
10734 var isDoubled = lookAhead( match ),
10735 size = ( match === "@" ? 14 : ( match === "!" ? 20 :
10736 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
10737 minSize = ( match === "y" ? size : 1 ),
10738 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
10739 num = value.substring( iValue ).match( digits );
10740 if ( !num ) {
10741 throw "Missing number at position " + iValue;
10742 }
10743 iValue += num[ 0 ].length;
10744 return parseInt( num[ 0 ], 10 );
10745 },
10746
10747 // Extract a name from the string value and convert to an index
10748 getName = function( match, shortNames, longNames ) {
10749 var index = -1,
10750 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
10751 return [ [ k, v ] ];
10752 } ).sort( function( a, b ) {
10753 return -( a[ 1 ].length - b[ 1 ].length );
10754 } );
10755
10756 $.each( names, function( i, pair ) {
10757 var name = pair[ 1 ];
10758 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
10759 index = pair[ 0 ];
10760 iValue += name.length;
10761 return false;
10762 }
10763 } );
10764 if ( index !== -1 ) {
10765 return index + 1;
10766 } else {
10767 throw "Unknown name at position " + iValue;
10768 }
10769 },
10770
10771 // Confirm that a literal character matches the string value
10772 checkLiteral = function() {
10773 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
10774 throw "Unexpected literal at position " + iValue;
10775 }
10776 iValue++;
10777 };
10778
10779 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
10780 if ( literal ) {
10781 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
10782 literal = false;
10783 } else {
10784 checkLiteral();
10785 }
10786 } else {
10787 switch ( format.charAt( iFormat ) ) {
10788 case "d":
10789 day = getNumber( "d" );
10790 break;
10791 case "D":
10792 getName( "D", dayNamesShort, dayNames );
10793 break;
10794 case "o":
10795 doy = getNumber( "o" );
10796 break;
10797 case "m":
10798 month = getNumber( "m" );
10799 break;
10800 case "M":
10801 month = getName( "M", monthNamesShort, monthNames );
10802 break;
10803 case "y":
10804 year = getNumber( "y" );
10805 break;
10806 case "@":
10807 date = new Date( getNumber( "@" ) );
10808 year = date.getFullYear();
10809 month = date.getMonth() + 1;
10810 day = date.getDate();
10811 break;
10812 case "!":
10813 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
10814 year = date.getFullYear();
10815 month = date.getMonth() + 1;
10816 day = date.getDate();
10817 break;
10818 case "'":
10819 if ( lookAhead( "'" ) ) {
10820 checkLiteral();
10821 } else {
10822 literal = true;
10823 }
10824 break;
10825 default:
10826 checkLiteral();
10827 }
10828 }
10829 }
10830
10831 if ( iValue < value.length ) {
10832 extra = value.substr( iValue );
10833 if ( !/^\s+/.test( extra ) ) {
10834 throw "Extra/unparsed characters found in date: " + extra;
10835 }
10836 }
10837
10838 if ( year === -1 ) {
10839 year = new Date().getFullYear();
10840 } else if ( year < 100 ) {
10841 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
10842 ( year <= shortYearCutoff ? 0 : -100 );
10843 }
10844
10845 if ( doy > -1 ) {
10846 month = 1;
10847 day = doy;
10848 do {
10849 dim = this._getDaysInMonth( year, month - 1 );
10850 if ( day <= dim ) {
10851 break;
10852 }
10853 month++;
10854 day -= dim;
10855 } while ( true );
10856 }
10857
10858 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
10859 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
10860 throw "Invalid date"; // E.g. 31/02/00
10861 }
10862 return date;
10863 },
10864
10865 /* Standard date formats. */
10866 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
10867 COOKIE: "D, dd M yy",
10868 ISO_8601: "yy-mm-dd",
10869 RFC_822: "D, d M y",
10870 RFC_850: "DD, dd-M-y",
10871 RFC_1036: "D, d M y",
10872 RFC_1123: "D, d M yy",
10873 RFC_2822: "D, d M yy",
10874 RSS: "D, d M y", // RFC 822
10875 TICKS: "!",
10876 TIMESTAMP: "@",
10877 W3C: "yy-mm-dd", // ISO 8601
10878
10879 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
10880 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
10881
10882 /* Format a date object into a string value.
10883 * The format can be combinations of the following:
10884 * d - day of month (no leading zero)
10885 * dd - day of month (two digit)
10886 * o - day of year (no leading zeros)
10887 * oo - day of year (three digit)
10888 * D - day name short
10889 * DD - day name long
10890 * m - month of year (no leading zero)
10891 * mm - month of year (two digit)
10892 * M - month name short
10893 * MM - month name long
10894 * y - year (two digit)
10895 * yy - year (four digit)
10896 * @ - Unix timestamp (ms since 01/01/1970)
10897 * ! - Windows ticks (100ns since 01/01/0001)
10898 * "..." - literal text
10899 * '' - single quote
10900 *
10901 * @param format string - the desired format of the date
10902 * @param date Date - the date value to format
10903 * @param settings Object - attributes include:
10904 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
10905 * dayNames string[7] - names of the days from Sunday (optional)
10906 * monthNamesShort string[12] - abbreviated names of the months (optional)
10907 * monthNames string[12] - names of the months (optional)
10908 * @return string - the date in the above format
10909 */
10910 formatDate: function( format, date, settings ) {
10911 if ( !date ) {
10912 return "";
10913 }
10914
10915 var iFormat,
10916 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
10917 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
10918 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
10919 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
10920
10921 // Check whether a format character is doubled
10922 lookAhead = function( match ) {
10923 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
10924 if ( matches ) {
10925 iFormat++;
10926 }
10927 return matches;
10928 },
10929
10930 // Format a number, with leading zero if necessary
10931 formatNumber = function( match, value, len ) {
10932 var num = "" + value;
10933 if ( lookAhead( match ) ) {
10934 while ( num.length < len ) {
10935 num = "0" + num;
10936 }
10937 }
10938 return num;
10939 },
10940
10941 // Format a name, short or long as requested
10942 formatName = function( match, value, shortNames, longNames ) {
10943 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
10944 },
10945 output = "",
10946 literal = false;
10947
10948 if ( date ) {
10949 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
10950 if ( literal ) {
10951 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
10952 literal = false;
10953 } else {
10954 output += format.charAt( iFormat );
10955 }
10956 } else {
10957 switch ( format.charAt( iFormat ) ) {
10958 case "d":
10959 output += formatNumber( "d", date.getDate(), 2 );
10960 break;
10961 case "D":
10962 output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
10963 break;
10964 case "o":
10965 output += formatNumber( "o",
10966 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
10967 break;
10968 case "m":
10969 output += formatNumber( "m", date.getMonth() + 1, 2 );
10970 break;
10971 case "M":
10972 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
10973 break;
10974 case "y":
10975 output += ( lookAhead( "y" ) ? date.getFullYear() :
10976 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
10977 break;
10978 case "@":
10979 output += date.getTime();
10980 break;
10981 case "!":
10982 output += date.getTime() * 10000 + this._ticksTo1970;
10983 break;
10984 case "'":
10985 if ( lookAhead( "'" ) ) {
10986 output += "'";
10987 } else {
10988 literal = true;
10989 }
10990 break;
10991 default:
10992 output += format.charAt( iFormat );
10993 }
10994 }
10995 }
10996 }
10997 return output;
10998 },
10999
11000 /* Extract all possible characters from the date format. */
11001 _possibleChars: function( format ) {
11002 var iFormat,
11003 chars = "",
11004 literal = false,
11005
11006 // Check whether a format character is doubled
11007 lookAhead = function( match ) {
11008 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
11009 if ( matches ) {
11010 iFormat++;
11011 }
11012 return matches;
11013 };
11014
11015 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
11016 if ( literal ) {
11017 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
11018 literal = false;
11019 } else {
11020 chars += format.charAt( iFormat );
11021 }
11022 } else {
11023 switch ( format.charAt( iFormat ) ) {
11024 case "d": case "m": case "y": case "@":
11025 chars += "0123456789";
11026 break;
11027 case "D": case "M":
11028 return null; // Accept anything
11029 case "'":
11030 if ( lookAhead( "'" ) ) {
11031 chars += "'";
11032 } else {
11033 literal = true;
11034 }
11035 break;
11036 default:
11037 chars += format.charAt( iFormat );
11038 }
11039 }
11040 }
11041 return chars;
11042 },
11043
11044 /* Get a setting value, defaulting if necessary. */
11045 _get: function( inst, name ) {
11046 return inst.settings[ name ] !== undefined ?
11047 inst.settings[ name ] : this._defaults[ name ];
11048 },
11049
11050 /* Parse existing date and initialise date picker. */
11051 _setDateFromField: function( inst, noDefault ) {
11052 if ( inst.input.val() === inst.lastVal ) {
11053 return;
11054 }
11055
11056 var dateFormat = this._get( inst, "dateFormat" ),
11057 dates = inst.lastVal = inst.input ? inst.input.val() : null,
11058 defaultDate = this._getDefaultDate( inst ),
11059 date = defaultDate,
11060 settings = this._getFormatConfig( inst );
11061
11062 try {
11063 date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
11064 } catch ( event ) {
11065 dates = ( noDefault ? "" : dates );
11066 }
11067 inst.selectedDay = date.getDate();
11068 inst.drawMonth = inst.selectedMonth = date.getMonth();
11069 inst.drawYear = inst.selectedYear = date.getFullYear();
11070 inst.currentDay = ( dates ? date.getDate() : 0 );
11071 inst.currentMonth = ( dates ? date.getMonth() : 0 );
11072 inst.currentYear = ( dates ? date.getFullYear() : 0 );
11073 this._adjustInstDate( inst );
11074 },
11075
11076 /* Retrieve the default date shown on opening. */
11077 _getDefaultDate: function( inst ) {
11078 return this._restrictMinMax( inst,
11079 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
11080 },
11081
11082 /* A date may be specified as an exact value or a relative one. */
11083 _determineDate: function( inst, date, defaultDate ) {
11084 var offsetNumeric = function( offset ) {
11085 var date = new Date();
11086 date.setDate( date.getDate() + offset );
11087 return date;
11088 },
11089 offsetString = function( offset ) {
11090 try {
11091 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
11092 offset, $.datepicker._getFormatConfig( inst ) );
11093 }
11094 catch ( e ) {
11095
11096 // Ignore
11097 }
11098
11099 var date = ( offset.toLowerCase().match( /^c/ ) ?
11100 $.datepicker._getDate( inst ) : null ) || new Date(),
11101 year = date.getFullYear(),
11102 month = date.getMonth(),
11103 day = date.getDate(),
11104 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
11105 matches = pattern.exec( offset );
11106
11107 while ( matches ) {
11108 switch ( matches[ 2 ] || "d" ) {
11109 case "d" : case "D" :
11110 day += parseInt( matches[ 1 ], 10 ); break;
11111 case "w" : case "W" :
11112 day += parseInt( matches[ 1 ], 10 ) * 7; break;
11113 case "m" : case "M" :
11114 month += parseInt( matches[ 1 ], 10 );
11115 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
11116 break;
11117 case "y": case "Y" :
11118 year += parseInt( matches[ 1 ], 10 );
11119 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
11120 break;
11121 }
11122 matches = pattern.exec( offset );
11123 }
11124 return new Date( year, month, day );
11125 },
11126 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
11127 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
11128
11129 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
11130 if ( newDate ) {
11131 newDate.setHours( 0 );
11132 newDate.setMinutes( 0 );
11133 newDate.setSeconds( 0 );
11134 newDate.setMilliseconds( 0 );
11135 }
11136 return this._daylightSavingAdjust( newDate );
11137 },
11138
11139 /* Handle switch to/from daylight saving.
11140 * Hours may be non-zero on daylight saving cut-over:
11141 * > 12 when midnight changeover, but then cannot generate
11142 * midnight datetime, so jump to 1AM, otherwise reset.
11143 * @param date (Date) the date to check
11144 * @return (Date) the corrected date
11145 */
11146 _daylightSavingAdjust: function( date ) {
11147 if ( !date ) {
11148 return null;
11149 }
11150 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
11151 return date;
11152 },
11153
11154 /* Set the date(s) directly. */
11155 _setDate: function( inst, date, noChange ) {
11156 var clear = !date,
11157 origMonth = inst.selectedMonth,
11158 origYear = inst.selectedYear,
11159 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
11160
11161 inst.selectedDay = inst.currentDay = newDate.getDate();
11162 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
11163 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
11164 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
11165 this._notifyChange( inst );
11166 }
11167 this._adjustInstDate( inst );
11168 if ( inst.input ) {
11169 inst.input.val( clear ? "" : this._formatDate( inst ) );
11170 }
11171 },
11172
11173 /* Retrieve the date(s) directly. */
11174 _getDate: function( inst ) {
11175 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
11176 this._daylightSavingAdjust( new Date(
11177 inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
11178 return startDate;
11179 },
11180
11181 /* Attach the onxxx handlers. These are declared statically so
11182 * they work with static code transformers like Caja.
11183 */
11184 _attachHandlers: function( inst ) {
11185 var stepMonths = this._get( inst, "stepMonths" ),
11186 id = "#" + inst.id.replace( /\\\\/g, "\\" );
11187 inst.dpDiv.find( "[data-handler]" ).map( function() {
11188 var handler = {
11189 prev: function() {
11190 $.datepicker._adjustDate( id, -stepMonths, "M" );
11191 },
11192 next: function() {
11193 $.datepicker._adjustDate( id, +stepMonths, "M" );
11194 },
11195 hide: function() {
11196 $.datepicker._hideDatepicker();
11197 },
11198 today: function() {
11199 $.datepicker._gotoToday( id );
11200 },
11201 selectDay: function() {
11202 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
11203 return false;
11204 },
11205 selectMonth: function() {
11206 $.datepicker._selectMonthYear( id, this, "M" );
11207 return false;
11208 },
11209 selectYear: function() {
11210 $.datepicker._selectMonthYear( id, this, "Y" );
11211 return false;
11212 }
11213 };
11214 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
11215 } );
11216 },
11217
11218 /* Generate the HTML for the current state of the date picker. */
11219 _generateHTML: function( inst ) {
11220 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
11221 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
11222 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
11223 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
11224 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
11225 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
11226 tempDate = new Date(),
11227 today = this._daylightSavingAdjust(
11228 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
11229 isRTL = this._get( inst, "isRTL" ),
11230 showButtonPanel = this._get( inst, "showButtonPanel" ),
11231 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
11232 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
11233 numMonths = this._getNumberOfMonths( inst ),
11234 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
11235 stepMonths = this._get( inst, "stepMonths" ),
11236 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
11237 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
11238 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
11239 minDate = this._getMinMaxDate( inst, "min" ),
11240 maxDate = this._getMinMaxDate( inst, "max" ),
11241 drawMonth = inst.drawMonth - showCurrentAtPos,
11242 drawYear = inst.drawYear;
11243
11244 if ( drawMonth < 0 ) {
11245 drawMonth += 12;
11246 drawYear--;
11247 }
11248 if ( maxDate ) {
11249 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
11250 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
11251 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
11252 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
11253 drawMonth--;
11254 if ( drawMonth < 0 ) {
11255 drawMonth = 11;
11256 drawYear--;
11257 }
11258 }
11259 }
11260 inst.drawMonth = drawMonth;
11261 inst.drawYear = drawYear;
11262
11263 prevText = this._get( inst, "prevText" );
11264 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
11265 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
11266 this._getFormatConfig( inst ) ) );
11267
11268 prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
11269 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
11270 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
11271 ( 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>" ) );
11272
11273 nextText = this._get( inst, "nextText" );
11274 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
11275 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
11276 this._getFormatConfig( inst ) ) );
11277
11278 next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
11279 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
11280 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
11281 ( 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>" ) );
11282
11283 currentText = this._get( inst, "currentText" );
11284 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
11285 currentText = ( !navigationAsDateFormat ? currentText :
11286 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
11287
11288 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'>" +
11289 this._get( inst, "closeText" ) + "</button>" : "" );
11290
11291 buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
11292 ( 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'" +
11293 ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
11294
11295 firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
11296 firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
11297
11298 showWeek = this._get( inst, "showWeek" );
11299 dayNames = this._get( inst, "dayNames" );
11300 dayNamesMin = this._get( inst, "dayNamesMin" );
11301 monthNames = this._get( inst, "monthNames" );
11302 monthNamesShort = this._get( inst, "monthNamesShort" );
11303 beforeShowDay = this._get( inst, "beforeShowDay" );
11304 showOtherMonths = this._get( inst, "showOtherMonths" );
11305 selectOtherMonths = this._get( inst, "selectOtherMonths" );
11306 defaultDate = this._getDefaultDate( inst );
11307 html = "";
11308
11309 for ( row = 0; row < numMonths[ 0 ]; row++ ) {
11310 group = "";
11311 this.maxRows = 4;
11312 for ( col = 0; col < numMonths[ 1 ]; col++ ) {
11313 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
11314 cornerClass = " ui-corner-all";
11315 calender = "";
11316 if ( isMultiMonth ) {
11317 calender += "<div class='ui-datepicker-group";
11318 if ( numMonths[ 1 ] > 1 ) {
11319 switch ( col ) {
11320 case 0: calender += " ui-datepicker-group-first";
11321 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
11322 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
11323 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
11324 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
11325 }
11326 }
11327 calender += "'>";
11328 }
11329 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
11330 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
11331 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
11332 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
11333 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
11334 "</div><table class='ui-datepicker-calendar'><thead>" +
11335 "<tr>";
11336 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
11337 for ( dow = 0; dow < 7; dow++ ) { // days of the week
11338 day = ( dow + firstDay ) % 7;
11339 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
11340 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
11341 }
11342 calender += thead + "</tr></thead><tbody>";
11343 daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
11344 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
11345 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
11346 }
11347 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
11348 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
11349 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
11350 this.maxRows = numRows;
11351 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
11352 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
11353 calender += "<tr>";
11354 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
11355 this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
11356 for ( dow = 0; dow < 7; dow++ ) { // create date picker days
11357 daySettings = ( beforeShowDay ?
11358 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
11359 otherMonth = ( printDate.getMonth() !== drawMonth );
11360 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
11361 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
11362 tbody += "<td class='" +
11363 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
11364 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
11365 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
11366 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
11367
11368 // or defaultDate is current printedDate and defaultDate is selectedDate
11369 " " + this._dayOverClass : "" ) + // highlight selected day
11370 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
11371 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
11372 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
11373 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
11374 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
11375 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
11376 ( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
11377 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
11378 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
11379 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
11380 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
11381 "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
11382 printDate.setDate( printDate.getDate() + 1 );
11383 printDate = this._daylightSavingAdjust( printDate );
11384 }
11385 calender += tbody + "</tr>";
11386 }
11387 drawMonth++;
11388 if ( drawMonth > 11 ) {
11389 drawMonth = 0;
11390 drawYear++;
11391 }
11392 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
11393 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
11394 group += calender;
11395 }
11396 html += group;
11397 }
11398 html += buttonPanel;
11399 inst._keyEvent = false;
11400 return html;
11401 },
11402
11403 /* Generate the month and year header. */
11404 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
11405 secondary, monthNames, monthNamesShort ) {
11406
11407 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
11408 changeMonth = this._get( inst, "changeMonth" ),
11409 changeYear = this._get( inst, "changeYear" ),
11410 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
11411 html = "<div class='ui-datepicker-title'>",
11412 monthHtml = "";
11413
11414 // Month selection
11415 if ( secondary || !changeMonth ) {
11416 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
11417 } else {
11418 inMinYear = ( minDate && minDate.getFullYear() === drawYear );
11419 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
11420 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
11421 for ( month = 0; month < 12; month++ ) {
11422 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
11423 monthHtml += "<option value='" + month + "'" +
11424 ( month === drawMonth ? " selected='selected'" : "" ) +
11425 ">" + monthNamesShort[ month ] + "</option>";
11426 }
11427 }
11428 monthHtml += "</select>";
11429 }
11430
11431 if ( !showMonthAfterYear ) {
11432 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
11433 }
11434
11435 // Year selection
11436 if ( !inst.yearshtml ) {
11437 inst.yearshtml = "";
11438 if ( secondary || !changeYear ) {
11439 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
11440 } else {
11441
11442 // determine range of years to display
11443 years = this._get( inst, "yearRange" ).split( ":" );
11444 thisYear = new Date().getFullYear();
11445 determineYear = function( value ) {
11446 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
11447 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
11448 parseInt( value, 10 ) ) );
11449 return ( isNaN( year ) ? thisYear : year );
11450 };
11451 year = determineYear( years[ 0 ] );
11452 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
11453 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
11454 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
11455 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
11456 for ( ; year <= endYear; year++ ) {
11457 inst.yearshtml += "<option value='" + year + "'" +
11458 ( year === drawYear ? " selected='selected'" : "" ) +
11459 ">" + year + "</option>";
11460 }
11461 inst.yearshtml += "</select>";
11462
11463 html += inst.yearshtml;
11464 inst.yearshtml = null;
11465 }
11466 }
11467
11468 html += this._get( inst, "yearSuffix" );
11469 if ( showMonthAfterYear ) {
11470 html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
11471 }
11472 html += "</div>"; // Close datepicker_header
11473 return html;
11474 },
11475
11476 /* Adjust one of the date sub-fields. */
11477 _adjustInstDate: function( inst, offset, period ) {
11478 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
11479 month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
11480 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
11481 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
11482
11483 inst.selectedDay = date.getDate();
11484 inst.drawMonth = inst.selectedMonth = date.getMonth();
11485 inst.drawYear = inst.selectedYear = date.getFullYear();
11486 if ( period === "M" || period === "Y" ) {
11487 this._notifyChange( inst );
11488 }
11489 },
11490
11491 /* Ensure a date is within any min/max bounds. */
11492 _restrictMinMax: function( inst, date ) {
11493 var minDate = this._getMinMaxDate( inst, "min" ),
11494 maxDate = this._getMinMaxDate( inst, "max" ),
11495 newDate = ( minDate && date < minDate ? minDate : date );
11496 return ( maxDate && newDate > maxDate ? maxDate : newDate );
11497 },
11498
11499 /* Notify change of month/year. */
11500 _notifyChange: function( inst ) {
11501 var onChange = this._get( inst, "onChangeMonthYear" );
11502 if ( onChange ) {
11503 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
11504 [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
11505 }
11506 },
11507
11508 /* Determine the number of months to show. */
11509 _getNumberOfMonths: function( inst ) {
11510 var numMonths = this._get( inst, "numberOfMonths" );
11511 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
11512 },
11513
11514 /* Determine the current maximum date - ensure no time components are set. */
11515 _getMinMaxDate: function( inst, minMax ) {
11516 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
11517 },
11518
11519 /* Find the number of days in a given month. */
11520 _getDaysInMonth: function( year, month ) {
11521 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
11522 },
11523
11524 /* Find the day of the week of the first of a month. */
11525 _getFirstDayOfMonth: function( year, month ) {
11526 return new Date( year, month, 1 ).getDay();
11527 },
11528
11529 /* Determines if we should allow a "next/prev" month display change. */
11530 _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
11531 var numMonths = this._getNumberOfMonths( inst ),
11532 date = this._daylightSavingAdjust( new Date( curYear,
11533 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
11534
11535 if ( offset < 0 ) {
11536 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
11537 }
11538 return this._isInRange( inst, date );
11539 },
11540
11541 /* Is the given date in the accepted range? */
11542 _isInRange: function( inst, date ) {
11543 var yearSplit, currentYear,
11544 minDate = this._getMinMaxDate( inst, "min" ),
11545 maxDate = this._getMinMaxDate( inst, "max" ),
11546 minYear = null,
11547 maxYear = null,
11548 years = this._get( inst, "yearRange" );
11549 if ( years ) {
11550 yearSplit = years.split( ":" );
11551 currentYear = new Date().getFullYear();
11552 minYear = parseInt( yearSplit[ 0 ], 10 );
11553 maxYear = parseInt( yearSplit[ 1 ], 10 );
11554 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
11555 minYear += currentYear;
11556 }
11557 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
11558 maxYear += currentYear;
11559 }
11560 }
11561
11562 return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
11563 ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
11564 ( !minYear || date.getFullYear() >= minYear ) &&
11565 ( !maxYear || date.getFullYear() <= maxYear ) );
11566 },
11567
11568 /* Provide the configuration settings for formatting/parsing. */
11569 _getFormatConfig: function( inst ) {
11570 var shortYearCutoff = this._get( inst, "shortYearCutoff" );
11571 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
11572 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
11573 return { shortYearCutoff: shortYearCutoff,
11574 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
11575 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
11576 },
11577
11578 /* Format the given date for display. */
11579 _formatDate: function( inst, day, month, year ) {
11580 if ( !day ) {
11581 inst.currentDay = inst.selectedDay;
11582 inst.currentMonth = inst.selectedMonth;
11583 inst.currentYear = inst.selectedYear;
11584 }
11585 var date = ( day ? ( typeof day === "object" ? day :
11586 this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
11587 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
11588 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
11589 }
11590 } );
11591
11592 /*
11593 * Bind hover events for datepicker elements.
11594 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
11595 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
11596 */
11597 function datepicker_bindHover( dpDiv ) {
11598 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
11599 return dpDiv.on( "mouseout", selector, function() {
11600 $( this ).removeClass( "ui-state-hover" );
11601 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
11602 $( this ).removeClass( "ui-datepicker-prev-hover" );
11603 }
11604 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
11605 $( this ).removeClass( "ui-datepicker-next-hover" );
11606 }
11607 } )
11608 .on( "mouseover", selector, datepicker_handleMouseover );
11609 }
11610
11611 function datepicker_handleMouseover() {
11612 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
11613 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
11614 $( this ).addClass( "ui-state-hover" );
11615 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
11616 $( this ).addClass( "ui-datepicker-prev-hover" );
11617 }
11618 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
11619 $( this ).addClass( "ui-datepicker-next-hover" );
11620 }
11621 }
11622 }
11623
11624 /* jQuery extend now ignores nulls! */
11625 function datepicker_extendRemove( target, props ) {
11626 $.extend( target, props );
11627 for ( var name in props ) {
11628 if ( props[ name ] == null ) {
11629 target[ name ] = props[ name ];
11630 }
11631 }
11632 return target;
11633 }
11634
11635 /* Invoke the datepicker functionality.
11636 @param options string - a command, optionally followed by additional parameters or
11637 Object - settings for attaching new datepicker functionality
11638 @return jQuery object */
11639 $.fn.datepicker = function( options ) {
11640
11641 /* Verify an empty collection wasn't passed - Fixes #6976 */
11642 if ( !this.length ) {
11643 return this;
11644 }
11645
11646 /* Initialise the date picker. */
11647 if ( !$.datepicker.initialized ) {
11648 $( document ).on( "mousedown", $.datepicker._checkExternalClick );
11649 $.datepicker.initialized = true;
11650 }
11651
11652 /* Append datepicker main container to body if not exist. */
11653 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
11654 $( "body" ).append( $.datepicker.dpDiv );
11655 }
11656
11657 var otherArgs = Array.prototype.slice.call( arguments, 1 );
11658 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
11659 return $.datepicker[ "_" + options + "Datepicker" ].
11660 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
11661 }
11662 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
11663 return $.datepicker[ "_" + options + "Datepicker" ].
11664 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
11665 }
11666 return this.each( function() {
11667 typeof options === "string" ?
11668 $.datepicker[ "_" + options + "Datepicker" ].
11669 apply( $.datepicker, [ this ].concat( otherArgs ) ) :
11670 $.datepicker._attachDatepicker( this, options );
11671 } );
11672 };
11673
11674 $.datepicker = new Datepicker(); // singleton instance
11675 $.datepicker.initialized = false;
11676 $.datepicker.uuid = new Date().getTime();
11677 $.datepicker.version = "1.12.1";
11678
11679 var widgetsDatepicker = $.datepicker;
11680
11681
11682 /*!
11683 * jQuery UI Dialog 1.12.1
11684 * http://jqueryui.com
11685 *
11686 * Copyright jQuery Foundation and other contributors
11687 * Released under the MIT license.
11688 * http://jquery.org/license
11689 */
11690
11691 //>>label: Dialog
11692 //>>group: Widgets
11693 //>>description: Displays customizable dialog windows.
11694 //>>docs: http://api.jqueryui.com/dialog/
11695 //>>demos: http://jqueryui.com/dialog/
11696 //>>css.structure: ../../themes/base/core.css
11697 //>>css.structure: ../../themes/base/dialog.css
11698 //>>css.theme: ../../themes/base/theme.css
11699
11700
11701
11702 $.widget( "ui.dialog", {
11703 version: "1.12.1",
11704 options: {
11705 appendTo: "body",
11706 autoOpen: true,
11707 buttons: [],
11708 classes: {
11709 "ui-dialog": "ui-corner-all",
11710 "ui-dialog-titlebar": "ui-corner-all"
11711 },
11712 closeOnEscape: true,
11713 closeText: "Close",
11714 draggable: true,
11715 hide: null,
11716 height: "auto",
11717 maxHeight: null,
11718 maxWidth: null,
11719 minHeight: 150,
11720 minWidth: 150,
11721 modal: false,
11722 position: {
11723 my: "center",
11724 at: "center",
11725 of: window,
11726 collision: "fit",
11727
11728 // Ensure the titlebar is always visible
11729 using: function( pos ) {
11730 var topOffset = $( this ).css( pos ).offset().top;
11731 if ( topOffset < 0 ) {
11732 $( this ).css( "top", pos.top - topOffset );
11733 }
11734 }
11735 },
11736 resizable: true,
11737 show: null,
11738 title: null,
11739 width: 300,
11740
11741 // Callbacks
11742 beforeClose: null,
11743 close: null,
11744 drag: null,
11745 dragStart: null,
11746 dragStop: null,
11747 focus: null,
11748 open: null,
11749 resize: null,
11750 resizeStart: null,
11751 resizeStop: null
11752 },
11753
11754 sizeRelatedOptions: {
11755 buttons: true,
11756 height: true,
11757 maxHeight: true,
11758 maxWidth: true,
11759 minHeight: true,
11760 minWidth: true,
11761 width: true
11762 },
11763
11764 resizableRelatedOptions: {
11765 maxHeight: true,
11766 maxWidth: true,
11767 minHeight: true,
11768 minWidth: true
11769 },
11770
11771 _create: function() {
11772 this.originalCss = {
11773 display: this.element[ 0 ].style.display,
11774 width: this.element[ 0 ].style.width,
11775 minHeight: this.element[ 0 ].style.minHeight,
11776 maxHeight: this.element[ 0 ].style.maxHeight,
11777 height: this.element[ 0 ].style.height
11778 };
11779 this.originalPosition = {
11780 parent: this.element.parent(),
11781 index: this.element.parent().children().index( this.element )
11782 };
11783 this.originalTitle = this.element.attr( "title" );
11784 if ( this.options.title == null && this.originalTitle != null ) {
11785 this.options.title = this.originalTitle;
11786 }
11787
11788 // Dialogs can't be disabled
11789 if ( this.options.disabled ) {
11790 this.options.disabled = false;
11791 }
11792
11793 this._createWrapper();
11794
11795 this.element
11796 .show()
11797 .removeAttr( "title" )
11798 .appendTo( this.uiDialog );
11799
11800 this._addClass( "ui-dialog-content", "ui-widget-content" );
11801
11802 this._createTitlebar();
11803 this._createButtonPane();
11804
11805 if ( this.options.draggable && $.fn.draggable ) {
11806 this._makeDraggable();
11807 }
11808 if ( this.options.resizable && $.fn.resizable ) {
11809 this._makeResizable();
11810 }
11811
11812 this._isOpen = false;
11813
11814 this._trackFocus();
11815 },
11816
11817 _init: function() {
11818 if ( this.options.autoOpen ) {
11819 this.open();
11820 }
11821 },
11822
11823 _appendTo: function() {
11824 var element = this.options.appendTo;
11825 if ( element && ( element.jquery || element.nodeType ) ) {
11826 return $( element );
11827 }
11828 return this.document.find( element || "body" ).eq( 0 );
11829 },
11830
11831 _destroy: function() {
11832 var next,
11833 originalPosition = this.originalPosition;
11834
11835 this._untrackInstance();
11836 this._destroyOverlay();
11837
11838 this.element
11839 .removeUniqueId()
11840 .css( this.originalCss )
11841
11842 // Without detaching first, the following becomes really slow
11843 .detach();
11844
11845 this.uiDialog.remove();
11846
11847 if ( this.originalTitle ) {
11848 this.element.attr( "title", this.originalTitle );
11849 }
11850
11851 next = originalPosition.parent.children().eq( originalPosition.index );
11852
11853 // Don't try to place the dialog next to itself (#8613)
11854 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
11855 next.before( this.element );
11856 } else {
11857 originalPosition.parent.append( this.element );
11858 }
11859 },
11860
11861 widget: function() {
11862 return this.uiDialog;
11863 },
11864
11865 disable: $.noop,
11866 enable: $.noop,
11867
11868 close: function( event ) {
11869 var that = this;
11870
11871 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
11872 return;
11873 }
11874
11875 this._isOpen = false;
11876 this._focusedElement = null;
11877 this._destroyOverlay();
11878 this._untrackInstance();
11879
11880 if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
11881
11882 // Hiding a focused element doesn't trigger blur in WebKit
11883 // so in case we have nothing to focus on, explicitly blur the active element
11884 // https://bugs.webkit.org/show_bug.cgi?id=47182
11885 $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
11886 }
11887
11888 this._hide( this.uiDialog, this.options.hide, function() {
11889 that._trigger( "close", event );
11890 } );
11891 },
11892
11893 isOpen: function() {
11894 return this._isOpen;
11895 },
11896
11897 moveToTop: function() {
11898 this._moveToTop();
11899 },
11900
11901 _moveToTop: function( event, silent ) {
11902 var moved = false,
11903 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
11904 return +$( this ).css( "z-index" );
11905 } ).get(),
11906 zIndexMax = Math.max.apply( null, zIndices );
11907
11908 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
11909 this.uiDialog.css( "z-index", zIndexMax + 1 );
11910 moved = true;
11911 }
11912
11913 if ( moved && !silent ) {
11914 this._trigger( "focus", event );
11915 }
11916 return moved;
11917 },
11918
11919 open: function() {
11920 var that = this;
11921 if ( this._isOpen ) {
11922 if ( this._moveToTop() ) {
11923 this._focusTabbable();
11924 }
11925 return;
11926 }
11927
11928 this._isOpen = true;
11929 this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
11930
11931 this._size();
11932 this._position();
11933 this._createOverlay();
11934 this._moveToTop( null, true );
11935
11936 // Ensure the overlay is moved to the top with the dialog, but only when
11937 // opening. The overlay shouldn't move after the dialog is open so that
11938 // modeless dialogs opened after the modal dialog stack properly.
11939 if ( this.overlay ) {
11940 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
11941 }
11942
11943 this._show( this.uiDialog, this.options.show, function() {
11944 that._focusTabbable();
11945 that._trigger( "focus" );
11946 } );
11947
11948 // Track the dialog immediately upon openening in case a focus event
11949 // somehow occurs outside of the dialog before an element inside the
11950 // dialog is focused (#10152)
11951 this._makeFocusTarget();
11952
11953 this._trigger( "open" );
11954 },
11955
11956 _focusTabbable: function() {
11957
11958 // Set focus to the first match:
11959 // 1. An element that was focused previously
11960 // 2. First element inside the dialog matching [autofocus]
11961 // 3. Tabbable element inside the content element
11962 // 4. Tabbable element inside the buttonpane
11963 // 5. The close button
11964 // 6. The dialog itself
11965 var hasFocus = this._focusedElement;
11966 if ( !hasFocus ) {
11967 hasFocus = this.element.find( "[autofocus]" );
11968 }
11969 if ( !hasFocus.length ) {
11970 hasFocus = this.element.find( ":tabbable" );
11971 }
11972 if ( !hasFocus.length ) {
11973 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
11974 }
11975 if ( !hasFocus.length ) {
11976 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
11977 }
11978 if ( !hasFocus.length ) {
11979 hasFocus = this.uiDialog;
11980 }
11981 hasFocus.eq( 0 ).trigger( "focus" );
11982 },
11983
11984 _keepFocus: function( event ) {
11985 function checkFocus() {
11986 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
11987 isActive = this.uiDialog[ 0 ] === activeElement ||
11988 $.contains( this.uiDialog[ 0 ], activeElement );
11989 if ( !isActive ) {
11990 this._focusTabbable();
11991 }
11992 }
11993 event.preventDefault();
11994 checkFocus.call( this );
11995
11996 // support: IE
11997 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
11998 // so we check again later
11999 this._delay( checkFocus );
12000 },
12001
12002 _createWrapper: function() {
12003 this.uiDialog = $( "<div>" )
12004 .hide()
12005 .attr( {
12006
12007 // Setting tabIndex makes the div focusable
12008 tabIndex: -1,
12009 role: "dialog"
12010 } )
12011 .appendTo( this._appendTo() );
12012
12013 this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
12014 this._on( this.uiDialog, {
12015 keydown: function( event ) {
12016 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
12017 event.keyCode === $.ui.keyCode.ESCAPE ) {
12018 event.preventDefault();
12019 this.close( event );
12020 return;
12021 }
12022
12023 // Prevent tabbing out of dialogs
12024 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
12025 return;
12026 }
12027 var tabbables = this.uiDialog.find( ":tabbable" ),
12028 first = tabbables.filter( ":first" ),
12029 last = tabbables.filter( ":last" );
12030
12031 if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
12032 !event.shiftKey ) {
12033 this._delay( function() {
12034 first.trigger( "focus" );
12035 } );
12036 event.preventDefault();
12037 } else if ( ( event.target === first[ 0 ] ||
12038 event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
12039 this._delay( function() {
12040 last.trigger( "focus" );
12041 } );
12042 event.preventDefault();
12043 }
12044 },
12045 mousedown: function( event ) {
12046 if ( this._moveToTop( event ) ) {
12047 this._focusTabbable();
12048 }
12049 }
12050 } );
12051
12052 // We assume that any existing aria-describedby attribute means
12053 // that the dialog content is marked up properly
12054 // otherwise we brute force the content as the description
12055 if ( !this.element.find( "[aria-describedby]" ).length ) {
12056 this.uiDialog.attr( {
12057 "aria-describedby": this.element.uniqueId().attr( "id" )
12058 } );
12059 }
12060 },
12061
12062 _createTitlebar: function() {
12063 var uiDialogTitle;
12064
12065 this.uiDialogTitlebar = $( "<div>" );
12066 this._addClass( this.uiDialogTitlebar,
12067 "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
12068 this._on( this.uiDialogTitlebar, {
12069 mousedown: function( event ) {
12070
12071 // Don't prevent click on close button (#8838)
12072 // Focusing a dialog that is partially scrolled out of view
12073 // causes the browser to scroll it into view, preventing the click event
12074 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
12075
12076 // Dialog isn't getting focus when dragging (#8063)
12077 this.uiDialog.trigger( "focus" );
12078 }
12079 }
12080 } );
12081
12082 // Support: IE
12083 // Use type="button" to prevent enter keypresses in textboxes from closing the
12084 // dialog in IE (#9312)
12085 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
12086 .button( {
12087 label: $( "<a>" ).text( this.options.closeText ).html(),
12088 icon: "ui-icon-closethick",
12089 showLabel: false
12090 } )
12091 .appendTo( this.uiDialogTitlebar );
12092
12093 this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
12094 this._on( this.uiDialogTitlebarClose, {
12095 click: function( event ) {
12096 event.preventDefault();
12097 this.close( event );
12098 }
12099 } );
12100
12101 uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
12102 this._addClass( uiDialogTitle, "ui-dialog-title" );
12103 this._title( uiDialogTitle );
12104
12105 this.uiDialogTitlebar.prependTo( this.uiDialog );
12106
12107 this.uiDialog.attr( {
12108 "aria-labelledby": uiDialogTitle.attr( "id" )
12109 } );
12110 },
12111
12112 _title: function( title ) {
12113 if ( this.options.title ) {
12114 title.text( this.options.title );
12115 } else {
12116 title.html( "&#160;" );
12117 }
12118 },
12119
12120 _createButtonPane: function() {
12121 this.uiDialogButtonPane = $( "<div>" );
12122 this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
12123 "ui-widget-content ui-helper-clearfix" );
12124
12125 this.uiButtonSet = $( "<div>" )
12126 .appendTo( this.uiDialogButtonPane );
12127 this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
12128
12129 this._createButtons();
12130 },
12131
12132 _createButtons: function() {
12133 var that = this,
12134 buttons = this.options.buttons;
12135
12136 // If we already have a button pane, remove it
12137 this.uiDialogButtonPane.remove();
12138 this.uiButtonSet.empty();
12139
12140 if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
12141 this._removeClass( this.uiDialog, "ui-dialog-buttons" );
12142 return;
12143 }
12144
12145 $.each( buttons, function( name, props ) {
12146 var click, buttonOptions;
12147 props = $.isFunction( props ) ?
12148 { click: props, text: name } :
12149 props;
12150
12151 // Default to a non-submitting button
12152 props = $.extend( { type: "button" }, props );
12153
12154 // Change the context for the click callback to be the main element
12155 click = props.click;
12156 buttonOptions = {
12157 icon: props.icon,
12158 iconPosition: props.iconPosition,
12159 showLabel: props.showLabel,
12160
12161 // Deprecated options
12162 icons: props.icons,
12163 text: props.text
12164 };
12165
12166 delete props.click;
12167 delete props.icon;
12168 delete props.iconPosition;
12169 delete props.showLabel;
12170
12171 // Deprecated options
12172 delete props.icons;
12173 if ( typeof props.text === "boolean" ) {
12174 delete props.text;
12175 }
12176
12177 $( "<button></button>", props )
12178 .button( buttonOptions )
12179 .appendTo( that.uiButtonSet )
12180 .on( "click", function() {
12181 click.apply( that.element[ 0 ], arguments );
12182 } );
12183 } );
12184 this._addClass( this.uiDialog, "ui-dialog-buttons" );
12185 this.uiDialogButtonPane.appendTo( this.uiDialog );
12186 },
12187
12188 _makeDraggable: function() {
12189 var that = this,
12190 options = this.options;
12191
12192 function filteredUi( ui ) {
12193 return {
12194 position: ui.position,
12195 offset: ui.offset
12196 };
12197 }
12198
12199 this.uiDialog.draggable( {
12200 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
12201 handle: ".ui-dialog-titlebar",
12202 containment: "document",
12203 start: function( event, ui ) {
12204 that._addClass( $( this ), "ui-dialog-dragging" );
12205 that._blockFrames();
12206 that._trigger( "dragStart", event, filteredUi( ui ) );
12207 },
12208 drag: function( event, ui ) {
12209 that._trigger( "drag", event, filteredUi( ui ) );
12210 },
12211 stop: function( event, ui ) {
12212 var left = ui.offset.left - that.document.scrollLeft(),
12213 top = ui.offset.top - that.document.scrollTop();
12214
12215 options.position = {
12216 my: "left top",
12217 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12218 "top" + ( top >= 0 ? "+" : "" ) + top,
12219 of: that.window
12220 };
12221 that._removeClass( $( this ), "ui-dialog-dragging" );
12222 that._unblockFrames();
12223 that._trigger( "dragStop", event, filteredUi( ui ) );
12224 }
12225 } );
12226 },
12227
12228 _makeResizable: function() {
12229 var that = this,
12230 options = this.options,
12231 handles = options.resizable,
12232
12233 // .ui-resizable has position: relative defined in the stylesheet
12234 // but dialogs have to use absolute or fixed positioning
12235 position = this.uiDialog.css( "position" ),
12236 resizeHandles = typeof handles === "string" ?
12237 handles :
12238 "n,e,s,w,se,sw,ne,nw";
12239
12240 function filteredUi( ui ) {
12241 return {
12242 originalPosition: ui.originalPosition,
12243 originalSize: ui.originalSize,
12244 position: ui.position,
12245 size: ui.size
12246 };
12247 }
12248
12249 this.uiDialog.resizable( {
12250 cancel: ".ui-dialog-content",
12251 containment: "document",
12252 alsoResize: this.element,
12253 maxWidth: options.maxWidth,
12254 maxHeight: options.maxHeight,
12255 minWidth: options.minWidth,
12256 minHeight: this._minHeight(),
12257 handles: resizeHandles,
12258 start: function( event, ui ) {
12259 that._addClass( $( this ), "ui-dialog-resizing" );
12260 that._blockFrames();
12261 that._trigger( "resizeStart", event, filteredUi( ui ) );
12262 },
12263 resize: function( event, ui ) {
12264 that._trigger( "resize", event, filteredUi( ui ) );
12265 },
12266 stop: function( event, ui ) {
12267 var offset = that.uiDialog.offset(),
12268 left = offset.left - that.document.scrollLeft(),
12269 top = offset.top - that.document.scrollTop();
12270
12271 options.height = that.uiDialog.height();
12272 options.width = that.uiDialog.width();
12273 options.position = {
12274 my: "left top",
12275 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12276 "top" + ( top >= 0 ? "+" : "" ) + top,
12277 of: that.window
12278 };
12279 that._removeClass( $( this ), "ui-dialog-resizing" );
12280 that._unblockFrames();
12281 that._trigger( "resizeStop", event, filteredUi( ui ) );
12282 }
12283 } )
12284 .css( "position", position );
12285 },
12286
12287 _trackFocus: function() {
12288 this._on( this.widget(), {
12289 focusin: function( event ) {
12290 this._makeFocusTarget();
12291 this._focusedElement = $( event.target );
12292 }
12293 } );
12294 },
12295
12296 _makeFocusTarget: function() {
12297 this._untrackInstance();
12298 this._trackingInstances().unshift( this );
12299 },
12300
12301 _untrackInstance: function() {
12302 var instances = this._trackingInstances(),
12303 exists = $.inArray( this, instances );
12304 if ( exists !== -1 ) {
12305 instances.splice( exists, 1 );
12306 }
12307 },
12308
12309 _trackingInstances: function() {
12310 var instances = this.document.data( "ui-dialog-instances" );
12311 if ( !instances ) {
12312 instances = [];
12313 this.document.data( "ui-dialog-instances", instances );
12314 }
12315 return instances;
12316 },
12317
12318 _minHeight: function() {
12319 var options = this.options;
12320
12321 return options.height === "auto" ?
12322 options.minHeight :
12323 Math.min( options.minHeight, options.height );
12324 },
12325
12326 _position: function() {
12327
12328 // Need to show the dialog to get the actual offset in the position plugin
12329 var isVisible = this.uiDialog.is( ":visible" );
12330 if ( !isVisible ) {
12331 this.uiDialog.show();
12332 }
12333 this.uiDialog.position( this.options.position );
12334 if ( !isVisible ) {
12335 this.uiDialog.hide();
12336 }
12337 },
12338
12339 _setOptions: function( options ) {
12340 var that = this,
12341 resize = false,
12342 resizableOptions = {};
12343
12344 $.each( options, function( key, value ) {
12345 that._setOption( key, value );
12346
12347 if ( key in that.sizeRelatedOptions ) {
12348 resize = true;
12349 }
12350 if ( key in that.resizableRelatedOptions ) {
12351 resizableOptions[ key ] = value;
12352 }
12353 } );
12354
12355 if ( resize ) {
12356 this._size();
12357 this._position();
12358 }
12359 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12360 this.uiDialog.resizable( "option", resizableOptions );
12361 }
12362 },
12363
12364 _setOption: function( key, value ) {
12365 var isDraggable, isResizable,
12366 uiDialog = this.uiDialog;
12367
12368 if ( key === "disabled" ) {
12369 return;
12370 }
12371
12372 this._super( key, value );
12373
12374 if ( key === "appendTo" ) {
12375 this.uiDialog.appendTo( this._appendTo() );
12376 }
12377
12378 if ( key === "buttons" ) {
12379 this._createButtons();
12380 }
12381
12382 if ( key === "closeText" ) {
12383 this.uiDialogTitlebarClose.button( {
12384
12385 // Ensure that we always pass a string
12386 label: $( "<a>" ).text( "" + this.options.closeText ).html()
12387 } );
12388 }
12389
12390 if ( key === "draggable" ) {
12391 isDraggable = uiDialog.is( ":data(ui-draggable)" );
12392 if ( isDraggable && !value ) {
12393 uiDialog.draggable( "destroy" );
12394 }
12395
12396 if ( !isDraggable && value ) {
12397 this._makeDraggable();
12398 }
12399 }
12400
12401 if ( key === "position" ) {
12402 this._position();
12403 }
12404
12405 if ( key === "resizable" ) {
12406
12407 // currently resizable, becoming non-resizable
12408 isResizable = uiDialog.is( ":data(ui-resizable)" );
12409 if ( isResizable && !value ) {
12410 uiDialog.resizable( "destroy" );
12411 }
12412
12413 // Currently resizable, changing handles
12414 if ( isResizable && typeof value === "string" ) {
12415 uiDialog.resizable( "option", "handles", value );
12416 }
12417
12418 // Currently non-resizable, becoming resizable
12419 if ( !isResizable && value !== false ) {
12420 this._makeResizable();
12421 }
12422 }
12423
12424 if ( key === "title" ) {
12425 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
12426 }
12427 },
12428
12429 _size: function() {
12430
12431 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
12432 // divs will both have width and height set, so we need to reset them
12433 var nonContentHeight, minContentHeight, maxContentHeight,
12434 options = this.options;
12435
12436 // Reset content sizing
12437 this.element.show().css( {
12438 width: "auto",
12439 minHeight: 0,
12440 maxHeight: "none",
12441 height: 0
12442 } );
12443
12444 if ( options.minWidth > options.width ) {
12445 options.width = options.minWidth;
12446 }
12447
12448 // Reset wrapper sizing
12449 // determine the height of all the non-content elements
12450 nonContentHeight = this.uiDialog.css( {
12451 height: "auto",
12452 width: options.width
12453 } )
12454 .outerHeight();
12455 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
12456 maxContentHeight = typeof options.maxHeight === "number" ?
12457 Math.max( 0, options.maxHeight - nonContentHeight ) :
12458 "none";
12459
12460 if ( options.height === "auto" ) {
12461 this.element.css( {
12462 minHeight: minContentHeight,
12463 maxHeight: maxContentHeight,
12464 height: "auto"
12465 } );
12466 } else {
12467 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
12468 }
12469
12470 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12471 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
12472 }
12473 },
12474
12475 _blockFrames: function() {
12476 this.iframeBlocks = this.document.find( "iframe" ).map( function() {
12477 var iframe = $( this );
12478
12479 return $( "<div>" )
12480 .css( {
12481 position: "absolute",
12482 width: iframe.outerWidth(),
12483 height: iframe.outerHeight()
12484 } )
12485 .appendTo( iframe.parent() )
12486 .offset( iframe.offset() )[ 0 ];
12487 } );
12488 },
12489
12490 _unblockFrames: function() {
12491 if ( this.iframeBlocks ) {
12492 this.iframeBlocks.remove();
12493 delete this.iframeBlocks;
12494 }
12495 },
12496
12497 _allowInteraction: function( event ) {
12498 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
12499 return true;
12500 }
12501
12502 // TODO: Remove hack when datepicker implements
12503 // the .ui-front logic (#8989)
12504 return !!$( event.target ).closest( ".ui-datepicker" ).length;
12505 },
12506
12507 _createOverlay: function() {
12508 if ( !this.options.modal ) {
12509 return;
12510 }
12511
12512 // We use a delay in case the overlay is created from an
12513 // event that we're going to be cancelling (#2804)
12514 var isOpening = true;
12515 this._delay( function() {
12516 isOpening = false;
12517 } );
12518
12519 if ( !this.document.data( "ui-dialog-overlays" ) ) {
12520
12521 // Prevent use of anchors and inputs
12522 // Using _on() for an event handler shared across many instances is
12523 // safe because the dialogs stack and must be closed in reverse order
12524 this._on( this.document, {
12525 focusin: function( event ) {
12526 if ( isOpening ) {
12527 return;
12528 }
12529
12530 if ( !this._allowInteraction( event ) ) {
12531 event.preventDefault();
12532 this._trackingInstances()[ 0 ]._focusTabbable();
12533 }
12534 }
12535 } );
12536 }
12537
12538 this.overlay = $( "<div>" )
12539 .appendTo( this._appendTo() );
12540
12541 this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
12542 this._on( this.overlay, {
12543 mousedown: "_keepFocus"
12544 } );
12545 this.document.data( "ui-dialog-overlays",
12546 ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
12547 },
12548
12549 _destroyOverlay: function() {
12550 if ( !this.options.modal ) {
12551 return;
12552 }
12553
12554 if ( this.overlay ) {
12555 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
12556
12557 if ( !overlays ) {
12558 this._off( this.document, "focusin" );
12559 this.document.removeData( "ui-dialog-overlays" );
12560 } else {
12561 this.document.data( "ui-dialog-overlays", overlays );
12562 }
12563
12564 this.overlay.remove();
12565 this.overlay = null;
12566 }
12567 }
12568 } );
12569
12570 // DEPRECATED
12571 // TODO: switch return back to widget declaration at top of file when this is removed
12572 if ( $.uiBackCompat !== false ) {
12573
12574 // Backcompat for dialogClass option
12575 $.widget( "ui.dialog", $.ui.dialog, {
12576 options: {
12577 dialogClass: ""
12578 },
12579 _createWrapper: function() {
12580 this._super();
12581 this.uiDialog.addClass( this.options.dialogClass );
12582 },
12583 _setOption: function( key, value ) {
12584 if ( key === "dialogClass" ) {
12585 this.uiDialog
12586 .removeClass( this.options.dialogClass )
12587 .addClass( value );
12588 }
12589 this._superApply( arguments );
12590 }
12591 } );
12592 }
12593
12594 var widgetsDialog = $.ui.dialog;
12595
12596
12597 /*!
12598 * jQuery UI Progressbar 1.12.1
12599 * http://jqueryui.com
12600 *
12601 * Copyright jQuery Foundation and other contributors
12602 * Released under the MIT license.
12603 * http://jquery.org/license
12604 */
12605
12606 //>>label: Progressbar
12607 //>>group: Widgets
12608 // jscs:disable maximumLineLength
12609 //>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
12610 // jscs:enable maximumLineLength
12611 //>>docs: http://api.jqueryui.com/progressbar/
12612 //>>demos: http://jqueryui.com/progressbar/
12613 //>>css.structure: ../../themes/base/core.css
12614 //>>css.structure: ../../themes/base/progressbar.css
12615 //>>css.theme: ../../themes/base/theme.css
12616
12617
12618
12619 var widgetsProgressbar = $.widget( "ui.progressbar", {
12620 version: "1.12.1",
12621 options: {
12622 classes: {
12623 "ui-progressbar": "ui-corner-all",
12624 "ui-progressbar-value": "ui-corner-left",
12625 "ui-progressbar-complete": "ui-corner-right"
12626 },
12627 max: 100,
12628 value: 0,
12629
12630 change: null,
12631 complete: null
12632 },
12633
12634 min: 0,
12635
12636 _create: function() {
12637
12638 // Constrain initial value
12639 this.oldValue = this.options.value = this._constrainedValue();
12640
12641 this.element.attr( {
12642
12643 // Only set static values; aria-valuenow and aria-valuemax are
12644 // set inside _refreshValue()
12645 role: "progressbar",
12646 "aria-valuemin": this.min
12647 } );
12648 this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
12649
12650 this.valueDiv = $( "<div>" ).appendTo( this.element );
12651 this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
12652 this._refreshValue();
12653 },
12654
12655 _destroy: function() {
12656 this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
12657
12658 this.valueDiv.remove();
12659 },
12660
12661 value: function( newValue ) {
12662 if ( newValue === undefined ) {
12663 return this.options.value;
12664 }
12665
12666 this.options.value = this._constrainedValue( newValue );
12667 this._refreshValue();
12668 },
12669
12670 _constrainedValue: function( newValue ) {
12671 if ( newValue === undefined ) {
12672 newValue = this.options.value;
12673 }
12674
12675 this.indeterminate = newValue === false;
12676
12677 // Sanitize value
12678 if ( typeof newValue !== "number" ) {
12679 newValue = 0;
12680 }
12681
12682 return this.indeterminate ? false :
12683 Math.min( this.options.max, Math.max( this.min, newValue ) );
12684 },
12685
12686 _setOptions: function( options ) {
12687
12688 // Ensure "value" option is set after other values (like max)
12689 var value = options.value;
12690 delete options.value;
12691
12692 this._super( options );
12693
12694 this.options.value = this._constrainedValue( value );
12695 this._refreshValue();
12696 },
12697
12698 _setOption: function( key, value ) {
12699 if ( key === "max" ) {
12700
12701 // Don't allow a max less than min
12702 value = Math.max( this.min, value );
12703 }
12704 this._super( key, value );
12705 },
12706
12707 _setOptionDisabled: function( value ) {
12708 this._super( value );
12709
12710 this.element.attr( "aria-disabled", value );
12711 this._toggleClass( null, "ui-state-disabled", !!value );
12712 },
12713
12714 _percentage: function() {
12715 return this.indeterminate ?
12716 100 :
12717 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
12718 },
12719
12720 _refreshValue: function() {
12721 var value = this.options.value,
12722 percentage = this._percentage();
12723
12724 this.valueDiv
12725 .toggle( this.indeterminate || value > this.min )
12726 .width( percentage.toFixed( 0 ) + "%" );
12727
12728 this
12729 ._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
12730 value === this.options.max )
12731 ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
12732
12733 if ( this.indeterminate ) {
12734 this.element.removeAttr( "aria-valuenow" );
12735 if ( !this.overlayDiv ) {
12736 this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
12737 this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
12738 }
12739 } else {
12740 this.element.attr( {
12741 "aria-valuemax": this.options.max,
12742 "aria-valuenow": value
12743 } );
12744 if ( this.overlayDiv ) {
12745 this.overlayDiv.remove();
12746 this.overlayDiv = null;
12747 }
12748 }
12749
12750 if ( this.oldValue !== value ) {
12751 this.oldValue = value;
12752 this._trigger( "change" );
12753 }
12754 if ( value === this.options.max ) {
12755 this._trigger( "complete" );
12756 }
12757 }
12758 } );
12759
12760
12761 /*!
12762 * jQuery UI Selectmenu 1.12.1
12763 * http://jqueryui.com
12764 *
12765 * Copyright jQuery Foundation and other contributors
12766 * Released under the MIT license.
12767 * http://jquery.org/license
12768 */
12769
12770 //>>label: Selectmenu
12771 //>>group: Widgets
12772 // jscs:disable maximumLineLength
12773 //>>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.
12774 // jscs:enable maximumLineLength
12775 //>>docs: http://api.jqueryui.com/selectmenu/
12776 //>>demos: http://jqueryui.com/selectmenu/
12777 //>>css.structure: ../../themes/base/core.css
12778 //>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
12779 //>>css.theme: ../../themes/base/theme.css
12780
12781
12782
12783 var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
12784 version: "1.12.1",
12785 defaultElement: "<select>",
12786 options: {
12787 appendTo: null,
12788 classes: {
12789 "ui-selectmenu-button-open": "ui-corner-top",
12790 "ui-selectmenu-button-closed": "ui-corner-all"
12791 },
12792 disabled: null,
12793 icons: {
12794 button: "ui-icon-triangle-1-s"
12795 },
12796 position: {
12797 my: "left top",
12798 at: "left bottom",
12799 collision: "none"
12800 },
12801 width: false,
12802
12803 // Callbacks
12804 change: null,
12805 close: null,
12806 focus: null,
12807 open: null,
12808 select: null
12809 },
12810
12811 _create: function() {
12812 var selectmenuId = this.element.uniqueId().attr( "id" );
12813 this.ids = {
12814 element: selectmenuId,
12815 button: selectmenuId + "-button",
12816 menu: selectmenuId + "-menu"
12817 };
12818
12819 this._drawButton();
12820 this._drawMenu();
12821 this._bindFormResetHandler();
12822
12823 this._rendered = false;
12824 this.menuItems = $();
12825 },
12826
12827 _drawButton: function() {
12828 var icon,
12829 that = this,
12830 item = this._parseOption(
12831 this.element.find( "option:selected" ),
12832 this.element[ 0 ].selectedIndex
12833 );
12834
12835 // Associate existing label with the new button
12836 this.labels = this.element.labels().attr( "for", this.ids.button );
12837 this._on( this.labels, {
12838 click: function( event ) {
12839 this.button.focus();
12840 event.preventDefault();
12841 }
12842 } );
12843
12844 // Hide original select element
12845 this.element.hide();
12846
12847 // Create button
12848 this.button = $( "<span>", {
12849 tabindex: this.options.disabled ? -1 : 0,
12850 id: this.ids.button,
12851 role: "combobox",
12852 "aria-expanded": "false",
12853 "aria-autocomplete": "list",
12854 "aria-owns": this.ids.menu,
12855 "aria-haspopup": "true",
12856 title: this.element.attr( "title" )
12857 } )
12858 .insertAfter( this.element );
12859
12860 this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
12861 "ui-button ui-widget" );
12862
12863 icon = $( "<span>" ).appendTo( this.button );
12864 this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
12865 this.buttonItem = this._renderButtonItem( item )
12866 .appendTo( this.button );
12867
12868 if ( this.options.width !== false ) {
12869 this._resizeButton();
12870 }
12871
12872 this._on( this.button, this._buttonEvents );
12873 this.button.one( "focusin", function() {
12874
12875 // Delay rendering the menu items until the button receives focus.
12876 // The menu may have already been rendered via a programmatic open.
12877 if ( !that._rendered ) {
12878 that._refreshMenu();
12879 }
12880 } );
12881 },
12882
12883 _drawMenu: function() {
12884 var that = this;
12885
12886 // Create menu
12887 this.menu = $( "<ul>", {
12888 "aria-hidden": "true",
12889 "aria-labelledby": this.ids.button,
12890 id: this.ids.menu
12891 } );
12892
12893 // Wrap menu
12894 this.menuWrap = $( "<div>" ).append( this.menu );
12895 this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
12896 this.menuWrap.appendTo( this._appendTo() );
12897
12898 // Initialize menu widget
12899 this.menuInstance = this.menu
12900 .menu( {
12901 classes: {
12902 "ui-menu": "ui-corner-bottom"
12903 },
12904 role: "listbox",
12905 select: function( event, ui ) {
12906 event.preventDefault();
12907
12908 // Support: IE8
12909 // If the item was selected via a click, the text selection
12910 // will be destroyed in IE
12911 that._setSelection();
12912
12913 that._select( ui.item.data( "ui-selectmenu-item" ), event );
12914 },
12915 focus: function( event, ui ) {
12916 var item = ui.item.data( "ui-selectmenu-item" );
12917
12918 // Prevent inital focus from firing and check if its a newly focused item
12919 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
12920 that._trigger( "focus", event, { item: item } );
12921 if ( !that.isOpen ) {
12922 that._select( item, event );
12923 }
12924 }
12925 that.focusIndex = item.index;
12926
12927 that.button.attr( "aria-activedescendant",
12928 that.menuItems.eq( item.index ).attr( "id" ) );
12929 }
12930 } )
12931 .menu( "instance" );
12932
12933 // Don't close the menu on mouseleave
12934 this.menuInstance._off( this.menu, "mouseleave" );
12935
12936 // Cancel the menu's collapseAll on document click
12937 this.menuInstance._closeOnDocumentClick = function() {
12938 return false;
12939 };
12940
12941 // Selects often contain empty items, but never contain dividers
12942 this.menuInstance._isDivider = function() {
12943 return false;
12944 };
12945 },
12946
12947 refresh: function() {
12948 this._refreshMenu();
12949 this.buttonItem.replaceWith(
12950 this.buttonItem = this._renderButtonItem(
12951
12952 // Fall back to an empty object in case there are no options
12953 this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
12954 )
12955 );
12956 if ( this.options.width === null ) {
12957 this._resizeButton();
12958 }
12959 },
12960
12961 _refreshMenu: function() {
12962 var item,
12963 options = this.element.find( "option" );
12964
12965 this.menu.empty();
12966
12967 this._parseOptions( options );
12968 this._renderMenu( this.menu, this.items );
12969
12970 this.menuInstance.refresh();
12971 this.menuItems = this.menu.find( "li" )
12972 .not( ".ui-selectmenu-optgroup" )
12973 .find( ".ui-menu-item-wrapper" );
12974
12975 this._rendered = true;
12976
12977 if ( !options.length ) {
12978 return;
12979 }
12980
12981 item = this._getSelectedItem();
12982
12983 // Update the menu to have the correct item focused
12984 this.menuInstance.focus( null, item );
12985 this._setAria( item.data( "ui-selectmenu-item" ) );
12986
12987 // Set disabled state
12988 this._setOption( "disabled", this.element.prop( "disabled" ) );
12989 },
12990
12991 open: function( event ) {
12992 if ( this.options.disabled ) {
12993 return;
12994 }
12995
12996 // If this is the first time the menu is being opened, render the items
12997 if ( !this._rendered ) {
12998 this._refreshMenu();
12999 } else {
13000
13001 // Menu clears focus on close, reset focus to selected item
13002 this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
13003 this.menuInstance.focus( null, this._getSelectedItem() );
13004 }
13005
13006 // If there are no options, don't open the menu
13007 if ( !this.menuItems.length ) {
13008 return;
13009 }
13010
13011 this.isOpen = true;
13012 this._toggleAttr();
13013 this._resizeMenu();
13014 this._position();
13015
13016 this._on( this.document, this._documentClick );
13017
13018 this._trigger( "open", event );
13019 },
13020
13021 _position: function() {
13022 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
13023 },
13024
13025 close: function( event ) {
13026 if ( !this.isOpen ) {
13027 return;
13028 }
13029
13030 this.isOpen = false;
13031 this._toggleAttr();
13032
13033 this.range = null;
13034 this._off( this.document );
13035
13036 this._trigger( "close", event );
13037 },
13038
13039 widget: function() {
13040 return this.button;
13041 },
13042
13043 menuWidget: function() {
13044 return this.menu;
13045 },
13046
13047 _renderButtonItem: function( item ) {
13048 var buttonItem = $( "<span>" );
13049
13050 this._setText( buttonItem, item.label );
13051 this._addClass( buttonItem, "ui-selectmenu-text" );
13052
13053 return buttonItem;
13054 },
13055
13056 _renderMenu: function( ul, items ) {
13057 var that = this,
13058 currentOptgroup = "";
13059
13060 $.each( items, function( index, item ) {
13061 var li;
13062
13063 if ( item.optgroup !== currentOptgroup ) {
13064 li = $( "<li>", {
13065 text: item.optgroup
13066 } );
13067 that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
13068 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
13069 " ui-state-disabled" :
13070 "" ) );
13071
13072 li.appendTo( ul );
13073
13074 currentOptgroup = item.optgroup;
13075 }
13076
13077 that._renderItemData( ul, item );
13078 } );
13079 },
13080
13081 _renderItemData: function( ul, item ) {
13082 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
13083 },
13084
13085 _renderItem: function( ul, item ) {
13086 var li = $( "<li>" ),
13087 wrapper = $( "<div>", {
13088 title: item.element.attr( "title" )
13089 } );
13090
13091 if ( item.disabled ) {
13092 this._addClass( li, null, "ui-state-disabled" );
13093 }
13094 this._setText( wrapper, item.label );
13095
13096 return li.append( wrapper ).appendTo( ul );
13097 },
13098
13099 _setText: function( element, value ) {
13100 if ( value ) {
13101 element.text( value );
13102 } else {
13103 element.html( "&#160;" );
13104 }
13105 },
13106
13107 _move: function( direction, event ) {
13108 var item, next,
13109 filter = ".ui-menu-item";
13110
13111 if ( this.isOpen ) {
13112 item = this.menuItems.eq( this.focusIndex ).parent( "li" );
13113 } else {
13114 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
13115 filter += ":not(.ui-state-disabled)";
13116 }
13117
13118 if ( direction === "first" || direction === "last" ) {
13119 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
13120 } else {
13121 next = item[ direction + "All" ]( filter ).eq( 0 );
13122 }
13123
13124 if ( next.length ) {
13125 this.menuInstance.focus( event, next );
13126 }
13127 },
13128
13129 _getSelectedItem: function() {
13130 return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
13131 },
13132
13133 _toggle: function( event ) {
13134 this[ this.isOpen ? "close" : "open" ]( event );
13135 },
13136
13137 _setSelection: function() {
13138 var selection;
13139
13140 if ( !this.range ) {
13141 return;
13142 }
13143
13144 if ( window.getSelection ) {
13145 selection = window.getSelection();
13146 selection.removeAllRanges();
13147 selection.addRange( this.range );
13148
13149 // Support: IE8
13150 } else {
13151 this.range.select();
13152 }
13153
13154 // Support: IE
13155 // Setting the text selection kills the button focus in IE, but
13156 // restoring the focus doesn't kill the selection.
13157 this.button.focus();
13158 },
13159
13160 _documentClick: {
13161 mousedown: function( event ) {
13162 if ( !this.isOpen ) {
13163 return;
13164 }
13165
13166 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
13167 $.ui.escapeSelector( this.ids.button ) ).length ) {
13168 this.close( event );
13169 }
13170 }
13171 },
13172
13173 _buttonEvents: {
13174
13175 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
13176 mousedown: function() {
13177 var selection;
13178
13179 if ( window.getSelection ) {
13180 selection = window.getSelection();
13181 if ( selection.rangeCount ) {
13182 this.range = selection.getRangeAt( 0 );
13183 }
13184
13185 // Support: IE8
13186 } else {
13187 this.range = document.selection.createRange();
13188 }
13189 },
13190
13191 click: function( event ) {
13192 this._setSelection();
13193 this._toggle( event );
13194 },
13195
13196 keydown: function( event ) {
13197 var preventDefault = true;
13198 switch ( event.keyCode ) {
13199 case $.ui.keyCode.TAB:
13200 case $.ui.keyCode.ESCAPE:
13201 this.close( event );
13202 preventDefault = false;
13203 break;
13204 case $.ui.keyCode.ENTER:
13205 if ( this.isOpen ) {
13206 this._selectFocusedItem( event );
13207 }
13208 break;
13209 case $.ui.keyCode.UP:
13210 if ( event.altKey ) {
13211 this._toggle( event );
13212 } else {
13213 this._move( "prev", event );
13214 }
13215 break;
13216 case $.ui.keyCode.DOWN:
13217 if ( event.altKey ) {
13218 this._toggle( event );
13219 } else {
13220 this._move( "next", event );
13221 }
13222 break;
13223 case $.ui.keyCode.SPACE:
13224 if ( this.isOpen ) {
13225 this._selectFocusedItem( event );
13226 } else {
13227 this._toggle( event );
13228 }
13229 break;
13230 case $.ui.keyCode.LEFT:
13231 this._move( "prev", event );
13232 break;
13233 case $.ui.keyCode.RIGHT:
13234 this._move( "next", event );
13235 break;
13236 case $.ui.keyCode.HOME:
13237 case $.ui.keyCode.PAGE_UP:
13238 this._move( "first", event );
13239 break;
13240 case $.ui.keyCode.END:
13241 case $.ui.keyCode.PAGE_DOWN:
13242 this._move( "last", event );
13243 break;
13244 default:
13245 this.menu.trigger( event );
13246 preventDefault = false;
13247 }
13248
13249 if ( preventDefault ) {
13250 event.preventDefault();
13251 }
13252 }
13253 },
13254
13255 _selectFocusedItem: function( event ) {
13256 var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
13257 if ( !item.hasClass( "ui-state-disabled" ) ) {
13258 this._select( item.data( "ui-selectmenu-item" ), event );
13259 }
13260 },
13261
13262 _select: function( item, event ) {
13263 var oldIndex = this.element[ 0 ].selectedIndex;
13264
13265 // Change native select element
13266 this.element[ 0 ].selectedIndex = item.index;
13267 this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
13268 this._setAria( item );
13269 this._trigger( "select", event, { item: item } );
13270
13271 if ( item.index !== oldIndex ) {
13272 this._trigger( "change", event, { item: item } );
13273 }
13274
13275 this.close( event );
13276 },
13277
13278 _setAria: function( item ) {
13279 var id = this.menuItems.eq( item.index ).attr( "id" );
13280
13281 this.button.attr( {
13282 "aria-labelledby": id,
13283 "aria-activedescendant": id
13284 } );
13285 this.menu.attr( "aria-activedescendant", id );
13286 },
13287
13288 _setOption: function( key, value ) {
13289 if ( key === "icons" ) {
13290 var icon = this.button.find( "span.ui-icon" );
13291 this._removeClass( icon, null, this.options.icons.button )
13292 ._addClass( icon, null, value.button );
13293 }
13294
13295 this._super( key, value );
13296
13297 if ( key === "appendTo" ) {
13298 this.menuWrap.appendTo( this._appendTo() );
13299 }
13300
13301 if ( key === "width" ) {
13302 this._resizeButton();
13303 }
13304 },
13305
13306 _setOptionDisabled: function( value ) {
13307 this._super( value );
13308
13309 this.menuInstance.option( "disabled", value );
13310 this.button.attr( "aria-disabled", value );
13311 this._toggleClass( this.button, null, "ui-state-disabled", value );
13312
13313 this.element.prop( "disabled", value );
13314 if ( value ) {
13315 this.button.attr( "tabindex", -1 );
13316 this.close();
13317 } else {
13318 this.button.attr( "tabindex", 0 );
13319 }
13320 },
13321
13322 _appendTo: function() {
13323 var element = this.options.appendTo;
13324
13325 if ( element ) {
13326 element = element.jquery || element.nodeType ?
13327 $( element ) :
13328 this.document.find( element ).eq( 0 );
13329 }
13330
13331 if ( !element || !element[ 0 ] ) {
13332 element = this.element.closest( ".ui-front, dialog" );
13333 }
13334
13335 if ( !element.length ) {
13336 element = this.document[ 0 ].body;
13337 }
13338
13339 return element;
13340 },
13341
13342 _toggleAttr: function() {
13343 this.button.attr( "aria-expanded", this.isOpen );
13344
13345 // We can't use two _toggleClass() calls here, because we need to make sure
13346 // we always remove classes first and add them second, otherwise if both classes have the
13347 // same theme class, it will be removed after we add it.
13348 this._removeClass( this.button, "ui-selectmenu-button-" +
13349 ( this.isOpen ? "closed" : "open" ) )
13350 ._addClass( this.button, "ui-selectmenu-button-" +
13351 ( this.isOpen ? "open" : "closed" ) )
13352 ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
13353
13354 this.menu.attr( "aria-hidden", !this.isOpen );
13355 },
13356
13357 _resizeButton: function() {
13358 var width = this.options.width;
13359
13360 // For `width: false`, just remove inline style and stop
13361 if ( width === false ) {
13362 this.button.css( "width", "" );
13363 return;
13364 }
13365
13366 // For `width: null`, match the width of the original element
13367 if ( width === null ) {
13368 width = this.element.show().outerWidth();
13369 this.element.hide();
13370 }
13371
13372 this.button.outerWidth( width );
13373 },
13374
13375 _resizeMenu: function() {
13376 this.menu.outerWidth( Math.max(
13377 this.button.outerWidth(),
13378
13379 // Support: IE10
13380 // IE10 wraps long text (possibly a rounding bug)
13381 // so we add 1px to avoid the wrapping
13382 this.menu.width( "" ).outerWidth() + 1
13383 ) );
13384 },
13385
13386 _getCreateOptions: function() {
13387 var options = this._super();
13388
13389 options.disabled = this.element.prop( "disabled" );
13390
13391 return options;
13392 },
13393
13394 _parseOptions: function( options ) {
13395 var that = this,
13396 data = [];
13397 options.each( function( index, item ) {
13398 data.push( that._parseOption( $( item ), index ) );
13399 } );
13400 this.items = data;
13401 },
13402
13403 _parseOption: function( option, index ) {
13404 var optgroup = option.parent( "optgroup" );
13405
13406 return {
13407 element: option,
13408 index: index,
13409 value: option.val(),
13410 label: option.text(),
13411 optgroup: optgroup.attr( "label" ) || "",
13412 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
13413 };
13414 },
13415
13416 _destroy: function() {
13417 this._unbindFormResetHandler();
13418 this.menuWrap.remove();
13419 this.button.remove();
13420 this.element.show();
13421 this.element.removeUniqueId();
13422 this.labels.attr( "for", this.ids.element );
13423 }
13424 } ] );
13425
13426
13427 /*!
13428 * jQuery UI Slider 1.12.1
13429 * http://jqueryui.com
13430 *
13431 * Copyright jQuery Foundation and other contributors
13432 * Released under the MIT license.
13433 * http://jquery.org/license
13434 */
13435
13436 //>>label: Slider
13437 //>>group: Widgets
13438 //>>description: Displays a flexible slider with ranges and accessibility via keyboard.
13439 //>>docs: http://api.jqueryui.com/slider/
13440 //>>demos: http://jqueryui.com/slider/
13441 //>>css.structure: ../../themes/base/core.css
13442 //>>css.structure: ../../themes/base/slider.css
13443 //>>css.theme: ../../themes/base/theme.css
13444
13445
13446
13447 var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
13448 version: "1.12.1",
13449 widgetEventPrefix: "slide",
13450
13451 options: {
13452 animate: false,
13453 classes: {
13454 "ui-slider": "ui-corner-all",
13455 "ui-slider-handle": "ui-corner-all",
13456
13457 // Note: ui-widget-header isn't the most fittingly semantic framework class for this
13458 // element, but worked best visually with a variety of themes
13459 "ui-slider-range": "ui-corner-all ui-widget-header"
13460 },
13461 distance: 0,
13462 max: 100,
13463 min: 0,
13464 orientation: "horizontal",
13465 range: false,
13466 step: 1,
13467 value: 0,
13468 values: null,
13469
13470 // Callbacks
13471 change: null,
13472 slide: null,
13473 start: null,
13474 stop: null
13475 },
13476
13477 // Number of pages in a slider
13478 // (how many times can you page up/down to go through the whole range)
13479 numPages: 5,
13480
13481 _create: function() {
13482 this._keySliding = false;
13483 this._mouseSliding = false;
13484 this._animateOff = true;
13485 this._handleIndex = null;
13486 this._detectOrientation();
13487 this._mouseInit();
13488 this._calculateNewMax();
13489
13490 this._addClass( "ui-slider ui-slider-" + this.orientation,
13491 "ui-widget ui-widget-content" );
13492
13493 this._refresh();
13494
13495 this._animateOff = false;
13496 },
13497
13498 _refresh: function() {
13499 this._createRange();
13500 this._createHandles();
13501 this._setupEvents();
13502 this._refreshValue();
13503 },
13504
13505 _createHandles: function() {
13506 var i, handleCount,
13507 options = this.options,
13508 existingHandles = this.element.find( ".ui-slider-handle" ),
13509 handle = "<span tabindex='0'></span>",
13510 handles = [];
13511
13512 handleCount = ( options.values && options.values.length ) || 1;
13513
13514 if ( existingHandles.length > handleCount ) {
13515 existingHandles.slice( handleCount ).remove();
13516 existingHandles = existingHandles.slice( 0, handleCount );
13517 }
13518
13519 for ( i = existingHandles.length; i < handleCount; i++ ) {
13520 handles.push( handle );
13521 }
13522
13523 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
13524
13525 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
13526
13527 this.handle = this.handles.eq( 0 );
13528
13529 this.handles.each( function( i ) {
13530 $( this )
13531 .data( "ui-slider-handle-index", i )
13532 .attr( "tabIndex", 0 );
13533 } );
13534 },
13535
13536 _createRange: function() {
13537 var options = this.options;
13538
13539 if ( options.range ) {
13540 if ( options.range === true ) {
13541 if ( !options.values ) {
13542 options.values = [ this._valueMin(), this._valueMin() ];
13543 } else if ( options.values.length && options.values.length !== 2 ) {
13544 options.values = [ options.values[ 0 ], options.values[ 0 ] ];
13545 } else if ( $.isArray( options.values ) ) {
13546 options.values = options.values.slice( 0 );
13547 }
13548 }
13549
13550 if ( !this.range || !this.range.length ) {
13551 this.range = $( "<div>" )
13552 .appendTo( this.element );
13553
13554 this._addClass( this.range, "ui-slider-range" );
13555 } else {
13556 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
13557
13558 // Handle range switching from true to min/max
13559 this.range.css( {
13560 "left": "",
13561 "bottom": ""
13562 } );
13563 }
13564 if ( options.range === "min" || options.range === "max" ) {
13565 this._addClass( this.range, "ui-slider-range-" + options.range );
13566 }
13567 } else {
13568 if ( this.range ) {
13569 this.range.remove();
13570 }
13571 this.range = null;
13572 }
13573 },
13574
13575 _setupEvents: function() {
13576 this._off( this.handles );
13577 this._on( this.handles, this._handleEvents );
13578 this._hoverable( this.handles );
13579 this._focusable( this.handles );
13580 },
13581
13582 _destroy: function() {
13583 this.handles.remove();
13584 if ( this.range ) {
13585 this.range.remove();
13586 }
13587
13588 this._mouseDestroy();
13589 },
13590
13591 _mouseCapture: function( event ) {
13592 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
13593 that = this,
13594 o = this.options;
13595
13596 if ( o.disabled ) {
13597 return false;
13598 }
13599
13600 this.elementSize = {
13601 width: this.element.outerWidth(),
13602 height: this.element.outerHeight()
13603 };
13604 this.elementOffset = this.element.offset();
13605
13606 position = { x: event.pageX, y: event.pageY };
13607 normValue = this._normValueFromMouse( position );
13608 distance = this._valueMax() - this._valueMin() + 1;
13609 this.handles.each( function( i ) {
13610 var thisDistance = Math.abs( normValue - that.values( i ) );
13611 if ( ( distance > thisDistance ) ||
13612 ( distance === thisDistance &&
13613 ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
13614 distance = thisDistance;
13615 closestHandle = $( this );
13616 index = i;
13617 }
13618 } );
13619
13620 allowed = this._start( event, index );
13621 if ( allowed === false ) {
13622 return false;
13623 }
13624 this._mouseSliding = true;
13625
13626 this._handleIndex = index;
13627
13628 this._addClass( closestHandle, null, "ui-state-active" );
13629 closestHandle.trigger( "focus" );
13630
13631 offset = closestHandle.offset();
13632 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
13633 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
13634 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
13635 top: event.pageY - offset.top -
13636 ( closestHandle.height() / 2 ) -
13637 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
13638 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
13639 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
13640 };
13641
13642 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
13643 this._slide( event, index, normValue );
13644 }
13645 this._animateOff = true;
13646 return true;
13647 },
13648
13649 _mouseStart: function() {
13650 return true;
13651 },
13652
13653 _mouseDrag: function( event ) {
13654 var position = { x: event.pageX, y: event.pageY },
13655 normValue = this._normValueFromMouse( position );
13656
13657 this._slide( event, this._handleIndex, normValue );
13658
13659 return false;
13660 },
13661
13662 _mouseStop: function( event ) {
13663 this._removeClass( this.handles, null, "ui-state-active" );
13664 this._mouseSliding = false;
13665
13666 this._stop( event, this._handleIndex );
13667 this._change( event, this._handleIndex );
13668
13669 this._handleIndex = null;
13670 this._clickOffset = null;
13671 this._animateOff = false;
13672
13673 return false;
13674 },
13675
13676 _detectOrientation: function() {
13677 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
13678 },
13679
13680 _normValueFromMouse: function( position ) {
13681 var pixelTotal,
13682 pixelMouse,
13683 percentMouse,
13684 valueTotal,
13685 valueMouse;
13686
13687 if ( this.orientation === "horizontal" ) {
13688 pixelTotal = this.elementSize.width;
13689 pixelMouse = position.x - this.elementOffset.left -
13690 ( this._clickOffset ? this._clickOffset.left : 0 );
13691 } else {
13692 pixelTotal = this.elementSize.height;
13693 pixelMouse = position.y - this.elementOffset.top -
13694 ( this._clickOffset ? this._clickOffset.top : 0 );
13695 }
13696
13697 percentMouse = ( pixelMouse / pixelTotal );
13698 if ( percentMouse > 1 ) {
13699 percentMouse = 1;
13700 }
13701 if ( percentMouse < 0 ) {
13702 percentMouse = 0;
13703 }
13704 if ( this.orientation === "vertical" ) {
13705 percentMouse = 1 - percentMouse;
13706 }
13707
13708 valueTotal = this._valueMax() - this._valueMin();
13709 valueMouse = this._valueMin() + percentMouse * valueTotal;
13710
13711 return this._trimAlignValue( valueMouse );
13712 },
13713
13714 _uiHash: function( index, value, values ) {
13715 var uiHash = {
13716 handle: this.handles[ index ],
13717 handleIndex: index,
13718 value: value !== undefined ? value : this.value()
13719 };
13720
13721 if ( this._hasMultipleValues() ) {
13722 uiHash.value = value !== undefined ? value : this.values( index );
13723 uiHash.values = values || this.values();
13724 }
13725
13726 return uiHash;
13727 },
13728
13729 _hasMultipleValues: function() {
13730 return this.options.values && this.options.values.length;
13731 },
13732
13733 _start: function( event, index ) {
13734 return this._trigger( "start", event, this._uiHash( index ) );
13735 },
13736
13737 _slide: function( event, index, newVal ) {
13738 var allowed, otherVal,
13739 currentValue = this.value(),
13740 newValues = this.values();
13741
13742 if ( this._hasMultipleValues() ) {
13743 otherVal = this.values( index ? 0 : 1 );
13744 currentValue = this.values( index );
13745
13746 if ( this.options.values.length === 2 && this.options.range === true ) {
13747 newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
13748 }
13749
13750 newValues[ index ] = newVal;
13751 }
13752
13753 if ( newVal === currentValue ) {
13754 return;
13755 }
13756
13757 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
13758
13759 // A slide can be canceled by returning false from the slide callback
13760 if ( allowed === false ) {
13761 return;
13762 }
13763
13764 if ( this._hasMultipleValues() ) {
13765 this.values( index, newVal );
13766 } else {
13767 this.value( newVal );
13768 }
13769 },
13770
13771 _stop: function( event, index ) {
13772 this._trigger( "stop", event, this._uiHash( index ) );
13773 },
13774
13775 _change: function( event, index ) {
13776 if ( !this._keySliding && !this._mouseSliding ) {
13777
13778 //store the last changed value index for reference when handles overlap
13779 this._lastChangedValue = index;
13780 this._trigger( "change", event, this._uiHash( index ) );
13781 }
13782 },
13783
13784 value: function( newValue ) {
13785 if ( arguments.length ) {
13786 this.options.value = this._trimAlignValue( newValue );
13787 this._refreshValue();
13788 this._change( null, 0 );
13789 return;
13790 }
13791
13792 return this._value();
13793 },
13794
13795 values: function( index, newValue ) {
13796 var vals,
13797 newValues,
13798 i;
13799
13800 if ( arguments.length > 1 ) {
13801 this.options.values[ index ] = this._trimAlignValue( newValue );
13802 this._refreshValue();
13803 this._change( null, index );
13804 return;
13805 }
13806
13807 if ( arguments.length ) {
13808 if ( $.isArray( arguments[ 0 ] ) ) {
13809 vals = this.options.values;
13810 newValues = arguments[ 0 ];
13811 for ( i = 0; i < vals.length; i += 1 ) {
13812 vals[ i ] = this._trimAlignValue( newValues[ i ] );
13813 this._change( null, i );
13814 }
13815 this._refreshValue();
13816 } else {
13817 if ( this._hasMultipleValues() ) {
13818 return this._values( index );
13819 } else {
13820 return this.value();
13821 }
13822 }
13823 } else {
13824 return this._values();
13825 }
13826 },
13827
13828 _setOption: function( key, value ) {
13829 var i,
13830 valsLength = 0;
13831
13832 if ( key === "range" && this.options.range === true ) {
13833 if ( value === "min" ) {
13834 this.options.value = this._values( 0 );
13835 this.options.values = null;
13836 } else if ( value === "max" ) {
13837 this.options.value = this._values( this.options.values.length - 1 );
13838 this.options.values = null;
13839 }
13840 }
13841
13842 if ( $.isArray( this.options.values ) ) {
13843 valsLength = this.options.values.length;
13844 }
13845
13846 this._super( key, value );
13847
13848 switch ( key ) {
13849 case "orientation":
13850 this._detectOrientation();
13851 this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
13852 ._addClass( "ui-slider-" + this.orientation );
13853 this._refreshValue();
13854 if ( this.options.range ) {
13855 this._refreshRange( value );
13856 }
13857
13858 // Reset positioning from previous orientation
13859 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
13860 break;
13861 case "value":
13862 this._animateOff = true;
13863 this._refreshValue();
13864 this._change( null, 0 );
13865 this._animateOff = false;
13866 break;
13867 case "values":
13868 this._animateOff = true;
13869 this._refreshValue();
13870
13871 // Start from the last handle to prevent unreachable handles (#9046)
13872 for ( i = valsLength - 1; i >= 0; i-- ) {
13873 this._change( null, i );
13874 }
13875 this._animateOff = false;
13876 break;
13877 case "step":
13878 case "min":
13879 case "max":
13880 this._animateOff = true;
13881 this._calculateNewMax();
13882 this._refreshValue();
13883 this._animateOff = false;
13884 break;
13885 case "range":
13886 this._animateOff = true;
13887 this._refresh();
13888 this._animateOff = false;
13889 break;
13890 }
13891 },
13892
13893 _setOptionDisabled: function( value ) {
13894 this._super( value );
13895
13896 this._toggleClass( null, "ui-state-disabled", !!value );
13897 },
13898
13899 //internal value getter
13900 // _value() returns value trimmed by min and max, aligned by step
13901 _value: function() {
13902 var val = this.options.value;
13903 val = this._trimAlignValue( val );
13904
13905 return val;
13906 },
13907
13908 //internal values getter
13909 // _values() returns array of values trimmed by min and max, aligned by step
13910 // _values( index ) returns single value trimmed by min and max, aligned by step
13911 _values: function( index ) {
13912 var val,
13913 vals,
13914 i;
13915
13916 if ( arguments.length ) {
13917 val = this.options.values[ index ];
13918 val = this._trimAlignValue( val );
13919
13920 return val;
13921 } else if ( this._hasMultipleValues() ) {
13922
13923 // .slice() creates a copy of the array
13924 // this copy gets trimmed by min and max and then returned
13925 vals = this.options.values.slice();
13926 for ( i = 0; i < vals.length; i += 1 ) {
13927 vals[ i ] = this._trimAlignValue( vals[ i ] );
13928 }
13929
13930 return vals;
13931 } else {
13932 return [];
13933 }
13934 },
13935
13936 // Returns the step-aligned value that val is closest to, between (inclusive) min and max
13937 _trimAlignValue: function( val ) {
13938 if ( val <= this._valueMin() ) {
13939 return this._valueMin();
13940 }
13941 if ( val >= this._valueMax() ) {
13942 return this._valueMax();
13943 }
13944 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13945 valModStep = ( val - this._valueMin() ) % step,
13946 alignValue = val - valModStep;
13947
13948 if ( Math.abs( valModStep ) * 2 >= step ) {
13949 alignValue += ( valModStep > 0 ) ? step : ( -step );
13950 }
13951
13952 // Since JavaScript has problems with large floats, round
13953 // the final value to 5 digits after the decimal point (see #4124)
13954 return parseFloat( alignValue.toFixed( 5 ) );
13955 },
13956
13957 _calculateNewMax: function() {
13958 var max = this.options.max,
13959 min = this._valueMin(),
13960 step = this.options.step,
13961 aboveMin = Math.round( ( max - min ) / step ) * step;
13962 max = aboveMin + min;
13963 if ( max > this.options.max ) {
13964
13965 //If max is not divisible by step, rounding off may increase its value
13966 max -= step;
13967 }
13968 this.max = parseFloat( max.toFixed( this._precision() ) );
13969 },
13970
13971 _precision: function() {
13972 var precision = this._precisionOf( this.options.step );
13973 if ( this.options.min !== null ) {
13974 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13975 }
13976 return precision;
13977 },
13978
13979 _precisionOf: function( num ) {
13980 var str = num.toString(),
13981 decimal = str.indexOf( "." );
13982 return decimal === -1 ? 0 : str.length - decimal - 1;
13983 },
13984
13985 _valueMin: function() {
13986 return this.options.min;
13987 },
13988
13989 _valueMax: function() {
13990 return this.max;
13991 },
13992
13993 _refreshRange: function( orientation ) {
13994 if ( orientation === "vertical" ) {
13995 this.range.css( { "width": "", "left": "" } );
13996 }
13997 if ( orientation === "horizontal" ) {
13998 this.range.css( { "height": "", "bottom": "" } );
13999 }
14000 },
14001
14002 _refreshValue: function() {
14003 var lastValPercent, valPercent, value, valueMin, valueMax,
14004 oRange = this.options.range,
14005 o = this.options,
14006 that = this,
14007 animate = ( !this._animateOff ) ? o.animate : false,
14008 _set = {};
14009
14010 if ( this._hasMultipleValues() ) {
14011 this.handles.each( function( i ) {
14012 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
14013 that._valueMin() ) * 100;
14014 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
14015 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
14016 if ( that.options.range === true ) {
14017 if ( that.orientation === "horizontal" ) {
14018 if ( i === 0 ) {
14019 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
14020 left: valPercent + "%"
14021 }, o.animate );
14022 }
14023 if ( i === 1 ) {
14024 that.range[ animate ? "animate" : "css" ]( {
14025 width: ( valPercent - lastValPercent ) + "%"
14026 }, {
14027 queue: false,
14028 duration: o.animate
14029 } );
14030 }
14031 } else {
14032 if ( i === 0 ) {
14033 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
14034 bottom: ( valPercent ) + "%"
14035 }, o.animate );
14036 }
14037 if ( i === 1 ) {
14038 that.range[ animate ? "animate" : "css" ]( {
14039 height: ( valPercent - lastValPercent ) + "%"
14040 }, {
14041 queue: false,
14042 duration: o.animate
14043 } );
14044 }
14045 }
14046 }
14047 lastValPercent = valPercent;
14048 } );
14049 } else {
14050 value = this.value();
14051 valueMin = this._valueMin();
14052 valueMax = this._valueMax();
14053 valPercent = ( valueMax !== valueMin ) ?
14054 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
14055 0;
14056 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
14057 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
14058
14059 if ( oRange === "min" && this.orientation === "horizontal" ) {
14060 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
14061 width: valPercent + "%"
14062 }, o.animate );
14063 }
14064 if ( oRange === "max" && this.orientation === "horizontal" ) {
14065 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
14066 width: ( 100 - valPercent ) + "%"
14067 }, o.animate );
14068 }
14069 if ( oRange === "min" && this.orientation === "vertical" ) {
14070 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
14071 height: valPercent + "%"
14072 }, o.animate );
14073 }
14074 if ( oRange === "max" && this.orientation === "vertical" ) {
14075 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
14076 height: ( 100 - valPercent ) + "%"
14077 }, o.animate );
14078 }
14079 }
14080 },
14081
14082 _handleEvents: {
14083 keydown: function( event ) {
14084 var allowed, curVal, newVal, step,
14085 index = $( event.target ).data( "ui-slider-handle-index" );
14086
14087 switch ( event.keyCode ) {
14088 case $.ui.keyCode.HOME:
14089 case $.ui.keyCode.END:
14090 case $.ui.keyCode.PAGE_UP:
14091 case $.ui.keyCode.PAGE_DOWN:
14092 case $.ui.keyCode.UP:
14093 case $.ui.keyCode.RIGHT:
14094 case $.ui.keyCode.DOWN:
14095 case $.ui.keyCode.LEFT:
14096 event.preventDefault();
14097 if ( !this._keySliding ) {
14098 this._keySliding = true;
14099 this._addClass( $( event.target ), null, "ui-state-active" );
14100 allowed = this._start( event, index );
14101 if ( allowed === false ) {
14102 return;
14103 }
14104 }
14105 break;
14106 }
14107
14108 step = this.options.step;
14109 if ( this._hasMultipleValues() ) {
14110 curVal = newVal = this.values( index );
14111 } else {
14112 curVal = newVal = this.value();
14113 }
14114
14115 switch ( event.keyCode ) {
14116 case $.ui.keyCode.HOME:
14117 newVal = this._valueMin();
14118 break;
14119 case $.ui.keyCode.END:
14120 newVal = this._valueMax();
14121 break;
14122 case $.ui.keyCode.PAGE_UP:
14123 newVal = this._trimAlignValue(
14124 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
14125 );
14126 break;
14127 case $.ui.keyCode.PAGE_DOWN:
14128 newVal = this._trimAlignValue(
14129 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
14130 break;
14131 case $.ui.keyCode.UP:
14132 case $.ui.keyCode.RIGHT:
14133 if ( curVal === this._valueMax() ) {
14134 return;
14135 }
14136 newVal = this._trimAlignValue( curVal + step );
14137 break;
14138 case $.ui.keyCode.DOWN:
14139 case $.ui.keyCode.LEFT:
14140 if ( curVal === this._valueMin() ) {
14141 return;
14142 }
14143 newVal = this._trimAlignValue( curVal - step );
14144 break;
14145 }
14146
14147 this._slide( event, index, newVal );
14148 },
14149 keyup: function( event ) {
14150 var index = $( event.target ).data( "ui-slider-handle-index" );
14151
14152 if ( this._keySliding ) {
14153 this._keySliding = false;
14154 this._stop( event, index );
14155 this._change( event, index );
14156 this._removeClass( $( event.target ), null, "ui-state-active" );
14157 }
14158 }
14159 }
14160 } );
14161
14162
14163 /*!
14164 * jQuery UI Spinner 1.12.1
14165 * http://jqueryui.com
14166 *
14167 * Copyright jQuery Foundation and other contributors
14168 * Released under the MIT license.
14169 * http://jquery.org/license
14170 */
14171
14172 //>>label: Spinner
14173 //>>group: Widgets
14174 //>>description: Displays buttons to easily input numbers via the keyboard or mouse.
14175 //>>docs: http://api.jqueryui.com/spinner/
14176 //>>demos: http://jqueryui.com/spinner/
14177 //>>css.structure: ../../themes/base/core.css
14178 //>>css.structure: ../../themes/base/spinner.css
14179 //>>css.theme: ../../themes/base/theme.css
14180
14181
14182
14183 function spinnerModifer( fn ) {
14184 return function() {
14185 var previous = this.element.val();
14186 fn.apply( this, arguments );
14187 this._refresh();
14188 if ( previous !== this.element.val() ) {
14189 this._trigger( "change" );
14190 }
14191 };
14192 }
14193
14194 $.widget( "ui.spinner", {
14195 version: "1.12.1",
14196 defaultElement: "<input>",
14197 widgetEventPrefix: "spin",
14198 options: {
14199 classes: {
14200 "ui-spinner": "ui-corner-all",
14201 "ui-spinner-down": "ui-corner-br",
14202 "ui-spinner-up": "ui-corner-tr"
14203 },
14204 culture: null,
14205 icons: {
14206 down: "ui-icon-triangle-1-s",
14207 up: "ui-icon-triangle-1-n"
14208 },
14209 incremental: true,
14210 max: null,
14211 min: null,
14212 numberFormat: null,
14213 page: 10,
14214 step: 1,
14215
14216 change: null,
14217 spin: null,
14218 start: null,
14219 stop: null
14220 },
14221
14222 _create: function() {
14223
14224 // handle string values that need to be parsed
14225 this._setOption( "max", this.options.max );
14226 this._setOption( "min", this.options.min );
14227 this._setOption( "step", this.options.step );
14228
14229 // Only format if there is a value, prevents the field from being marked
14230 // as invalid in Firefox, see #9573.
14231 if ( this.value() !== "" ) {
14232
14233 // Format the value, but don't constrain.
14234 this._value( this.element.val(), true );
14235 }
14236
14237 this._draw();
14238 this._on( this._events );
14239 this._refresh();
14240
14241 // Turning off autocomplete prevents the browser from remembering the
14242 // value when navigating through history, so we re-enable autocomplete
14243 // if the page is unloaded before the widget is destroyed. #7790
14244 this._on( this.window, {
14245 beforeunload: function() {
14246 this.element.removeAttr( "autocomplete" );
14247 }
14248 } );
14249 },
14250
14251 _getCreateOptions: function() {
14252 var options = this._super();
14253 var element = this.element;
14254
14255 $.each( [ "min", "max", "step" ], function( i, option ) {
14256 var value = element.attr( option );
14257 if ( value != null && value.length ) {
14258 options[ option ] = value;
14259 }
14260 } );
14261
14262 return options;
14263 },
14264
14265 _events: {
14266 keydown: function( event ) {
14267 if ( this._start( event ) && this._keydown( event ) ) {
14268 event.preventDefault();
14269 }
14270 },
14271 keyup: "_stop",
14272 focus: function() {
14273 this.previous = this.element.val();
14274 },
14275 blur: function( event ) {
14276 if ( this.cancelBlur ) {
14277 delete this.cancelBlur;
14278 return;
14279 }
14280
14281 this._stop();
14282 this._refresh();
14283 if ( this.previous !== this.element.val() ) {
14284 this._trigger( "change", event );
14285 }
14286 },
14287 mousewheel: function( event, delta ) {
14288 if ( !delta ) {
14289 return;
14290 }
14291 if ( !this.spinning && !this._start( event ) ) {
14292 return false;
14293 }
14294
14295 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
14296 clearTimeout( this.mousewheelTimer );
14297 this.mousewheelTimer = this._delay( function() {
14298 if ( this.spinning ) {
14299 this._stop( event );
14300 }
14301 }, 100 );
14302 event.preventDefault();
14303 },
14304 "mousedown .ui-spinner-button": function( event ) {
14305 var previous;
14306
14307 // We never want the buttons to have focus; whenever the user is
14308 // interacting with the spinner, the focus should be on the input.
14309 // If the input is focused then this.previous is properly set from
14310 // when the input first received focus. If the input is not focused
14311 // then we need to set this.previous based on the value before spinning.
14312 previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
14313 this.previous : this.element.val();
14314 function checkFocus() {
14315 var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
14316 if ( !isActive ) {
14317 this.element.trigger( "focus" );
14318 this.previous = previous;
14319
14320 // support: IE
14321 // IE sets focus asynchronously, so we need to check if focus
14322 // moved off of the input because the user clicked on the button.
14323 this._delay( function() {
14324 this.previous = previous;
14325 } );
14326 }
14327 }
14328
14329 // Ensure focus is on (or stays on) the text field
14330 event.preventDefault();
14331 checkFocus.call( this );
14332
14333 // Support: IE
14334 // IE doesn't prevent moving focus even with event.preventDefault()
14335 // so we set a flag to know when we should ignore the blur event
14336 // and check (again) if focus moved off of the input.
14337 this.cancelBlur = true;
14338 this._delay( function() {
14339 delete this.cancelBlur;
14340 checkFocus.call( this );
14341 } );
14342
14343 if ( this._start( event ) === false ) {
14344 return;
14345 }
14346
14347 this._repeat( null, $( event.currentTarget )
14348 .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14349 },
14350 "mouseup .ui-spinner-button": "_stop",
14351 "mouseenter .ui-spinner-button": function( event ) {
14352
14353 // button will add ui-state-active if mouse was down while mouseleave and kept down
14354 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
14355 return;
14356 }
14357
14358 if ( this._start( event ) === false ) {
14359 return false;
14360 }
14361 this._repeat( null, $( event.currentTarget )
14362 .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14363 },
14364
14365 // TODO: do we really want to consider this a stop?
14366 // shouldn't we just stop the repeater and wait until mouseup before
14367 // we trigger the stop event?
14368 "mouseleave .ui-spinner-button": "_stop"
14369 },
14370
14371 // Support mobile enhanced option and make backcompat more sane
14372 _enhance: function() {
14373 this.uiSpinner = this.element
14374 .attr( "autocomplete", "off" )
14375 .wrap( "<span>" )
14376 .parent()
14377
14378 // Add buttons
14379 .append(
14380 "<a></a><a></a>"
14381 );
14382 },
14383
14384 _draw: function() {
14385 this._enhance();
14386
14387 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
14388 this._addClass( "ui-spinner-input" );
14389
14390 this.element.attr( "role", "spinbutton" );
14391
14392 // Button bindings
14393 this.buttons = this.uiSpinner.children( "a" )
14394 .attr( "tabIndex", -1 )
14395 .attr( "aria-hidden", true )
14396 .button( {
14397 classes: {
14398 "ui-button": ""
14399 }
14400 } );
14401
14402 // TODO: Right now button does not support classes this is already updated in button PR
14403 this._removeClass( this.buttons, "ui-corner-all" );
14404
14405 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
14406 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
14407 this.buttons.first().button( {
14408 "icon": this.options.icons.up,
14409 "showLabel": false
14410 } );
14411 this.buttons.last().button( {
14412 "icon": this.options.icons.down,
14413 "showLabel": false
14414 } );
14415
14416 // IE 6 doesn't understand height: 50% for the buttons
14417 // unless the wrapper has an explicit height
14418 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
14419 this.uiSpinner.height() > 0 ) {
14420 this.uiSpinner.height( this.uiSpinner.height() );
14421 }
14422 },
14423
14424 _keydown: function( event ) {
14425 var options = this.options,
14426 keyCode = $.ui.keyCode;
14427
14428 switch ( event.keyCode ) {
14429 case keyCode.UP:
14430 this._repeat( null, 1, event );
14431 return true;
14432 case keyCode.DOWN:
14433 this._repeat( null, -1, event );
14434 return true;
14435 case keyCode.PAGE_UP:
14436 this._repeat( null, options.page, event );
14437 return true;
14438 case keyCode.PAGE_DOWN:
14439 this._repeat( null, -options.page, event );
14440 return true;
14441 }
14442
14443 return false;
14444 },
14445
14446 _start: function( event ) {
14447 if ( !this.spinning && this._trigger( "start", event ) === false ) {
14448 return false;
14449 }
14450
14451 if ( !this.counter ) {
14452 this.counter = 1;
14453 }
14454 this.spinning = true;
14455 return true;
14456 },
14457
14458 _repeat: function( i, steps, event ) {
14459 i = i || 500;
14460
14461 clearTimeout( this.timer );
14462 this.timer = this._delay( function() {
14463 this._repeat( 40, steps, event );
14464 }, i );
14465
14466 this._spin( steps * this.options.step, event );
14467 },
14468
14469 _spin: function( step, event ) {
14470 var value = this.value() || 0;
14471
14472 if ( !this.counter ) {
14473 this.counter = 1;
14474 }
14475
14476 value = this._adjustValue( value + step * this._increment( this.counter ) );
14477
14478 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
14479 this._value( value );
14480 this.counter++;
14481 }
14482 },
14483
14484 _increment: function( i ) {
14485 var incremental = this.options.incremental;
14486
14487 if ( incremental ) {
14488 return $.isFunction( incremental ) ?
14489 incremental( i ) :
14490 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
14491 }
14492
14493 return 1;
14494 },
14495
14496 _precision: function() {
14497 var precision = this._precisionOf( this.options.step );
14498 if ( this.options.min !== null ) {
14499 precision = Math.max( precision, this._precisionOf( this.options.min ) );
14500 }
14501 return precision;
14502 },
14503
14504 _precisionOf: function( num ) {
14505 var str = num.toString(),
14506 decimal = str.indexOf( "." );
14507 return decimal === -1 ? 0 : str.length - decimal - 1;
14508 },
14509
14510 _adjustValue: function( value ) {
14511 var base, aboveMin,
14512 options = this.options;
14513
14514 // Make sure we're at a valid step
14515 // - find out where we are relative to the base (min or 0)
14516 base = options.min !== null ? options.min : 0;
14517 aboveMin = value - base;
14518
14519 // - round to the nearest step
14520 aboveMin = Math.round( aboveMin / options.step ) * options.step;
14521
14522 // - rounding is based on 0, so adjust back to our base
14523 value = base + aboveMin;
14524
14525 // Fix precision from bad JS floating point math
14526 value = parseFloat( value.toFixed( this._precision() ) );
14527
14528 // Clamp the value
14529 if ( options.max !== null && value > options.max ) {
14530 return options.max;
14531 }
14532 if ( options.min !== null && value < options.min ) {
14533 return options.min;
14534 }
14535
14536 return value;
14537 },
14538
14539 _stop: function( event ) {
14540 if ( !this.spinning ) {
14541 return;
14542 }
14543
14544 clearTimeout( this.timer );
14545 clearTimeout( this.mousewheelTimer );
14546 this.counter = 0;
14547 this.spinning = false;
14548 this._trigger( "stop", event );
14549 },
14550
14551 _setOption: function( key, value ) {
14552 var prevValue, first, last;
14553
14554 if ( key === "culture" || key === "numberFormat" ) {
14555 prevValue = this._parse( this.element.val() );
14556 this.options[ key ] = value;
14557 this.element.val( this._format( prevValue ) );
14558 return;
14559 }
14560
14561 if ( key === "max" || key === "min" || key === "step" ) {
14562 if ( typeof value === "string" ) {
14563 value = this._parse( value );
14564 }
14565 }
14566 if ( key === "icons" ) {
14567 first = this.buttons.first().find( ".ui-icon" );
14568 this._removeClass( first, null, this.options.icons.up );
14569 this._addClass( first, null, value.up );
14570 last = this.buttons.last().find( ".ui-icon" );
14571 this._removeClass( last, null, this.options.icons.down );
14572 this._addClass( last, null, value.down );
14573 }
14574
14575 this._super( key, value );
14576 },
14577
14578 _setOptionDisabled: function( value ) {
14579 this._super( value );
14580
14581 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
14582 this.element.prop( "disabled", !!value );
14583 this.buttons.button( value ? "disable" : "enable" );
14584 },
14585
14586 _setOptions: spinnerModifer( function( options ) {
14587 this._super( options );
14588 } ),
14589
14590 _parse: function( val ) {
14591 if ( typeof val === "string" && val !== "" ) {
14592 val = window.Globalize && this.options.numberFormat ?
14593 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
14594 }
14595 return val === "" || isNaN( val ) ? null : val;
14596 },
14597
14598 _format: function( value ) {
14599 if ( value === "" ) {
14600 return "";
14601 }
14602 return window.Globalize && this.options.numberFormat ?
14603 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
14604 value;
14605 },
14606
14607 _refresh: function() {
14608 this.element.attr( {
14609 "aria-valuemin": this.options.min,
14610 "aria-valuemax": this.options.max,
14611
14612 // TODO: what should we do with values that can't be parsed?
14613 "aria-valuenow": this._parse( this.element.val() )
14614 } );
14615 },
14616
14617 isValid: function() {
14618 var value = this.value();
14619
14620 // Null is invalid
14621 if ( value === null ) {
14622 return false;
14623 }
14624
14625 // If value gets adjusted, it's invalid
14626 return value === this._adjustValue( value );
14627 },
14628
14629 // Update the value without triggering change
14630 _value: function( value, allowAny ) {
14631 var parsed;
14632 if ( value !== "" ) {
14633 parsed = this._parse( value );
14634 if ( parsed !== null ) {
14635 if ( !allowAny ) {
14636 parsed = this._adjustValue( parsed );
14637 }
14638 value = this._format( parsed );
14639 }
14640 }
14641 this.element.val( value );
14642 this._refresh();
14643 },
14644
14645 _destroy: function() {
14646 this.element
14647 .prop( "disabled", false )
14648 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
14649
14650 this.uiSpinner.replaceWith( this.element );
14651 },
14652
14653 stepUp: spinnerModifer( function( steps ) {
14654 this._stepUp( steps );
14655 } ),
14656 _stepUp: function( steps ) {
14657 if ( this._start() ) {
14658 this._spin( ( steps || 1 ) * this.options.step );
14659 this._stop();
14660 }
14661 },
14662
14663 stepDown: spinnerModifer( function( steps ) {
14664 this._stepDown( steps );
14665 } ),
14666 _stepDown: function( steps ) {
14667 if ( this._start() ) {
14668 this._spin( ( steps || 1 ) * -this.options.step );
14669 this._stop();
14670 }
14671 },
14672
14673 pageUp: spinnerModifer( function( pages ) {
14674 this._stepUp( ( pages || 1 ) * this.options.page );
14675 } ),
14676
14677 pageDown: spinnerModifer( function( pages ) {
14678 this._stepDown( ( pages || 1 ) * this.options.page );
14679 } ),
14680
14681 value: function( newVal ) {
14682 if ( !arguments.length ) {
14683 return this._parse( this.element.val() );
14684 }
14685 spinnerModifer( this._value ).call( this, newVal );
14686 },
14687
14688 widget: function() {
14689 return this.uiSpinner;
14690 }
14691 } );
14692
14693 // DEPRECATED
14694 // TODO: switch return back to widget declaration at top of file when this is removed
14695 if ( $.uiBackCompat !== false ) {
14696
14697 // Backcompat for spinner html extension points
14698 $.widget( "ui.spinner", $.ui.spinner, {
14699 _enhance: function() {
14700 this.uiSpinner = this.element
14701 .attr( "autocomplete", "off" )
14702 .wrap( this._uiSpinnerHtml() )
14703 .parent()
14704
14705 // Add buttons
14706 .append( this._buttonHtml() );
14707 },
14708 _uiSpinnerHtml: function() {
14709 return "<span>";
14710 },
14711
14712 _buttonHtml: function() {
14713 return "<a></a><a></a>";
14714 }
14715 } );
14716 }
14717
14718 var widgetsSpinner = $.ui.spinner;
14719
14720
14721 /*!
14722 * jQuery UI Tabs 1.12.1
14723 * http://jqueryui.com
14724 *
14725 * Copyright jQuery Foundation and other contributors
14726 * Released under the MIT license.
14727 * http://jquery.org/license
14728 */
14729
14730 //>>label: Tabs
14731 //>>group: Widgets
14732 //>>description: Transforms a set of container elements into a tab structure.
14733 //>>docs: http://api.jqueryui.com/tabs/
14734 //>>demos: http://jqueryui.com/tabs/
14735 //>>css.structure: ../../themes/base/core.css
14736 //>>css.structure: ../../themes/base/tabs.css
14737 //>>css.theme: ../../themes/base/theme.css
14738
14739
14740
14741 $.widget( "ui.tabs", {
14742 version: "1.12.1",
14743 delay: 300,
14744 options: {
14745 active: null,
14746 classes: {
14747 "ui-tabs": "ui-corner-all",
14748 "ui-tabs-nav": "ui-corner-all",
14749 "ui-tabs-panel": "ui-corner-bottom",
14750 "ui-tabs-tab": "ui-corner-top"
14751 },
14752 collapsible: false,
14753 event: "click",
14754 heightStyle: "content",
14755 hide: null,
14756 show: null,
14757
14758 // Callbacks
14759 activate: null,
14760 beforeActivate: null,
14761 beforeLoad: null,
14762 load: null
14763 },
14764
14765 _isLocal: ( function() {
14766 var rhash = /#.*$/;
14767
14768 return function( anchor ) {
14769 var anchorUrl, locationUrl;
14770
14771 anchorUrl = anchor.href.replace( rhash, "" );
14772 locationUrl = location.href.replace( rhash, "" );
14773
14774 // Decoding may throw an error if the URL isn't UTF-8 (#9518)
14775 try {
14776 anchorUrl = decodeURIComponent( anchorUrl );
14777 } catch ( error ) {}
14778 try {
14779 locationUrl = decodeURIComponent( locationUrl );
14780 } catch ( error ) {}
14781
14782 return anchor.hash.length > 1 && anchorUrl === locationUrl;
14783 };
14784 } )(),
14785
14786 _create: function() {
14787 var that = this,
14788 options = this.options;
14789
14790 this.running = false;
14791
14792 this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
14793 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
14794
14795 this._processTabs();
14796 options.active = this._initialActive();
14797
14798 // Take disabling tabs via class attribute from HTML
14799 // into account and update option properly.
14800 if ( $.isArray( options.disabled ) ) {
14801 options.disabled = $.unique( options.disabled.concat(
14802 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
14803 return that.tabs.index( li );
14804 } )
14805 ) ).sort();
14806 }
14807
14808 // Check for length avoids error when initializing empty list
14809 if ( this.options.active !== false && this.anchors.length ) {
14810 this.active = this._findActive( options.active );
14811 } else {
14812 this.active = $();
14813 }
14814
14815 this._refresh();
14816
14817 if ( this.active.length ) {
14818 this.load( options.active );
14819 }
14820 },
14821
14822 _initialActive: function() {
14823 var active = this.options.active,
14824 collapsible = this.options.collapsible,
14825 locationHash = location.hash.substring( 1 );
14826
14827 if ( active === null ) {
14828
14829 // check the fragment identifier in the URL
14830 if ( locationHash ) {
14831 this.tabs.each( function( i, tab ) {
14832 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
14833 active = i;
14834 return false;
14835 }
14836 } );
14837 }
14838
14839 // Check for a tab marked active via a class
14840 if ( active === null ) {
14841 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
14842 }
14843
14844 // No active tab, set to false
14845 if ( active === null || active === -1 ) {
14846 active = this.tabs.length ? 0 : false;
14847 }
14848 }
14849
14850 // Handle numbers: negative, out of range
14851 if ( active !== false ) {
14852 active = this.tabs.index( this.tabs.eq( active ) );
14853 if ( active === -1 ) {
14854 active = collapsible ? false : 0;
14855 }
14856 }
14857
14858 // Don't allow collapsible: false and active: false
14859 if ( !collapsible && active === false && this.anchors.length ) {
14860 active = 0;
14861 }
14862
14863 return active;
14864 },
14865
14866 _getCreateEventData: function() {
14867 return {
14868 tab: this.active,
14869 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
14870 };
14871 },
14872
14873 _tabKeydown: function( event ) {
14874 var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
14875 selectedIndex = this.tabs.index( focusedTab ),
14876 goingForward = true;
14877
14878 if ( this._handlePageNav( event ) ) {
14879 return;
14880 }
14881
14882 switch ( event.keyCode ) {
14883 case $.ui.keyCode.RIGHT:
14884 case $.ui.keyCode.DOWN:
14885 selectedIndex++;
14886 break;
14887 case $.ui.keyCode.UP:
14888 case $.ui.keyCode.LEFT:
14889 goingForward = false;
14890 selectedIndex--;
14891 break;
14892 case $.ui.keyCode.END:
14893 selectedIndex = this.anchors.length - 1;
14894 break;
14895 case $.ui.keyCode.HOME:
14896 selectedIndex = 0;
14897 break;
14898 case $.ui.keyCode.SPACE:
14899
14900 // Activate only, no collapsing
14901 event.preventDefault();
14902 clearTimeout( this.activating );
14903 this._activate( selectedIndex );
14904 return;
14905 case $.ui.keyCode.ENTER:
14906
14907 // Toggle (cancel delayed activation, allow collapsing)
14908 event.preventDefault();
14909 clearTimeout( this.activating );
14910
14911 // Determine if we should collapse or activate
14912 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
14913 return;
14914 default:
14915 return;
14916 }
14917
14918 // Focus the appropriate tab, based on which key was pressed
14919 event.preventDefault();
14920 clearTimeout( this.activating );
14921 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
14922
14923 // Navigating with control/command key will prevent automatic activation
14924 if ( !event.ctrlKey && !event.metaKey ) {
14925
14926 // Update aria-selected immediately so that AT think the tab is already selected.
14927 // Otherwise AT may confuse the user by stating that they need to activate the tab,
14928 // but the tab will already be activated by the time the announcement finishes.
14929 focusedTab.attr( "aria-selected", "false" );
14930 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
14931
14932 this.activating = this._delay( function() {
14933 this.option( "active", selectedIndex );
14934 }, this.delay );
14935 }
14936 },
14937
14938 _panelKeydown: function( event ) {
14939 if ( this._handlePageNav( event ) ) {
14940 return;
14941 }
14942
14943 // Ctrl+up moves focus to the current tab
14944 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
14945 event.preventDefault();
14946 this.active.trigger( "focus" );
14947 }
14948 },
14949
14950 // Alt+page up/down moves focus to the previous/next tab (and activates)
14951 _handlePageNav: function( event ) {
14952 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
14953 this._activate( this._focusNextTab( this.options.active - 1, false ) );
14954 return true;
14955 }
14956 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
14957 this._activate( this._focusNextTab( this.options.active + 1, true ) );
14958 return true;
14959 }
14960 },
14961
14962 _findNextTab: function( index, goingForward ) {
14963 var lastTabIndex = this.tabs.length - 1;
14964
14965 function constrain() {
14966 if ( index > lastTabIndex ) {
14967 index = 0;
14968 }
14969 if ( index < 0 ) {
14970 index = lastTabIndex;
14971 }
14972 return index;
14973 }
14974
14975 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
14976 index = goingForward ? index + 1 : index - 1;
14977 }
14978
14979 return index;
14980 },
14981
14982 _focusNextTab: function( index, goingForward ) {
14983 index = this._findNextTab( index, goingForward );
14984 this.tabs.eq( index ).trigger( "focus" );
14985 return index;
14986 },
14987
14988 _setOption: function( key, value ) {
14989 if ( key === "active" ) {
14990
14991 // _activate() will handle invalid values and update this.options
14992 this._activate( value );
14993 return;
14994 }
14995
14996 this._super( key, value );
14997
14998 if ( key === "collapsible" ) {
14999 this._toggleClass( "ui-tabs-collapsible", null, value );
15000
15001 // Setting collapsible: false while collapsed; open first panel
15002 if ( !value && this.options.active === false ) {
15003 this._activate( 0 );
15004 }
15005 }
15006
15007 if ( key === "event" ) {
15008 this._setupEvents( value );
15009 }
15010
15011 if ( key === "heightStyle" ) {
15012 this._setupHeightStyle( value );
15013 }
15014 },
15015
15016 _sanitizeSelector: function( hash ) {
15017 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
15018 },
15019
15020 refresh: function() {
15021 var options = this.options,
15022 lis = this.tablist.children( ":has(a[href])" );
15023
15024 // Get disabled tabs from class attribute from HTML
15025 // this will get converted to a boolean if needed in _refresh()
15026 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
15027 return lis.index( tab );
15028 } );
15029
15030 this._processTabs();
15031
15032 // Was collapsed or no tabs
15033 if ( options.active === false || !this.anchors.length ) {
15034 options.active = false;
15035 this.active = $();
15036
15037 // was active, but active tab is gone
15038 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
15039
15040 // all remaining tabs are disabled
15041 if ( this.tabs.length === options.disabled.length ) {
15042 options.active = false;
15043 this.active = $();
15044
15045 // activate previous tab
15046 } else {
15047 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
15048 }
15049
15050 // was active, active tab still exists
15051 } else {
15052
15053 // make sure active index is correct
15054 options.active = this.tabs.index( this.active );
15055 }
15056
15057 this._refresh();
15058 },
15059
15060 _refresh: function() {
15061 this._setOptionDisabled( this.options.disabled );
15062 this._setupEvents( this.options.event );
15063 this._setupHeightStyle( this.options.heightStyle );
15064
15065 this.tabs.not( this.active ).attr( {
15066 "aria-selected": "false",
15067 "aria-expanded": "false",
15068 tabIndex: -1
15069 } );
15070 this.panels.not( this._getPanelForTab( this.active ) )
15071 .hide()
15072 .attr( {
15073 "aria-hidden": "true"
15074 } );
15075
15076 // Make sure one tab is in the tab order
15077 if ( !this.active.length ) {
15078 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
15079 } else {
15080 this.active
15081 .attr( {
15082 "aria-selected": "true",
15083 "aria-expanded": "true",
15084 tabIndex: 0
15085 } );
15086 this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
15087 this._getPanelForTab( this.active )
15088 .show()
15089 .attr( {
15090 "aria-hidden": "false"
15091 } );
15092 }
15093 },
15094
15095 _processTabs: function() {
15096 var that = this,
15097 prevTabs = this.tabs,
15098 prevAnchors = this.anchors,
15099 prevPanels = this.panels;
15100
15101 this.tablist = this._getList().attr( "role", "tablist" );
15102 this._addClass( this.tablist, "ui-tabs-nav",
15103 "ui-helper-reset ui-helper-clearfix ui-widget-header" );
15104
15105 // Prevent users from focusing disabled tabs via click
15106 this.tablist
15107 .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
15108 if ( $( this ).is( ".ui-state-disabled" ) ) {
15109 event.preventDefault();
15110 }
15111 } )
15112
15113 // Support: IE <9
15114 // Preventing the default action in mousedown doesn't prevent IE
15115 // from focusing the element, so if the anchor gets focused, blur.
15116 // We don't have to worry about focusing the previously focused
15117 // element since clicking on a non-focusable element should focus
15118 // the body anyway.
15119 .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
15120 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
15121 this.blur();
15122 }
15123 } );
15124
15125 this.tabs = this.tablist.find( "> li:has(a[href])" )
15126 .attr( {
15127 role: "tab",
15128 tabIndex: -1
15129 } );
15130 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
15131
15132 this.anchors = this.tabs.map( function() {
15133 return $( "a", this )[ 0 ];
15134 } )
15135 .attr( {
15136 role: "presentation",
15137 tabIndex: -1
15138 } );
15139 this._addClass( this.anchors, "ui-tabs-anchor" );
15140
15141 this.panels = $();
15142
15143 this.anchors.each( function( i, anchor ) {
15144 var selector, panel, panelId,
15145 anchorId = $( anchor ).uniqueId().attr( "id" ),
15146 tab = $( anchor ).closest( "li" ),
15147 originalAriaControls = tab.attr( "aria-controls" );
15148
15149 // Inline tab
15150 if ( that._isLocal( anchor ) ) {
15151 selector = anchor.hash;
15152 panelId = selector.substring( 1 );
15153 panel = that.element.find( that._sanitizeSelector( selector ) );
15154
15155 // remote tab
15156 } else {
15157
15158 // If the tab doesn't already have aria-controls,
15159 // generate an id by using a throw-away element
15160 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
15161 selector = "#" + panelId;
15162 panel = that.element.find( selector );
15163 if ( !panel.length ) {
15164 panel = that._createPanel( panelId );
15165 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
15166 }
15167 panel.attr( "aria-live", "polite" );
15168 }
15169
15170 if ( panel.length ) {
15171 that.panels = that.panels.add( panel );
15172 }
15173 if ( originalAriaControls ) {
15174 tab.data( "ui-tabs-aria-controls", originalAriaControls );
15175 }
15176 tab.attr( {
15177 "aria-controls": panelId,
15178 "aria-labelledby": anchorId
15179 } );
15180 panel.attr( "aria-labelledby", anchorId );
15181 } );
15182
15183 this.panels.attr( "role", "tabpanel" );
15184 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
15185
15186 // Avoid memory leaks (#10056)
15187 if ( prevTabs ) {
15188 this._off( prevTabs.not( this.tabs ) );
15189 this._off( prevAnchors.not( this.anchors ) );
15190 this._off( prevPanels.not( this.panels ) );
15191 }
15192 },
15193
15194 // Allow overriding how to find the list for rare usage scenarios (#7715)
15195 _getList: function() {
15196 return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
15197 },
15198
15199 _createPanel: function( id ) {
15200 return $( "<div>" )
15201 .attr( "id", id )
15202 .data( "ui-tabs-destroy", true );
15203 },
15204
15205 _setOptionDisabled: function( disabled ) {
15206 var currentItem, li, i;
15207
15208 if ( $.isArray( disabled ) ) {
15209 if ( !disabled.length ) {
15210 disabled = false;
15211 } else if ( disabled.length === this.anchors.length ) {
15212 disabled = true;
15213 }
15214 }
15215
15216 // Disable tabs
15217 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
15218 currentItem = $( li );
15219 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
15220 currentItem.attr( "aria-disabled", "true" );
15221 this._addClass( currentItem, null, "ui-state-disabled" );
15222 } else {
15223 currentItem.removeAttr( "aria-disabled" );
15224 this._removeClass( currentItem, null, "ui-state-disabled" );
15225 }
15226 }
15227
15228 this.options.disabled = disabled;
15229
15230 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
15231 disabled === true );
15232 },
15233
15234 _setupEvents: function( event ) {
15235 var events = {};
15236 if ( event ) {
15237 $.each( event.split( " " ), function( index, eventName ) {
15238 events[ eventName ] = "_eventHandler";
15239 } );
15240 }
15241
15242 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
15243
15244 // Always prevent the default action, even when disabled
15245 this._on( true, this.anchors, {
15246 click: function( event ) {
15247 event.preventDefault();
15248 }
15249 } );
15250 this._on( this.anchors, events );
15251 this._on( this.tabs, { keydown: "_tabKeydown" } );
15252 this._on( this.panels, { keydown: "_panelKeydown" } );
15253
15254 this._focusable( this.tabs );
15255 this._hoverable( this.tabs );
15256 },
15257
15258 _setupHeightStyle: function( heightStyle ) {
15259 var maxHeight,
15260 parent = this.element.parent();
15261
15262 if ( heightStyle === "fill" ) {
15263 maxHeight = parent.height();
15264 maxHeight -= this.element.outerHeight() - this.element.height();
15265
15266 this.element.siblings( ":visible" ).each( function() {
15267 var elem = $( this ),
15268 position = elem.css( "position" );
15269
15270 if ( position === "absolute" || position === "fixed" ) {
15271 return;
15272 }
15273 maxHeight -= elem.outerHeight( true );
15274 } );
15275
15276 this.element.children().not( this.panels ).each( function() {
15277 maxHeight -= $( this ).outerHeight( true );
15278 } );
15279
15280 this.panels.each( function() {
15281 $( this ).height( Math.max( 0, maxHeight -
15282 $( this ).innerHeight() + $( this ).height() ) );
15283 } )
15284 .css( "overflow", "auto" );
15285 } else if ( heightStyle === "auto" ) {
15286 maxHeight = 0;
15287 this.panels.each( function() {
15288 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
15289 } ).height( maxHeight );
15290 }
15291 },
15292
15293 _eventHandler: function( event ) {
15294 var options = this.options,
15295 active = this.active,
15296 anchor = $( event.currentTarget ),
15297 tab = anchor.closest( "li" ),
15298 clickedIsActive = tab[ 0 ] === active[ 0 ],
15299 collapsing = clickedIsActive && options.collapsible,
15300 toShow = collapsing ? $() : this._getPanelForTab( tab ),
15301 toHide = !active.length ? $() : this._getPanelForTab( active ),
15302 eventData = {
15303 oldTab: active,
15304 oldPanel: toHide,
15305 newTab: collapsing ? $() : tab,
15306 newPanel: toShow
15307 };
15308
15309 event.preventDefault();
15310
15311 if ( tab.hasClass( "ui-state-disabled" ) ||
15312
15313 // tab is already loading
15314 tab.hasClass( "ui-tabs-loading" ) ||
15315
15316 // can't switch durning an animation
15317 this.running ||
15318
15319 // click on active header, but not collapsible
15320 ( clickedIsActive && !options.collapsible ) ||
15321
15322 // allow canceling activation
15323 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
15324 return;
15325 }
15326
15327 options.active = collapsing ? false : this.tabs.index( tab );
15328
15329 this.active = clickedIsActive ? $() : tab;
15330 if ( this.xhr ) {
15331 this.xhr.abort();
15332 }
15333
15334 if ( !toHide.length && !toShow.length ) {
15335 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
15336 }
15337
15338 if ( toShow.length ) {
15339 this.load( this.tabs.index( tab ), event );
15340 }
15341 this._toggle( event, eventData );
15342 },
15343
15344 // Handles show/hide for selecting tabs
15345 _toggle: function( event, eventData ) {
15346 var that = this,
15347 toShow = eventData.newPanel,
15348 toHide = eventData.oldPanel;
15349
15350 this.running = true;
15351
15352 function complete() {
15353 that.running = false;
15354 that._trigger( "activate", event, eventData );
15355 }
15356
15357 function show() {
15358 that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
15359
15360 if ( toShow.length && that.options.show ) {
15361 that._show( toShow, that.options.show, complete );
15362 } else {
15363 toShow.show();
15364 complete();
15365 }
15366 }
15367
15368 // Start out by hiding, then showing, then completing
15369 if ( toHide.length && this.options.hide ) {
15370 this._hide( toHide, this.options.hide, function() {
15371 that._removeClass( eventData.oldTab.closest( "li" ),
15372 "ui-tabs-active", "ui-state-active" );
15373 show();
15374 } );
15375 } else {
15376 this._removeClass( eventData.oldTab.closest( "li" ),
15377 "ui-tabs-active", "ui-state-active" );
15378 toHide.hide();
15379 show();
15380 }
15381
15382 toHide.attr( "aria-hidden", "true" );
15383 eventData.oldTab.attr( {
15384 "aria-selected": "false",
15385 "aria-expanded": "false"
15386 } );
15387
15388 // If we're switching tabs, remove the old tab from the tab order.
15389 // If we're opening from collapsed state, remove the previous tab from the tab order.
15390 // If we're collapsing, then keep the collapsing tab in the tab order.
15391 if ( toShow.length && toHide.length ) {
15392 eventData.oldTab.attr( "tabIndex", -1 );
15393 } else if ( toShow.length ) {
15394 this.tabs.filter( function() {
15395 return $( this ).attr( "tabIndex" ) === 0;
15396 } )
15397 .attr( "tabIndex", -1 );
15398 }
15399
15400 toShow.attr( "aria-hidden", "false" );
15401 eventData.newTab.attr( {
15402 "aria-selected": "true",
15403 "aria-expanded": "true",
15404 tabIndex: 0
15405 } );
15406 },
15407
15408 _activate: function( index ) {
15409 var anchor,
15410 active = this._findActive( index );
15411
15412 // Trying to activate the already active panel
15413 if ( active[ 0 ] === this.active[ 0 ] ) {
15414 return;
15415 }
15416
15417 // Trying to collapse, simulate a click on the current active header
15418 if ( !active.length ) {
15419 active = this.active;
15420 }
15421
15422 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
15423 this._eventHandler( {
15424 target: anchor,
15425 currentTarget: anchor,
15426 preventDefault: $.noop
15427 } );
15428 },
15429
15430 _findActive: function( index ) {
15431 return index === false ? $() : this.tabs.eq( index );
15432 },
15433
15434 _getIndex: function( index ) {
15435
15436 // meta-function to give users option to provide a href string instead of a numerical index.
15437 if ( typeof index === "string" ) {
15438 index = this.anchors.index( this.anchors.filter( "[href$='" +
15439 $.ui.escapeSelector( index ) + "']" ) );
15440 }
15441
15442 return index;
15443 },
15444
15445 _destroy: function() {
15446 if ( this.xhr ) {
15447 this.xhr.abort();
15448 }
15449
15450 this.tablist
15451 .removeAttr( "role" )
15452 .off( this.eventNamespace );
15453
15454 this.anchors
15455 .removeAttr( "role tabIndex" )
15456 .removeUniqueId();
15457
15458 this.tabs.add( this.panels ).each( function() {
15459 if ( $.data( this, "ui-tabs-destroy" ) ) {
15460 $( this ).remove();
15461 } else {
15462 $( this ).removeAttr( "role tabIndex " +
15463 "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
15464 }
15465 } );
15466
15467 this.tabs.each( function() {
15468 var li = $( this ),
15469 prev = li.data( "ui-tabs-aria-controls" );
15470 if ( prev ) {
15471 li
15472 .attr( "aria-controls", prev )
15473 .removeData( "ui-tabs-aria-controls" );
15474 } else {
15475 li.removeAttr( "aria-controls" );
15476 }
15477 } );
15478
15479 this.panels.show();
15480
15481 if ( this.options.heightStyle !== "content" ) {
15482 this.panels.css( "height", "" );
15483 }
15484 },
15485
15486 enable: function( index ) {
15487 var disabled = this.options.disabled;
15488 if ( disabled === false ) {
15489 return;
15490 }
15491
15492 if ( index === undefined ) {
15493 disabled = false;
15494 } else {
15495 index = this._getIndex( index );
15496 if ( $.isArray( disabled ) ) {
15497 disabled = $.map( disabled, function( num ) {
15498 return num !== index ? num : null;
15499 } );
15500 } else {
15501 disabled = $.map( this.tabs, function( li, num ) {
15502 return num !== index ? num : null;
15503 } );
15504 }
15505 }
15506 this._setOptionDisabled( disabled );
15507 },
15508
15509 disable: function( index ) {
15510 var disabled = this.options.disabled;
15511 if ( disabled === true ) {
15512 return;
15513 }
15514
15515 if ( index === undefined ) {
15516 disabled = true;
15517 } else {
15518 index = this._getIndex( index );
15519 if ( $.inArray( index, disabled ) !== -1 ) {
15520 return;
15521 }
15522 if ( $.isArray( disabled ) ) {
15523 disabled = $.merge( [ index ], disabled ).sort();
15524 } else {
15525 disabled = [ index ];
15526 }
15527 }
15528 this._setOptionDisabled( disabled );
15529 },
15530
15531 load: function( index, event ) {
15532 index = this._getIndex( index );
15533 var that = this,
15534 tab = this.tabs.eq( index ),
15535 anchor = tab.find( ".ui-tabs-anchor" ),
15536 panel = this._getPanelForTab( tab ),
15537 eventData = {
15538 tab: tab,
15539 panel: panel
15540 },
15541 complete = function( jqXHR, status ) {
15542 if ( status === "abort" ) {
15543 that.panels.stop( false, true );
15544 }
15545
15546 that._removeClass( tab, "ui-tabs-loading" );
15547 panel.removeAttr( "aria-busy" );
15548
15549 if ( jqXHR === that.xhr ) {
15550 delete that.xhr;
15551 }
15552 };
15553
15554 // Not remote
15555 if ( this._isLocal( anchor[ 0 ] ) ) {
15556 return;
15557 }
15558
15559 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
15560
15561 // Support: jQuery <1.8
15562 // jQuery <1.8 returns false if the request is canceled in beforeSend,
15563 // but as of 1.8, $.ajax() always returns a jqXHR object.
15564 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
15565 this._addClass( tab, "ui-tabs-loading" );
15566 panel.attr( "aria-busy", "true" );
15567
15568 this.xhr
15569 .done( function( response, status, jqXHR ) {
15570
15571 // support: jQuery <1.8
15572 // http://bugs.jquery.com/ticket/11778
15573 setTimeout( function() {
15574 panel.html( response );
15575 that._trigger( "load", event, eventData );
15576
15577 complete( jqXHR, status );
15578 }, 1 );
15579 } )
15580 .fail( function( jqXHR, status ) {
15581
15582 // support: jQuery <1.8
15583 // http://bugs.jquery.com/ticket/11778
15584 setTimeout( function() {
15585 complete( jqXHR, status );
15586 }, 1 );
15587 } );
15588 }
15589 },
15590
15591 _ajaxSettings: function( anchor, event, eventData ) {
15592 var that = this;
15593 return {
15594
15595 // Support: IE <11 only
15596 // Strip any hash that exists to prevent errors with the Ajax request
15597 url: anchor.attr( "href" ).replace( /#.*$/, "" ),
15598 beforeSend: function( jqXHR, settings ) {
15599 return that._trigger( "beforeLoad", event,
15600 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
15601 }
15602 };
15603 },
15604
15605 _getPanelForTab: function( tab ) {
15606 var id = $( tab ).attr( "aria-controls" );
15607 return this.element.find( this._sanitizeSelector( "#" + id ) );
15608 }
15609 } );
15610
15611 // DEPRECATED
15612 // TODO: Switch return back to widget declaration at top of file when this is removed
15613 if ( $.uiBackCompat !== false ) {
15614
15615 // Backcompat for ui-tab class (now ui-tabs-tab)
15616 $.widget( "ui.tabs", $.ui.tabs, {
15617 _processTabs: function() {
15618 this._superApply( arguments );
15619 this._addClass( this.tabs, "ui-tab" );
15620 }
15621 } );
15622 }
15623
15624 var widgetsTabs = $.ui.tabs;
15625
15626
15627 /*!
15628 * jQuery UI Tooltip 1.12.1
15629 * http://jqueryui.com
15630 *
15631 * Copyright jQuery Foundation and other contributors
15632 * Released under the MIT license.
15633 * http://jquery.org/license
15634 */
15635
15636 //>>label: Tooltip
15637 //>>group: Widgets
15638 //>>description: Shows additional information for any element on hover or focus.
15639 //>>docs: http://api.jqueryui.com/tooltip/
15640 //>>demos: http://jqueryui.com/tooltip/
15641 //>>css.structure: ../../themes/base/core.css
15642 //>>css.structure: ../../themes/base/tooltip.css
15643 //>>css.theme: ../../themes/base/theme.css
15644
15645
15646
15647 $.widget( "ui.tooltip", {
15648 version: "1.12.1",
15649 options: {
15650 classes: {
15651 "ui-tooltip": "ui-corner-all ui-widget-shadow"
15652 },
15653 content: function() {
15654
15655 // support: IE<9, Opera in jQuery <1.7
15656 // .text() can't accept undefined, so coerce to a string
15657 var title = $( this ).attr( "title" ) || "";
15658
15659 // Escape title, since we're going from an attribute to raw HTML
15660 return $( "<a>" ).text( title ).html();
15661 },
15662 hide: true,
15663
15664 // Disabled elements have inconsistent behavior across browsers (#8661)
15665 items: "[title]:not([disabled])",
15666 position: {
15667 my: "left top+15",
15668 at: "left bottom",
15669 collision: "flipfit flip"
15670 },
15671 show: true,
15672 track: false,
15673
15674 // Callbacks
15675 close: null,
15676 open: null
15677 },
15678
15679 _addDescribedBy: function( elem, id ) {
15680 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
15681 describedby.push( id );
15682 elem
15683 .data( "ui-tooltip-id", id )
15684 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
15685 },
15686
15687 _removeDescribedBy: function( elem ) {
15688 var id = elem.data( "ui-tooltip-id" ),
15689 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
15690 index = $.inArray( id, describedby );
15691
15692 if ( index !== -1 ) {
15693 describedby.splice( index, 1 );
15694 }
15695
15696 elem.removeData( "ui-tooltip-id" );
15697 describedby = $.trim( describedby.join( " " ) );
15698 if ( describedby ) {
15699 elem.attr( "aria-describedby", describedby );
15700 } else {
15701 elem.removeAttr( "aria-describedby" );
15702 }
15703 },
15704
15705 _create: function() {
15706 this._on( {
15707 mouseover: "open",
15708 focusin: "open"
15709 } );
15710
15711 // IDs of generated tooltips, needed for destroy
15712 this.tooltips = {};
15713
15714 // IDs of parent tooltips where we removed the title attribute
15715 this.parents = {};
15716
15717 // Append the aria-live region so tooltips announce correctly
15718 this.liveRegion = $( "<div>" )
15719 .attr( {
15720 role: "log",
15721 "aria-live": "assertive",
15722 "aria-relevant": "additions"
15723 } )
15724 .appendTo( this.document[ 0 ].body );
15725 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
15726
15727 this.disabledTitles = $( [] );
15728 },
15729
15730 _setOption: function( key, value ) {
15731 var that = this;
15732
15733 this._super( key, value );
15734
15735 if ( key === "content" ) {
15736 $.each( this.tooltips, function( id, tooltipData ) {
15737 that._updateContent( tooltipData.element );
15738 } );
15739 }
15740 },
15741
15742 _setOptionDisabled: function( value ) {
15743 this[ value ? "_disable" : "_enable" ]();
15744 },
15745
15746 _disable: function() {
15747 var that = this;
15748
15749 // Close open tooltips
15750 $.each( this.tooltips, function( id, tooltipData ) {
15751 var event = $.Event( "blur" );
15752 event.target = event.currentTarget = tooltipData.element[ 0 ];
15753 that.close( event, true );
15754 } );
15755
15756 // Remove title attributes to prevent native tooltips
15757 this.disabledTitles = this.disabledTitles.add(
15758 this.element.find( this.options.items ).addBack()
15759 .filter( function() {
15760 var element = $( this );
15761 if ( element.is( "[title]" ) ) {
15762 return element
15763 .data( "ui-tooltip-title", element.attr( "title" ) )
15764 .removeAttr( "title" );
15765 }
15766 } )
15767 );
15768 },
15769
15770 _enable: function() {
15771
15772 // restore title attributes
15773 this.disabledTitles.each( function() {
15774 var element = $( this );
15775 if ( element.data( "ui-tooltip-title" ) ) {
15776 element.attr( "title", element.data( "ui-tooltip-title" ) );
15777 }
15778 } );
15779 this.disabledTitles = $( [] );
15780 },
15781
15782 open: function( event ) {
15783 var that = this,
15784 target = $( event ? event.target : this.element )
15785
15786 // we need closest here due to mouseover bubbling,
15787 // but always pointing at the same event target
15788 .closest( this.options.items );
15789
15790 // No element to show a tooltip for or the tooltip is already open
15791 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
15792 return;
15793 }
15794
15795 if ( target.attr( "title" ) ) {
15796 target.data( "ui-tooltip-title", target.attr( "title" ) );
15797 }
15798
15799 target.data( "ui-tooltip-open", true );
15800
15801 // Kill parent tooltips, custom or native, for hover
15802 if ( event && event.type === "mouseover" ) {
15803 target.parents().each( function() {
15804 var parent = $( this ),
15805 blurEvent;
15806 if ( parent.data( "ui-tooltip-open" ) ) {
15807 blurEvent = $.Event( "blur" );
15808 blurEvent.target = blurEvent.currentTarget = this;
15809 that.close( blurEvent, true );
15810 }
15811 if ( parent.attr( "title" ) ) {
15812 parent.uniqueId();
15813 that.parents[ this.id ] = {
15814 element: this,
15815 title: parent.attr( "title" )
15816 };
15817 parent.attr( "title", "" );
15818 }
15819 } );
15820 }
15821
15822 this._registerCloseHandlers( event, target );
15823 this._updateContent( target, event );
15824 },
15825
15826 _updateContent: function( target, event ) {
15827 var content,
15828 contentOption = this.options.content,
15829 that = this,
15830 eventType = event ? event.type : null;
15831
15832 if ( typeof contentOption === "string" || contentOption.nodeType ||
15833 contentOption.jquery ) {
15834 return this._open( event, target, contentOption );
15835 }
15836
15837 content = contentOption.call( target[ 0 ], function( response ) {
15838
15839 // IE may instantly serve a cached response for ajax requests
15840 // delay this call to _open so the other call to _open runs first
15841 that._delay( function() {
15842
15843 // Ignore async response if tooltip was closed already
15844 if ( !target.data( "ui-tooltip-open" ) ) {
15845 return;
15846 }
15847
15848 // JQuery creates a special event for focusin when it doesn't
15849 // exist natively. To improve performance, the native event
15850 // object is reused and the type is changed. Therefore, we can't
15851 // rely on the type being correct after the event finished
15852 // bubbling, so we set it back to the previous value. (#8740)
15853 if ( event ) {
15854 event.type = eventType;
15855 }
15856 this._open( event, target, response );
15857 } );
15858 } );
15859 if ( content ) {
15860 this._open( event, target, content );
15861 }
15862 },
15863
15864 _open: function( event, target, content ) {
15865 var tooltipData, tooltip, delayedShow, a11yContent,
15866 positionOption = $.extend( {}, this.options.position );
15867
15868 if ( !content ) {
15869 return;
15870 }
15871
15872 // Content can be updated multiple times. If the tooltip already
15873 // exists, then just update the content and bail.
15874 tooltipData = this._find( target );
15875 if ( tooltipData ) {
15876 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
15877 return;
15878 }
15879
15880 // If we have a title, clear it to prevent the native tooltip
15881 // we have to check first to avoid defining a title if none exists
15882 // (we don't want to cause an element to start matching [title])
15883 //
15884 // We use removeAttr only for key events, to allow IE to export the correct
15885 // accessible attributes. For mouse events, set to empty string to avoid
15886 // native tooltip showing up (happens only when removing inside mouseover).
15887 if ( target.is( "[title]" ) ) {
15888 if ( event && event.type === "mouseover" ) {
15889 target.attr( "title", "" );
15890 } else {
15891 target.removeAttr( "title" );
15892 }
15893 }
15894
15895 tooltipData = this._tooltip( target );
15896 tooltip = tooltipData.tooltip;
15897 this._addDescribedBy( target, tooltip.attr( "id" ) );
15898 tooltip.find( ".ui-tooltip-content" ).html( content );
15899
15900 // Support: Voiceover on OS X, JAWS on IE <= 9
15901 // JAWS announces deletions even when aria-relevant="additions"
15902 // Voiceover will sometimes re-read the entire log region's contents from the beginning
15903 this.liveRegion.children().hide();
15904 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
15905 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
15906 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
15907 a11yContent.appendTo( this.liveRegion );
15908
15909 function position( event ) {
15910 positionOption.of = event;
15911 if ( tooltip.is( ":hidden" ) ) {
15912 return;
15913 }
15914 tooltip.position( positionOption );
15915 }
15916 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
15917 this._on( this.document, {
15918 mousemove: position
15919 } );
15920
15921 // trigger once to override element-relative positioning
15922 position( event );
15923 } else {
15924 tooltip.position( $.extend( {
15925 of: target
15926 }, this.options.position ) );
15927 }
15928
15929 tooltip.hide();
15930
15931 this._show( tooltip, this.options.show );
15932
15933 // Handle tracking tooltips that are shown with a delay (#8644). As soon
15934 // as the tooltip is visible, position the tooltip using the most recent
15935 // event.
15936 // Adds the check to add the timers only when both delay and track options are set (#14682)
15937 if ( this.options.track && this.options.show && this.options.show.delay ) {
15938 delayedShow = this.delayedShow = setInterval( function() {
15939 if ( tooltip.is( ":visible" ) ) {
15940 position( positionOption.of );
15941 clearInterval( delayedShow );
15942 }
15943 }, $.fx.interval );
15944 }
15945
15946 this._trigger( "open", event, { tooltip: tooltip } );
15947 },
15948
15949 _registerCloseHandlers: function( event, target ) {
15950 var events = {
15951 keyup: function( event ) {
15952 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
15953 var fakeEvent = $.Event( event );
15954 fakeEvent.currentTarget = target[ 0 ];
15955 this.close( fakeEvent, true );
15956 }
15957 }
15958 };
15959
15960 // Only bind remove handler for delegated targets. Non-delegated
15961 // tooltips will handle this in destroy.
15962 if ( target[ 0 ] !== this.element[ 0 ] ) {
15963 events.remove = function() {
15964 this._removeTooltip( this._find( target ).tooltip );
15965 };
15966 }
15967
15968 if ( !event || event.type === "mouseover" ) {
15969 events.mouseleave = "close";
15970 }
15971 if ( !event || event.type === "focusin" ) {
15972 events.focusout = "close";
15973 }
15974 this._on( true, target, events );
15975 },
15976
15977 close: function( event ) {
15978 var tooltip,
15979 that = this,
15980 target = $( event ? event.currentTarget : this.element ),
15981 tooltipData = this._find( target );
15982
15983 // The tooltip may already be closed
15984 if ( !tooltipData ) {
15985
15986 // We set ui-tooltip-open immediately upon open (in open()), but only set the
15987 // additional data once there's actually content to show (in _open()). So even if the
15988 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
15989 // the period between open() and _open().
15990 target.removeData( "ui-tooltip-open" );
15991 return;
15992 }
15993
15994 tooltip = tooltipData.tooltip;
15995
15996 // Disabling closes the tooltip, so we need to track when we're closing
15997 // to avoid an infinite loop in case the tooltip becomes disabled on close
15998 if ( tooltipData.closing ) {
15999 return;
16000 }
16001
16002 // Clear the interval for delayed tracking tooltips
16003 clearInterval( this.delayedShow );
16004
16005 // Only set title if we had one before (see comment in _open())
16006 // If the title attribute has changed since open(), don't restore
16007 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
16008 target.attr( "title", target.data( "ui-tooltip-title" ) );
16009 }
16010
16011 this._removeDescribedBy( target );
16012
16013 tooltipData.hiding = true;
16014 tooltip.stop( true );
16015 this._hide( tooltip, this.options.hide, function() {
16016 that._removeTooltip( $( this ) );
16017 } );
16018
16019 target.removeData( "ui-tooltip-open" );
16020 this._off( target, "mouseleave focusout keyup" );
16021
16022 // Remove 'remove' binding only on delegated targets
16023 if ( target[ 0 ] !== this.element[ 0 ] ) {
16024 this._off( target, "remove" );
16025 }
16026 this._off( this.document, "mousemove" );
16027
16028 if ( event && event.type === "mouseleave" ) {
16029 $.each( this.parents, function( id, parent ) {
16030 $( parent.element ).attr( "title", parent.title );
16031 delete that.parents[ id ];
16032 } );
16033 }
16034
16035 tooltipData.closing = true;
16036 this._trigger( "close", event, { tooltip: tooltip } );
16037 if ( !tooltipData.hiding ) {
16038 tooltipData.closing = false;
16039 }
16040 },
16041
16042 _tooltip: function( element ) {
16043 var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
16044 content = $( "<div>" ).appendTo( tooltip ),
16045 id = tooltip.uniqueId().attr( "id" );
16046
16047 this._addClass( content, "ui-tooltip-content" );
16048 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
16049
16050 tooltip.appendTo( this._appendTo( element ) );
16051
16052 return this.tooltips[ id ] = {
16053 element: element,
16054 tooltip: tooltip
16055 };
16056 },
16057
16058 _find: function( target ) {
16059 var id = target.data( "ui-tooltip-id" );
16060 return id ? this.tooltips[ id ] : null;
16061 },
16062
16063 _removeTooltip: function( tooltip ) {
16064 tooltip.remove();
16065 delete this.tooltips[ tooltip.attr( "id" ) ];
16066 },
16067
16068 _appendTo: function( target ) {
16069 var element = target.closest( ".ui-front, dialog" );
16070
16071 if ( !element.length ) {
16072 element = this.document[ 0 ].body;
16073 }
16074
16075 return element;
16076 },
16077
16078 _destroy: function() {
16079 var that = this;
16080
16081 // Close open tooltips
16082 $.each( this.tooltips, function( id, tooltipData ) {
16083
16084 // Delegate to close method to handle common cleanup
16085 var event = $.Event( "blur" ),
16086 element = tooltipData.element;
16087 event.target = event.currentTarget = element[ 0 ];
16088 that.close( event, true );
16089
16090 // Remove immediately; destroying an open tooltip doesn't use the
16091 // hide animation
16092 $( "#" + id ).remove();
16093
16094 // Restore the title
16095 if ( element.data( "ui-tooltip-title" ) ) {
16096
16097 // If the title attribute has changed since open(), don't restore
16098 if ( !element.attr( "title" ) ) {
16099 element.attr( "title", element.data( "ui-tooltip-title" ) );
16100 }
16101 element.removeData( "ui-tooltip-title" );
16102 }
16103 } );
16104 this.liveRegion.remove();
16105 }
16106 } );
16107
16108 // DEPRECATED
16109 // TODO: Switch return back to widget declaration at top of file when this is removed
16110 if ( $.uiBackCompat !== false ) {
16111
16112 // Backcompat for tooltipClass option
16113 $.widget( "ui.tooltip", $.ui.tooltip, {
16114 options: {
16115 tooltipClass: null
16116 },
16117 _tooltip: function() {
16118 var tooltipData = this._superApply( arguments );
16119 if ( this.options.tooltipClass ) {
16120 tooltipData.tooltip.addClass( this.options.tooltipClass );
16121 }
16122 return tooltipData;
16123 }
16124 } );
16125 }
16126
16127 var widgetsTooltip = $.ui.tooltip;
16128
16129
16130 /*!
16131 * jQuery UI Effects 1.12.1
16132 * http://jqueryui.com
16133 *
16134 * Copyright jQuery Foundation and other contributors
16135 * Released under the MIT license.
16136 * http://jquery.org/license
16137 */
16138
16139 //>>label: Effects Core
16140 //>>group: Effects
16141 // jscs:disable maximumLineLength
16142 //>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
16143 // jscs:enable maximumLineLength
16144 //>>docs: http://api.jqueryui.com/category/effects-core/
16145 //>>demos: http://jqueryui.com/effect/
16146
16147
16148
16149 var dataSpace = "ui-effects-",
16150 dataSpaceStyle = "ui-effects-style",
16151 dataSpaceAnimated = "ui-effects-animated",
16152
16153 // Create a local jQuery because jQuery Color relies on it and the
16154 // global may not exist with AMD and a custom build (#10199)
16155 jQuery = $;
16156
16157 $.effects = {
16158 effect: {}
16159 };
16160
16161 /*!
16162 * jQuery Color Animations v2.1.2
16163 * https://github.com/jquery/jquery-color
16164 *
16165 * Copyright 2014 jQuery Foundation and other contributors
16166 * Released under the MIT license.
16167 * http://jquery.org/license
16168 *
16169 * Date: Wed Jan 16 08:47:09 2013 -0600
16170 */
16171 ( function( jQuery, undefined ) {
16172
16173 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
16174 "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
16175
16176 // Plusequals test for += 100 -= 100
16177 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
16178
16179 // A set of RE's that can match strings and generate color tuples.
16180 stringParsers = [ {
16181 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
16182 parse: function( execResult ) {
16183 return [
16184 execResult[ 1 ],
16185 execResult[ 2 ],
16186 execResult[ 3 ],
16187 execResult[ 4 ]
16188 ];
16189 }
16190 }, {
16191 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
16192 parse: function( execResult ) {
16193 return [
16194 execResult[ 1 ] * 2.55,
16195 execResult[ 2 ] * 2.55,
16196 execResult[ 3 ] * 2.55,
16197 execResult[ 4 ]
16198 ];
16199 }
16200 }, {
16201
16202 // This regex ignores A-F because it's compared against an already lowercased string
16203 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
16204 parse: function( execResult ) {
16205 return [
16206 parseInt( execResult[ 1 ], 16 ),
16207 parseInt( execResult[ 2 ], 16 ),
16208 parseInt( execResult[ 3 ], 16 )
16209 ];
16210 }
16211 }, {
16212
16213 // This regex ignores A-F because it's compared against an already lowercased string
16214 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
16215 parse: function( execResult ) {
16216 return [
16217 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
16218 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
16219 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
16220 ];
16221 }
16222 }, {
16223 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
16224 space: "hsla",
16225 parse: function( execResult ) {
16226 return [
16227 execResult[ 1 ],
16228 execResult[ 2 ] / 100,
16229 execResult[ 3 ] / 100,
16230 execResult[ 4 ]
16231 ];
16232 }
16233 } ],
16234
16235 // JQuery.Color( )
16236 color = jQuery.Color = function( color, green, blue, alpha ) {
16237 return new jQuery.Color.fn.parse( color, green, blue, alpha );
16238 },
16239 spaces = {
16240 rgba: {
16241 props: {
16242 red: {
16243 idx: 0,
16244 type: "byte"
16245 },
16246 green: {
16247 idx: 1,
16248 type: "byte"
16249 },
16250 blue: {
16251 idx: 2,
16252 type: "byte"
16253 }
16254 }
16255 },
16256
16257 hsla: {
16258 props: {
16259 hue: {
16260 idx: 0,
16261 type: "degrees"
16262 },
16263 saturation: {
16264 idx: 1,
16265 type: "percent"
16266 },
16267 lightness: {
16268 idx: 2,
16269 type: "percent"
16270 }
16271 }
16272 }
16273 },
16274 propTypes = {
16275 "byte": {
16276 floor: true,
16277 max: 255
16278 },
16279 "percent": {
16280 max: 1
16281 },
16282 "degrees": {
16283 mod: 360,
16284 floor: true
16285 }
16286 },
16287 support = color.support = {},
16288
16289 // Element for support tests
16290 supportElem = jQuery( "<p>" )[ 0 ],
16291
16292 // Colors = jQuery.Color.names
16293 colors,
16294
16295 // Local aliases of functions called often
16296 each = jQuery.each;
16297
16298 // Determine rgba support immediately
16299 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
16300 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
16301
16302 // Define cache name and alpha properties
16303 // for rgba and hsla spaces
16304 each( spaces, function( spaceName, space ) {
16305 space.cache = "_" + spaceName;
16306 space.props.alpha = {
16307 idx: 3,
16308 type: "percent",
16309 def: 1
16310 };
16311 } );
16312
16313 function clamp( value, prop, allowEmpty ) {
16314 var type = propTypes[ prop.type ] || {};
16315
16316 if ( value == null ) {
16317 return ( allowEmpty || !prop.def ) ? null : prop.def;
16318 }
16319
16320 // ~~ is an short way of doing floor for positive numbers
16321 value = type.floor ? ~~value : parseFloat( value );
16322
16323 // IE will pass in empty strings as value for alpha,
16324 // which will hit this case
16325 if ( isNaN( value ) ) {
16326 return prop.def;
16327 }
16328
16329 if ( type.mod ) {
16330
16331 // We add mod before modding to make sure that negatives values
16332 // get converted properly: -10 -> 350
16333 return ( value + type.mod ) % type.mod;
16334 }
16335
16336 // For now all property types without mod have min and max
16337 return 0 > value ? 0 : type.max < value ? type.max : value;
16338 }
16339
16340 function stringParse( string ) {
16341 var inst = color(),
16342 rgba = inst._rgba = [];
16343
16344 string = string.toLowerCase();
16345
16346 each( stringParsers, function( i, parser ) {
16347 var parsed,
16348 match = parser.re.exec( string ),
16349 values = match && parser.parse( match ),
16350 spaceName = parser.space || "rgba";
16351
16352 if ( values ) {
16353 parsed = inst[ spaceName ]( values );
16354
16355 // If this was an rgba parse the assignment might happen twice
16356 // oh well....
16357 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
16358 rgba = inst._rgba = parsed._rgba;
16359
16360 // Exit each( stringParsers ) here because we matched
16361 return false;
16362 }
16363 } );
16364
16365 // Found a stringParser that handled it
16366 if ( rgba.length ) {
16367
16368 // If this came from a parsed string, force "transparent" when alpha is 0
16369 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
16370 if ( rgba.join() === "0,0,0,0" ) {
16371 jQuery.extend( rgba, colors.transparent );
16372 }
16373 return inst;
16374 }
16375
16376 // Named colors
16377 return colors[ string ];
16378 }
16379
16380 color.fn = jQuery.extend( color.prototype, {
16381 parse: function( red, green, blue, alpha ) {
16382 if ( red === undefined ) {
16383 this._rgba = [ null, null, null, null ];
16384 return this;
16385 }
16386 if ( red.jquery || red.nodeType ) {
16387 red = jQuery( red ).css( green );
16388 green = undefined;
16389 }
16390
16391 var inst = this,
16392 type = jQuery.type( red ),
16393 rgba = this._rgba = [];
16394
16395 // More than 1 argument specified - assume ( red, green, blue, alpha )
16396 if ( green !== undefined ) {
16397 red = [ red, green, blue, alpha ];
16398 type = "array";
16399 }
16400
16401 if ( type === "string" ) {
16402 return this.parse( stringParse( red ) || colors._default );
16403 }
16404
16405 if ( type === "array" ) {
16406 each( spaces.rgba.props, function( key, prop ) {
16407 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
16408 } );
16409 return this;
16410 }
16411
16412 if ( type === "object" ) {
16413 if ( red instanceof color ) {
16414 each( spaces, function( spaceName, space ) {
16415 if ( red[ space.cache ] ) {
16416 inst[ space.cache ] = red[ space.cache ].slice();
16417 }
16418 } );
16419 } else {
16420 each( spaces, function( spaceName, space ) {
16421 var cache = space.cache;
16422 each( space.props, function( key, prop ) {
16423
16424 // If the cache doesn't exist, and we know how to convert
16425 if ( !inst[ cache ] && space.to ) {
16426
16427 // If the value was null, we don't need to copy it
16428 // if the key was alpha, we don't need to copy it either
16429 if ( key === "alpha" || red[ key ] == null ) {
16430 return;
16431 }
16432 inst[ cache ] = space.to( inst._rgba );
16433 }
16434
16435 // This is the only case where we allow nulls for ALL properties.
16436 // call clamp with alwaysAllowEmpty
16437 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
16438 } );
16439
16440 // Everything defined but alpha?
16441 if ( inst[ cache ] &&
16442 jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
16443
16444 // Use the default of 1
16445 inst[ cache ][ 3 ] = 1;
16446 if ( space.from ) {
16447 inst._rgba = space.from( inst[ cache ] );
16448 }
16449 }
16450 } );
16451 }
16452 return this;
16453 }
16454 },
16455 is: function( compare ) {
16456 var is = color( compare ),
16457 same = true,
16458 inst = this;
16459
16460 each( spaces, function( _, space ) {
16461 var localCache,
16462 isCache = is[ space.cache ];
16463 if ( isCache ) {
16464 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
16465 each( space.props, function( _, prop ) {
16466 if ( isCache[ prop.idx ] != null ) {
16467 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
16468 return same;
16469 }
16470 } );
16471 }
16472 return same;
16473 } );
16474 return same;
16475 },
16476 _space: function() {
16477 var used = [],
16478 inst = this;
16479 each( spaces, function( spaceName, space ) {
16480 if ( inst[ space.cache ] ) {
16481 used.push( spaceName );
16482 }
16483 } );
16484 return used.pop();
16485 },
16486 transition: function( other, distance ) {
16487 var end = color( other ),
16488 spaceName = end._space(),
16489 space = spaces[ spaceName ],
16490 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
16491 start = startColor[ space.cache ] || space.to( startColor._rgba ),
16492 result = start.slice();
16493
16494 end = end[ space.cache ];
16495 each( space.props, function( key, prop ) {
16496 var index = prop.idx,
16497 startValue = start[ index ],
16498 endValue = end[ index ],
16499 type = propTypes[ prop.type ] || {};
16500
16501 // If null, don't override start value
16502 if ( endValue === null ) {
16503 return;
16504 }
16505
16506 // If null - use end
16507 if ( startValue === null ) {
16508 result[ index ] = endValue;
16509 } else {
16510 if ( type.mod ) {
16511 if ( endValue - startValue > type.mod / 2 ) {
16512 startValue += type.mod;
16513 } else if ( startValue - endValue > type.mod / 2 ) {
16514 startValue -= type.mod;
16515 }
16516 }
16517 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
16518 }
16519 } );
16520 return this[ spaceName ]( result );
16521 },
16522 blend: function( opaque ) {
16523
16524 // If we are already opaque - return ourself
16525 if ( this._rgba[ 3 ] === 1 ) {
16526 return this;
16527 }
16528
16529 var rgb = this._rgba.slice(),
16530 a = rgb.pop(),
16531 blend = color( opaque )._rgba;
16532
16533 return color( jQuery.map( rgb, function( v, i ) {
16534 return ( 1 - a ) * blend[ i ] + a * v;
16535 } ) );
16536 },
16537 toRgbaString: function() {
16538 var prefix = "rgba(",
16539 rgba = jQuery.map( this._rgba, function( v, i ) {
16540 return v == null ? ( i > 2 ? 1 : 0 ) : v;
16541 } );
16542
16543 if ( rgba[ 3 ] === 1 ) {
16544 rgba.pop();
16545 prefix = "rgb(";
16546 }
16547
16548 return prefix + rgba.join() + ")";
16549 },
16550 toHslaString: function() {
16551 var prefix = "hsla(",
16552 hsla = jQuery.map( this.hsla(), function( v, i ) {
16553 if ( v == null ) {
16554 v = i > 2 ? 1 : 0;
16555 }
16556
16557 // Catch 1 and 2
16558 if ( i && i < 3 ) {
16559 v = Math.round( v * 100 ) + "%";
16560 }
16561 return v;
16562 } );
16563
16564 if ( hsla[ 3 ] === 1 ) {
16565 hsla.pop();
16566 prefix = "hsl(";
16567 }
16568 return prefix + hsla.join() + ")";
16569 },
16570 toHexString: function( includeAlpha ) {
16571 var rgba = this._rgba.slice(),
16572 alpha = rgba.pop();
16573
16574 if ( includeAlpha ) {
16575 rgba.push( ~~( alpha * 255 ) );
16576 }
16577
16578 return "#" + jQuery.map( rgba, function( v ) {
16579
16580 // Default to 0 when nulls exist
16581 v = ( v || 0 ).toString( 16 );
16582 return v.length === 1 ? "0" + v : v;
16583 } ).join( "" );
16584 },
16585 toString: function() {
16586 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
16587 }
16588 } );
16589 color.fn.parse.prototype = color.fn;
16590
16591 // Hsla conversions adapted from:
16592 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
16593
16594 function hue2rgb( p, q, h ) {
16595 h = ( h + 1 ) % 1;
16596 if ( h * 6 < 1 ) {
16597 return p + ( q - p ) * h * 6;
16598 }
16599 if ( h * 2 < 1 ) {
16600 return q;
16601 }
16602 if ( h * 3 < 2 ) {
16603 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
16604 }
16605 return p;
16606 }
16607
16608 spaces.hsla.to = function( rgba ) {
16609 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
16610 return [ null, null, null, rgba[ 3 ] ];
16611 }
16612 var r = rgba[ 0 ] / 255,
16613 g = rgba[ 1 ] / 255,
16614 b = rgba[ 2 ] / 255,
16615 a = rgba[ 3 ],
16616 max = Math.max( r, g, b ),
16617 min = Math.min( r, g, b ),
16618 diff = max - min,
16619 add = max + min,
16620 l = add * 0.5,
16621 h, s;
16622
16623 if ( min === max ) {
16624 h = 0;
16625 } else if ( r === max ) {
16626 h = ( 60 * ( g - b ) / diff ) + 360;
16627 } else if ( g === max ) {
16628 h = ( 60 * ( b - r ) / diff ) + 120;
16629 } else {
16630 h = ( 60 * ( r - g ) / diff ) + 240;
16631 }
16632
16633 // Chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
16634 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
16635 if ( diff === 0 ) {
16636 s = 0;
16637 } else if ( l <= 0.5 ) {
16638 s = diff / add;
16639 } else {
16640 s = diff / ( 2 - add );
16641 }
16642 return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
16643 };
16644
16645 spaces.hsla.from = function( hsla ) {
16646 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
16647 return [ null, null, null, hsla[ 3 ] ];
16648 }
16649 var h = hsla[ 0 ] / 360,
16650 s = hsla[ 1 ],
16651 l = hsla[ 2 ],
16652 a = hsla[ 3 ],
16653 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
16654 p = 2 * l - q;
16655
16656 return [
16657 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
16658 Math.round( hue2rgb( p, q, h ) * 255 ),
16659 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
16660 a
16661 ];
16662 };
16663
16664 each( spaces, function( spaceName, space ) {
16665 var props = space.props,
16666 cache = space.cache,
16667 to = space.to,
16668 from = space.from;
16669
16670 // Makes rgba() and hsla()
16671 color.fn[ spaceName ] = function( value ) {
16672
16673 // Generate a cache for this space if it doesn't exist
16674 if ( to && !this[ cache ] ) {
16675 this[ cache ] = to( this._rgba );
16676 }
16677 if ( value === undefined ) {
16678 return this[ cache ].slice();
16679 }
16680
16681 var ret,
16682 type = jQuery.type( value ),
16683 arr = ( type === "array" || type === "object" ) ? value : arguments,
16684 local = this[ cache ].slice();
16685
16686 each( props, function( key, prop ) {
16687 var val = arr[ type === "object" ? key : prop.idx ];
16688 if ( val == null ) {
16689 val = local[ prop.idx ];
16690 }
16691 local[ prop.idx ] = clamp( val, prop );
16692 } );
16693
16694 if ( from ) {
16695 ret = color( from( local ) );
16696 ret[ cache ] = local;
16697 return ret;
16698 } else {
16699 return color( local );
16700 }
16701 };
16702
16703 // Makes red() green() blue() alpha() hue() saturation() lightness()
16704 each( props, function( key, prop ) {
16705
16706 // Alpha is included in more than one space
16707 if ( color.fn[ key ] ) {
16708 return;
16709 }
16710 color.fn[ key ] = function( value ) {
16711 var vtype = jQuery.type( value ),
16712 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
16713 local = this[ fn ](),
16714 cur = local[ prop.idx ],
16715 match;
16716
16717 if ( vtype === "undefined" ) {
16718 return cur;
16719 }
16720
16721 if ( vtype === "function" ) {
16722 value = value.call( this, cur );
16723 vtype = jQuery.type( value );
16724 }
16725 if ( value == null && prop.empty ) {
16726 return this;
16727 }
16728 if ( vtype === "string" ) {
16729 match = rplusequals.exec( value );
16730 if ( match ) {
16731 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
16732 }
16733 }
16734 local[ prop.idx ] = value;
16735 return this[ fn ]( local );
16736 };
16737 } );
16738 } );
16739
16740 // Add cssHook and .fx.step function for each named hook.
16741 // accept a space separated string of properties
16742 color.hook = function( hook ) {
16743 var hooks = hook.split( " " );
16744 each( hooks, function( i, hook ) {
16745 jQuery.cssHooks[ hook ] = {
16746 set: function( elem, value ) {
16747 var parsed, curElem,
16748 backgroundColor = "";
16749
16750 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" ||
16751 ( parsed = stringParse( value ) ) ) ) {
16752 value = color( parsed || value );
16753 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
16754 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
16755 while (
16756 ( backgroundColor === "" || backgroundColor === "transparent" ) &&
16757 curElem && curElem.style
16758 ) {
16759 try {
16760 backgroundColor = jQuery.css( curElem, "backgroundColor" );
16761 curElem = curElem.parentNode;
16762 } catch ( e ) {
16763 }
16764 }
16765
16766 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
16767 backgroundColor :
16768 "_default" );
16769 }
16770
16771 value = value.toRgbaString();
16772 }
16773 try {
16774 elem.style[ hook ] = value;
16775 } catch ( e ) {
16776
16777 // Wrapped to prevent IE from throwing errors on "invalid" values like
16778 // 'auto' or 'inherit'
16779 }
16780 }
16781 };
16782 jQuery.fx.step[ hook ] = function( fx ) {
16783 if ( !fx.colorInit ) {
16784 fx.start = color( fx.elem, hook );
16785 fx.end = color( fx.end );
16786 fx.colorInit = true;
16787 }
16788 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
16789 };
16790 } );
16791
16792 };
16793
16794 color.hook( stepHooks );
16795
16796 jQuery.cssHooks.borderColor = {
16797 expand: function( value ) {
16798 var expanded = {};
16799
16800 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
16801 expanded[ "border" + part + "Color" ] = value;
16802 } );
16803 return expanded;
16804 }
16805 };
16806
16807 // Basic color names only.
16808 // Usage of any of the other color names requires adding yourself or including
16809 // jquery.color.svg-names.js.
16810 colors = jQuery.Color.names = {
16811
16812 // 4.1. Basic color keywords
16813 aqua: "#00ffff",
16814 black: "#000000",
16815 blue: "#0000ff",
16816 fuchsia: "#ff00ff",
16817 gray: "#808080",
16818 green: "#008000",
16819 lime: "#00ff00",
16820 maroon: "#800000",
16821 navy: "#000080",
16822 olive: "#808000",
16823 purple: "#800080",
16824 red: "#ff0000",
16825 silver: "#c0c0c0",
16826 teal: "#008080",
16827 white: "#ffffff",
16828 yellow: "#ffff00",
16829
16830 // 4.2.3. "transparent" color keyword
16831 transparent: [ null, null, null, 0 ],
16832
16833 _default: "#ffffff"
16834 };
16835
16836 } )( jQuery );
16837
16838 /******************************************************************************/
16839 /****************************** CLASS ANIMATIONS ******************************/
16840 /******************************************************************************/
16841 ( function() {
16842
16843 var classAnimationActions = [ "add", "remove", "toggle" ],
16844 shorthandStyles = {
16845 border: 1,
16846 borderBottom: 1,
16847 borderColor: 1,
16848 borderLeft: 1,
16849 borderRight: 1,
16850 borderTop: 1,
16851 borderWidth: 1,
16852 margin: 1,
16853 padding: 1
16854 };
16855
16856 $.each(
16857 [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
16858 function( _, prop ) {
16859 $.fx.step[ prop ] = function( fx ) {
16860 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
16861 jQuery.style( fx.elem, prop, fx.end );
16862 fx.setAttr = true;
16863 }
16864 };
16865 }
16866 );
16867
16868 function getElementStyles( elem ) {
16869 var key, len,
16870 style = elem.ownerDocument.defaultView ?
16871 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
16872 elem.currentStyle,
16873 styles = {};
16874
16875 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
16876 len = style.length;
16877 while ( len-- ) {
16878 key = style[ len ];
16879 if ( typeof style[ key ] === "string" ) {
16880 styles[ $.camelCase( key ) ] = style[ key ];
16881 }
16882 }
16883
16884 // Support: Opera, IE <9
16885 } else {
16886 for ( key in style ) {
16887 if ( typeof style[ key ] === "string" ) {
16888 styles[ key ] = style[ key ];
16889 }
16890 }
16891 }
16892
16893 return styles;
16894 }
16895
16896 function styleDifference( oldStyle, newStyle ) {
16897 var diff = {},
16898 name, value;
16899
16900 for ( name in newStyle ) {
16901 value = newStyle[ name ];
16902 if ( oldStyle[ name ] !== value ) {
16903 if ( !shorthandStyles[ name ] ) {
16904 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
16905 diff[ name ] = value;
16906 }
16907 }
16908 }
16909 }
16910
16911 return diff;
16912 }
16913
16914 // Support: jQuery <1.8
16915 if ( !$.fn.addBack ) {
16916 $.fn.addBack = function( selector ) {
16917 return this.add( selector == null ?
16918 this.prevObject : this.prevObject.filter( selector )
16919 );
16920 };
16921 }
16922
16923 $.effects.animateClass = function( value, duration, easing, callback ) {
16924 var o = $.speed( duration, easing, callback );
16925
16926 return this.queue( function() {
16927 var animated = $( this ),
16928 baseClass = animated.attr( "class" ) || "",
16929 applyClassChange,
16930 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
16931
16932 // Map the animated objects to store the original styles.
16933 allAnimations = allAnimations.map( function() {
16934 var el = $( this );
16935 return {
16936 el: el,
16937 start: getElementStyles( this )
16938 };
16939 } );
16940
16941 // Apply class change
16942 applyClassChange = function() {
16943 $.each( classAnimationActions, function( i, action ) {
16944 if ( value[ action ] ) {
16945 animated[ action + "Class" ]( value[ action ] );
16946 }
16947 } );
16948 };
16949 applyClassChange();
16950
16951 // Map all animated objects again - calculate new styles and diff
16952 allAnimations = allAnimations.map( function() {
16953 this.end = getElementStyles( this.el[ 0 ] );
16954 this.diff = styleDifference( this.start, this.end );
16955 return this;
16956 } );
16957
16958 // Apply original class
16959 animated.attr( "class", baseClass );
16960
16961 // Map all animated objects again - this time collecting a promise
16962 allAnimations = allAnimations.map( function() {
16963 var styleInfo = this,
16964 dfd = $.Deferred(),
16965 opts = $.extend( {}, o, {
16966 queue: false,
16967 complete: function() {
16968 dfd.resolve( styleInfo );
16969 }
16970 } );
16971
16972 this.el.animate( this.diff, opts );
16973 return dfd.promise();
16974 } );
16975
16976 // Once all animations have completed:
16977 $.when.apply( $, allAnimations.get() ).done( function() {
16978
16979 // Set the final class
16980 applyClassChange();
16981
16982 // For each animated element,
16983 // clear all css properties that were animated
16984 $.each( arguments, function() {
16985 var el = this.el;
16986 $.each( this.diff, function( key ) {
16987 el.css( key, "" );
16988 } );
16989 } );
16990
16991 // This is guarnteed to be there if you use jQuery.speed()
16992 // it also handles dequeuing the next anim...
16993 o.complete.call( animated[ 0 ] );
16994 } );
16995 } );
16996 };
16997
16998 $.fn.extend( {
16999 addClass: ( function( orig ) {
17000 return function( classNames, speed, easing, callback ) {
17001 return speed ?
17002 $.effects.animateClass.call( this,
17003 { add: classNames }, speed, easing, callback ) :
17004 orig.apply( this, arguments );
17005 };
17006 } )( $.fn.addClass ),
17007
17008 removeClass: ( function( orig ) {
17009 return function( classNames, speed, easing, callback ) {
17010 return arguments.length > 1 ?
17011 $.effects.animateClass.call( this,
17012 { remove: classNames }, speed, easing, callback ) :
17013 orig.apply( this, arguments );
17014 };
17015 } )( $.fn.removeClass ),
17016
17017 toggleClass: ( function( orig ) {
17018 return function( classNames, force, speed, easing, callback ) {
17019 if ( typeof force === "boolean" || force === undefined ) {
17020 if ( !speed ) {
17021
17022 // Without speed parameter
17023 return orig.apply( this, arguments );
17024 } else {
17025 return $.effects.animateClass.call( this,
17026 ( force ? { add: classNames } : { remove: classNames } ),
17027 speed, easing, callback );
17028 }
17029 } else {
17030
17031 // Without force parameter
17032 return $.effects.animateClass.call( this,
17033 { toggle: classNames }, force, speed, easing );
17034 }
17035 };
17036 } )( $.fn.toggleClass ),
17037
17038 switchClass: function( remove, add, speed, easing, callback ) {
17039 return $.effects.animateClass.call( this, {
17040 add: add,
17041 remove: remove
17042 }, speed, easing, callback );
17043 }
17044 } );
17045
17046 } )();
17047
17048 /******************************************************************************/
17049 /*********************************** EFFECTS **********************************/
17050 /******************************************************************************/
17051
17052 ( function() {
17053
17054 if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
17055 $.expr.filters.animated = ( function( orig ) {
17056 return function( elem ) {
17057 return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
17058 };
17059 } )( $.expr.filters.animated );
17060 }
17061
17062 if ( $.uiBackCompat !== false ) {
17063 $.extend( $.effects, {
17064
17065 // Saves a set of properties in a data storage
17066 save: function( element, set ) {
17067 var i = 0, length = set.length;
17068 for ( ; i < length; i++ ) {
17069 if ( set[ i ] !== null ) {
17070 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
17071 }
17072 }
17073 },
17074
17075 // Restores a set of previously saved properties from a data storage
17076 restore: function( element, set ) {
17077 var val, i = 0, length = set.length;
17078 for ( ; i < length; i++ ) {
17079 if ( set[ i ] !== null ) {
17080 val = element.data( dataSpace + set[ i ] );
17081 element.css( set[ i ], val );
17082 }
17083 }
17084 },
17085
17086 setMode: function( el, mode ) {
17087 if ( mode === "toggle" ) {
17088 mode = el.is( ":hidden" ) ? "show" : "hide";
17089 }
17090 return mode;
17091 },
17092
17093 // Wraps the element around a wrapper that copies position properties
17094 createWrapper: function( element ) {
17095
17096 // If the element is already wrapped, return it
17097 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
17098 return element.parent();
17099 }
17100
17101 // Wrap the element
17102 var props = {
17103 width: element.outerWidth( true ),
17104 height: element.outerHeight( true ),
17105 "float": element.css( "float" )
17106 },
17107 wrapper = $( "<div></div>" )
17108 .addClass( "ui-effects-wrapper" )
17109 .css( {
17110 fontSize: "100%",
17111 background: "transparent",
17112 border: "none",
17113 margin: 0,
17114 padding: 0
17115 } ),
17116
17117 // Store the size in case width/height are defined in % - Fixes #5245
17118 size = {
17119 width: element.width(),
17120 height: element.height()
17121 },
17122 active = document.activeElement;
17123
17124 // Support: Firefox
17125 // Firefox incorrectly exposes anonymous content
17126 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
17127 try {
17128 active.id;
17129 } catch ( e ) {
17130 active = document.body;
17131 }
17132
17133 element.wrap( wrapper );
17134
17135 // Fixes #7595 - Elements lose focus when wrapped.
17136 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
17137 $( active ).trigger( "focus" );
17138 }
17139
17140 // Hotfix for jQuery 1.4 since some change in wrap() seems to actually
17141 // lose the reference to the wrapped element
17142 wrapper = element.parent();
17143
17144 // Transfer positioning properties to the wrapper
17145 if ( element.css( "position" ) === "static" ) {
17146 wrapper.css( { position: "relative" } );
17147 element.css( { position: "relative" } );
17148 } else {
17149 $.extend( props, {
17150 position: element.css( "position" ),
17151 zIndex: element.css( "z-index" )
17152 } );
17153 $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
17154 props[ pos ] = element.css( pos );
17155 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
17156 props[ pos ] = "auto";
17157 }
17158 } );
17159 element.css( {
17160 position: "relative",
17161 top: 0,
17162 left: 0,
17163 right: "auto",
17164 bottom: "auto"
17165 } );
17166 }
17167 element.css( size );
17168
17169 return wrapper.css( props ).show();
17170 },
17171
17172 removeWrapper: function( element ) {
17173 var active = document.activeElement;
17174
17175 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
17176 element.parent().replaceWith( element );
17177
17178 // Fixes #7595 - Elements lose focus when wrapped.
17179 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
17180 $( active ).trigger( "focus" );
17181 }
17182 }
17183
17184 return element;
17185 }
17186 } );
17187 }
17188
17189 $.extend( $.effects, {
17190 version: "1.12.1",
17191
17192 define: function( name, mode, effect ) {
17193 if ( !effect ) {
17194 effect = mode;
17195 mode = "effect";
17196 }
17197
17198 $.effects.effect[ name ] = effect;
17199 $.effects.effect[ name ].mode = mode;
17200
17201 return effect;
17202 },
17203
17204 scaledDimensions: function( element, percent, direction ) {
17205 if ( percent === 0 ) {
17206 return {
17207 height: 0,
17208 width: 0,
17209 outerHeight: 0,
17210 outerWidth: 0
17211 };
17212 }
17213
17214 var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
17215 y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
17216
17217 return {
17218 height: element.height() * y,
17219 width: element.width() * x,
17220 outerHeight: element.outerHeight() * y,
17221 outerWidth: element.outerWidth() * x
17222 };
17223
17224 },
17225
17226 clipToBox: function( animation ) {
17227 return {
17228 width: animation.clip.right - animation.clip.left,
17229 height: animation.clip.bottom - animation.clip.top,
17230 left: animation.clip.left,
17231 top: animation.clip.top
17232 };
17233 },
17234
17235 // Injects recently queued functions to be first in line (after "inprogress")
17236 unshift: function( element, queueLength, count ) {
17237 var queue = element.queue();
17238
17239 if ( queueLength > 1 ) {
17240 queue.splice.apply( queue,
17241 [ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
17242 }
17243 element.dequeue();
17244 },
17245
17246 saveStyle: function( element ) {
17247 element.data( dataSpaceStyle, element[ 0 ].style.cssText );
17248 },
17249
17250 restoreStyle: function( element ) {
17251 element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
17252 element.removeData( dataSpaceStyle );
17253 },
17254
17255 mode: function( element, mode ) {
17256 var hidden = element.is( ":hidden" );
17257
17258 if ( mode === "toggle" ) {
17259 mode = hidden ? "show" : "hide";
17260 }
17261 if ( hidden ? mode === "hide" : mode === "show" ) {
17262 mode = "none";
17263 }
17264 return mode;
17265 },
17266
17267 // Translates a [top,left] array into a baseline value
17268 getBaseline: function( origin, original ) {
17269 var y, x;
17270
17271 switch ( origin[ 0 ] ) {
17272 case "top":
17273 y = 0;
17274 break;
17275 case "middle":
17276 y = 0.5;
17277 break;
17278 case "bottom":
17279 y = 1;
17280 break;
17281 default:
17282 y = origin[ 0 ] / original.height;
17283 }
17284
17285 switch ( origin[ 1 ] ) {
17286 case "left":
17287 x = 0;
17288 break;
17289 case "center":
17290 x = 0.5;
17291 break;
17292 case "right":
17293 x = 1;
17294 break;
17295 default:
17296 x = origin[ 1 ] / original.width;
17297 }
17298
17299 return {
17300 x: x,
17301 y: y
17302 };
17303 },
17304
17305 // Creates a placeholder element so that the original element can be made absolute
17306 createPlaceholder: function( element ) {
17307 var placeholder,
17308 cssPosition = element.css( "position" ),
17309 position = element.position();
17310
17311 // Lock in margins first to account for form elements, which
17312 // will change margin if you explicitly set height
17313 // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
17314 // Support: Safari
17315 element.css( {
17316 marginTop: element.css( "marginTop" ),
17317 marginBottom: element.css( "marginBottom" ),
17318 marginLeft: element.css( "marginLeft" ),
17319 marginRight: element.css( "marginRight" )
17320 } )
17321 .outerWidth( element.outerWidth() )
17322 .outerHeight( element.outerHeight() );
17323
17324 if ( /^(static|relative)/.test( cssPosition ) ) {
17325 cssPosition = "absolute";
17326
17327 placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
17328
17329 // Convert inline to inline block to account for inline elements
17330 // that turn to inline block based on content (like img)
17331 display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
17332 "inline-block" :
17333 "block",
17334 visibility: "hidden",
17335
17336 // Margins need to be set to account for margin collapse
17337 marginTop: element.css( "marginTop" ),
17338 marginBottom: element.css( "marginBottom" ),
17339 marginLeft: element.css( "marginLeft" ),
17340 marginRight: element.css( "marginRight" ),
17341 "float": element.css( "float" )
17342 } )
17343 .outerWidth( element.outerWidth() )
17344 .outerHeight( element.outerHeight() )
17345 .addClass( "ui-effects-placeholder" );
17346
17347 element.data( dataSpace + "placeholder", placeholder );
17348 }
17349
17350 element.css( {
17351 position: cssPosition,
17352 left: position.left,
17353 top: position.top
17354 } );
17355
17356 return placeholder;
17357 },
17358
17359 removePlaceholder: function( element ) {
17360 var dataKey = dataSpace + "placeholder",
17361 placeholder = element.data( dataKey );
17362
17363 if ( placeholder ) {
17364 placeholder.remove();
17365 element.removeData( dataKey );
17366 }
17367 },
17368
17369 // Removes a placeholder if it exists and restores
17370 // properties that were modified during placeholder creation
17371 cleanUp: function( element ) {
17372 $.effects.restoreStyle( element );
17373 $.effects.removePlaceholder( element );
17374 },
17375
17376 setTransition: function( element, list, factor, value ) {
17377 value = value || {};
17378 $.each( list, function( i, x ) {
17379 var unit = element.cssUnit( x );
17380 if ( unit[ 0 ] > 0 ) {
17381 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
17382 }
17383 } );
17384 return value;
17385 }
17386 } );
17387
17388 // Return an effect options object for the given parameters:
17389 function _normalizeArguments( effect, options, speed, callback ) {
17390
17391 // Allow passing all options as the first parameter
17392 if ( $.isPlainObject( effect ) ) {
17393 options = effect;
17394 effect = effect.effect;
17395 }
17396
17397 // Convert to an object
17398 effect = { effect: effect };
17399
17400 // Catch (effect, null, ...)
17401 if ( options == null ) {
17402 options = {};
17403 }
17404
17405 // Catch (effect, callback)
17406 if ( $.isFunction( options ) ) {
17407 callback = options;
17408 speed = null;
17409 options = {};
17410 }
17411
17412 // Catch (effect, speed, ?)
17413 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
17414 callback = speed;
17415 speed = options;
17416 options = {};
17417 }
17418
17419 // Catch (effect, options, callback)
17420 if ( $.isFunction( speed ) ) {
17421 callback = speed;
17422 speed = null;
17423 }
17424
17425 // Add options to effect
17426 if ( options ) {
17427 $.extend( effect, options );
17428 }
17429
17430 speed = speed || options.duration;
17431 effect.duration = $.fx.off ? 0 :
17432 typeof speed === "number" ? speed :
17433 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
17434 $.fx.speeds._default;
17435
17436 effect.complete = callback || options.complete;
17437
17438 return effect;
17439 }
17440
17441 function standardAnimationOption( option ) {
17442
17443 // Valid standard speeds (nothing, number, named speed)
17444 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
17445 return true;
17446 }
17447
17448 // Invalid strings - treat as "normal" speed
17449 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
17450 return true;
17451 }
17452
17453 // Complete callback
17454 if ( $.isFunction( option ) ) {
17455 return true;
17456 }
17457
17458 // Options hash (but not naming an effect)
17459 if ( typeof option === "object" && !option.effect ) {
17460 return true;
17461 }
17462
17463 // Didn't match any standard API
17464 return false;
17465 }
17466
17467 $.fn.extend( {
17468 effect: function( /* effect, options, speed, callback */ ) {
17469 var args = _normalizeArguments.apply( this, arguments ),
17470 effectMethod = $.effects.effect[ args.effect ],
17471 defaultMode = effectMethod.mode,
17472 queue = args.queue,
17473 queueName = queue || "fx",
17474 complete = args.complete,
17475 mode = args.mode,
17476 modes = [],
17477 prefilter = function( next ) {
17478 var el = $( this ),
17479 normalizedMode = $.effects.mode( el, mode ) || defaultMode;
17480
17481 // Sentinel for duck-punching the :animated psuedo-selector
17482 el.data( dataSpaceAnimated, true );
17483
17484 // Save effect mode for later use,
17485 // we can't just call $.effects.mode again later,
17486 // as the .show() below destroys the initial state
17487 modes.push( normalizedMode );
17488
17489 // See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
17490 if ( defaultMode && ( normalizedMode === "show" ||
17491 ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
17492 el.show();
17493 }
17494
17495 if ( !defaultMode || normalizedMode !== "none" ) {
17496 $.effects.saveStyle( el );
17497 }
17498
17499 if ( $.isFunction( next ) ) {
17500 next();
17501 }
17502 };
17503
17504 if ( $.fx.off || !effectMethod ) {
17505
17506 // Delegate to the original method (e.g., .show()) if possible
17507 if ( mode ) {
17508 return this[ mode ]( args.duration, complete );
17509 } else {
17510 return this.each( function() {
17511 if ( complete ) {
17512 complete.call( this );
17513 }
17514 } );
17515 }
17516 }
17517
17518 function run( next ) {
17519 var elem = $( this );
17520
17521 function cleanup() {
17522 elem.removeData( dataSpaceAnimated );
17523
17524 $.effects.cleanUp( elem );
17525
17526 if ( args.mode === "hide" ) {
17527 elem.hide();
17528 }
17529
17530 done();
17531 }
17532
17533 function done() {
17534 if ( $.isFunction( complete ) ) {
17535 complete.call( elem[ 0 ] );
17536 }
17537
17538 if ( $.isFunction( next ) ) {
17539 next();
17540 }
17541 }
17542
17543 // Override mode option on a per element basis,
17544 // as toggle can be either show or hide depending on element state
17545 args.mode = modes.shift();
17546
17547 if ( $.uiBackCompat !== false && !defaultMode ) {
17548 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
17549
17550 // Call the core method to track "olddisplay" properly
17551 elem[ mode ]();
17552 done();
17553 } else {
17554 effectMethod.call( elem[ 0 ], args, done );
17555 }
17556 } else {
17557 if ( args.mode === "none" ) {
17558
17559 // Call the core method to track "olddisplay" properly
17560 elem[ mode ]();
17561 done();
17562 } else {
17563 effectMethod.call( elem[ 0 ], args, cleanup );
17564 }
17565 }
17566 }
17567
17568 // Run prefilter on all elements first to ensure that
17569 // any showing or hiding happens before placeholder creation,
17570 // which ensures that any layout changes are correctly captured.
17571 return queue === false ?
17572 this.each( prefilter ).each( run ) :
17573 this.queue( queueName, prefilter ).queue( queueName, run );
17574 },
17575
17576 show: ( function( orig ) {
17577 return function( option ) {
17578 if ( standardAnimationOption( option ) ) {
17579 return orig.apply( this, arguments );
17580 } else {
17581 var args = _normalizeArguments.apply( this, arguments );
17582 args.mode = "show";
17583 return this.effect.call( this, args );
17584 }
17585 };
17586 } )( $.fn.show ),
17587
17588 hide: ( function( orig ) {
17589 return function( option ) {
17590 if ( standardAnimationOption( option ) ) {
17591 return orig.apply( this, arguments );
17592 } else {
17593 var args = _normalizeArguments.apply( this, arguments );
17594 args.mode = "hide";
17595 return this.effect.call( this, args );
17596 }
17597 };
17598 } )( $.fn.hide ),
17599
17600 toggle: ( function( orig ) {
17601 return function( option ) {
17602 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
17603 return orig.apply( this, arguments );
17604 } else {
17605 var args = _normalizeArguments.apply( this, arguments );
17606 args.mode = "toggle";
17607 return this.effect.call( this, args );
17608 }
17609 };
17610 } )( $.fn.toggle ),
17611
17612 cssUnit: function( key ) {
17613 var style = this.css( key ),
17614 val = [];
17615
17616 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
17617 if ( style.indexOf( unit ) > 0 ) {
17618 val = [ parseFloat( style ), unit ];
17619 }
17620 } );
17621 return val;
17622 },
17623
17624 cssClip: function( clipObj ) {
17625 if ( clipObj ) {
17626 return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
17627 clipObj.bottom + "px " + clipObj.left + "px)" );
17628 }
17629 return parseClip( this.css( "clip" ), this );
17630 },
17631
17632 transfer: function( options, done ) {
17633 var element = $( this ),
17634 target = $( options.to ),
17635 targetFixed = target.css( "position" ) === "fixed",
17636 body = $( "body" ),
17637 fixTop = targetFixed ? body.scrollTop() : 0,
17638 fixLeft = targetFixed ? body.scrollLeft() : 0,
17639 endPosition = target.offset(),
17640 animation = {
17641 top: endPosition.top - fixTop,
17642 left: endPosition.left - fixLeft,
17643 height: target.innerHeight(),
17644 width: target.innerWidth()
17645 },
17646 startPosition = element.offset(),
17647 transfer = $( "<div class='ui-effects-transfer'></div>" )
17648 .appendTo( "body" )
17649 .addClass( options.className )
17650 .css( {
17651 top: startPosition.top - fixTop,
17652 left: startPosition.left - fixLeft,
17653 height: element.innerHeight(),
17654 width: element.innerWidth(),
17655 position: targetFixed ? "fixed" : "absolute"
17656 } )
17657 .animate( animation, options.duration, options.easing, function() {
17658 transfer.remove();
17659 if ( $.isFunction( done ) ) {
17660 done();
17661 }
17662 } );
17663 }
17664 } );
17665
17666 function parseClip( str, element ) {
17667 var outerWidth = element.outerWidth(),
17668 outerHeight = element.outerHeight(),
17669 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)\)$/,
17670 values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
17671
17672 return {
17673 top: parseFloat( values[ 1 ] ) || 0,
17674 right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
17675 bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
17676 left: parseFloat( values[ 4 ] ) || 0
17677 };
17678 }
17679
17680 $.fx.step.clip = function( fx ) {
17681 if ( !fx.clipInit ) {
17682 fx.start = $( fx.elem ).cssClip();
17683 if ( typeof fx.end === "string" ) {
17684 fx.end = parseClip( fx.end, fx.elem );
17685 }
17686 fx.clipInit = true;
17687 }
17688
17689 $( fx.elem ).cssClip( {
17690 top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
17691 right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
17692 bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
17693 left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
17694 } );
17695 };
17696
17697 } )();
17698
17699 /******************************************************************************/
17700 /*********************************** EASING ***********************************/
17701 /******************************************************************************/
17702
17703 ( function() {
17704
17705 // Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
17706
17707 var baseEasings = {};
17708
17709 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
17710 baseEasings[ name ] = function( p ) {
17711 return Math.pow( p, i + 2 );
17712 };
17713 } );
17714
17715 $.extend( baseEasings, {
17716 Sine: function( p ) {
17717 return 1 - Math.cos( p * Math.PI / 2 );
17718 },
17719 Circ: function( p ) {
17720 return 1 - Math.sqrt( 1 - p * p );
17721 },
17722 Elastic: function( p ) {
17723 return p === 0 || p === 1 ? p :
17724 -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
17725 },
17726 Back: function( p ) {
17727 return p * p * ( 3 * p - 2 );
17728 },
17729 Bounce: function( p ) {
17730 var pow2,
17731 bounce = 4;
17732
17733 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
17734 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
17735 }
17736 } );
17737
17738 $.each( baseEasings, function( name, easeIn ) {
17739 $.easing[ "easeIn" + name ] = easeIn;
17740 $.easing[ "easeOut" + name ] = function( p ) {
17741 return 1 - easeIn( 1 - p );
17742 };
17743 $.easing[ "easeInOut" + name ] = function( p ) {
17744 return p < 0.5 ?
17745 easeIn( p * 2 ) / 2 :
17746 1 - easeIn( p * -2 + 2 ) / 2;
17747 };
17748 } );
17749
17750 } )();
17751
17752 var effect = $.effects;
17753
17754
17755 /*!
17756 * jQuery UI Effects Blind 1.12.1
17757 * http://jqueryui.com
17758 *
17759 * Copyright jQuery Foundation and other contributors
17760 * Released under the MIT license.
17761 * http://jquery.org/license
17762 */
17763
17764 //>>label: Blind Effect
17765 //>>group: Effects
17766 //>>description: Blinds the element.
17767 //>>docs: http://api.jqueryui.com/blind-effect/
17768 //>>demos: http://jqueryui.com/effect/
17769
17770
17771
17772 var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
17773 var map = {
17774 up: [ "bottom", "top" ],
17775 vertical: [ "bottom", "top" ],
17776 down: [ "top", "bottom" ],
17777 left: [ "right", "left" ],
17778 horizontal: [ "right", "left" ],
17779 right: [ "left", "right" ]
17780 },
17781 element = $( this ),
17782 direction = options.direction || "up",
17783 start = element.cssClip(),
17784 animate = { clip: $.extend( {}, start ) },
17785 placeholder = $.effects.createPlaceholder( element );
17786
17787 animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
17788
17789 if ( options.mode === "show" ) {
17790 element.cssClip( animate.clip );
17791 if ( placeholder ) {
17792 placeholder.css( $.effects.clipToBox( animate ) );
17793 }
17794
17795 animate.clip = start;
17796 }
17797
17798 if ( placeholder ) {
17799 placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
17800 }
17801
17802 element.animate( animate, {
17803 queue: false,
17804 duration: options.duration,
17805 easing: options.easing,
17806 complete: done
17807 } );
17808 } );
17809
17810
17811 /*!
17812 * jQuery UI Effects Bounce 1.12.1
17813 * http://jqueryui.com
17814 *
17815 * Copyright jQuery Foundation and other contributors
17816 * Released under the MIT license.
17817 * http://jquery.org/license
17818 */
17819
17820 //>>label: Bounce Effect
17821 //>>group: Effects
17822 //>>description: Bounces an element horizontally or vertically n times.
17823 //>>docs: http://api.jqueryui.com/bounce-effect/
17824 //>>demos: http://jqueryui.com/effect/
17825
17826
17827
17828 var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
17829 var upAnim, downAnim, refValue,
17830 element = $( this ),
17831
17832 // Defaults:
17833 mode = options.mode,
17834 hide = mode === "hide",
17835 show = mode === "show",
17836 direction = options.direction || "up",
17837 distance = options.distance,
17838 times = options.times || 5,
17839
17840 // Number of internal animations
17841 anims = times * 2 + ( show || hide ? 1 : 0 ),
17842 speed = options.duration / anims,
17843 easing = options.easing,
17844
17845 // Utility:
17846 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
17847 motion = ( direction === "up" || direction === "left" ),
17848 i = 0,
17849
17850 queuelen = element.queue().length;
17851
17852 $.effects.createPlaceholder( element );
17853
17854 refValue = element.css( ref );
17855
17856 // Default distance for the BIGGEST bounce is the outer Distance / 3
17857 if ( !distance ) {
17858 distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
17859 }
17860
17861 if ( show ) {
17862 downAnim = { opacity: 1 };
17863 downAnim[ ref ] = refValue;
17864
17865 // If we are showing, force opacity 0 and set the initial position
17866 // then do the "first" animation
17867 element
17868 .css( "opacity", 0 )
17869 .css( ref, motion ? -distance * 2 : distance * 2 )
17870 .animate( downAnim, speed, easing );
17871 }
17872
17873 // Start at the smallest distance if we are hiding
17874 if ( hide ) {
17875 distance = distance / Math.pow( 2, times - 1 );
17876 }
17877
17878 downAnim = {};
17879 downAnim[ ref ] = refValue;
17880
17881 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
17882 for ( ; i < times; i++ ) {
17883 upAnim = {};
17884 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
17885
17886 element
17887 .animate( upAnim, speed, easing )
17888 .animate( downAnim, speed, easing );
17889
17890 distance = hide ? distance * 2 : distance / 2;
17891 }
17892
17893 // Last Bounce when Hiding
17894 if ( hide ) {
17895 upAnim = { opacity: 0 };
17896 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
17897
17898 element.animate( upAnim, speed, easing );
17899 }
17900
17901 element.queue( done );
17902
17903 $.effects.unshift( element, queuelen, anims + 1 );
17904 } );
17905
17906
17907 /*!
17908 * jQuery UI Effects Clip 1.12.1
17909 * http://jqueryui.com
17910 *
17911 * Copyright jQuery Foundation and other contributors
17912 * Released under the MIT license.
17913 * http://jquery.org/license
17914 */
17915
17916 //>>label: Clip Effect
17917 //>>group: Effects
17918 //>>description: Clips the element on and off like an old TV.
17919 //>>docs: http://api.jqueryui.com/clip-effect/
17920 //>>demos: http://jqueryui.com/effect/
17921
17922
17923
17924 var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
17925 var start,
17926 animate = {},
17927 element = $( this ),
17928 direction = options.direction || "vertical",
17929 both = direction === "both",
17930 horizontal = both || direction === "horizontal",
17931 vertical = both || direction === "vertical";
17932
17933 start = element.cssClip();
17934 animate.clip = {
17935 top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
17936 right: horizontal ? ( start.right - start.left ) / 2 : start.right,
17937 bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
17938 left: horizontal ? ( start.right - start.left ) / 2 : start.left
17939 };
17940
17941 $.effects.createPlaceholder( element );
17942
17943 if ( options.mode === "show" ) {
17944 element.cssClip( animate.clip );
17945 animate.clip = start;
17946 }
17947
17948 element.animate( animate, {
17949 queue: false,
17950 duration: options.duration,
17951 easing: options.easing,
17952 complete: done
17953 } );
17954
17955 } );
17956
17957
17958 /*!
17959 * jQuery UI Effects Drop 1.12.1
17960 * http://jqueryui.com
17961 *
17962 * Copyright jQuery Foundation and other contributors
17963 * Released under the MIT license.
17964 * http://jquery.org/license
17965 */
17966
17967 //>>label: Drop Effect
17968 //>>group: Effects
17969 //>>description: Moves an element in one direction and hides it at the same time.
17970 //>>docs: http://api.jqueryui.com/drop-effect/
17971 //>>demos: http://jqueryui.com/effect/
17972
17973
17974
17975 var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
17976
17977 var distance,
17978 element = $( this ),
17979 mode = options.mode,
17980 show = mode === "show",
17981 direction = options.direction || "left",
17982 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
17983 motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
17984 oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
17985 animation = {
17986 opacity: 0
17987 };
17988
17989 $.effects.createPlaceholder( element );
17990
17991 distance = options.distance ||
17992 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
17993
17994 animation[ ref ] = motion + distance;
17995
17996 if ( show ) {
17997 element.css( animation );
17998
17999 animation[ ref ] = oppositeMotion + distance;
18000 animation.opacity = 1;
18001 }
18002
18003 // Animate
18004 element.animate( animation, {
18005 queue: false,
18006 duration: options.duration,
18007 easing: options.easing,
18008 complete: done
18009 } );
18010 } );
18011
18012
18013 /*!
18014 * jQuery UI Effects Explode 1.12.1
18015 * http://jqueryui.com
18016 *
18017 * Copyright jQuery Foundation and other contributors
18018 * Released under the MIT license.
18019 * http://jquery.org/license
18020 */
18021
18022 //>>label: Explode Effect
18023 //>>group: Effects
18024 // jscs:disable maximumLineLength
18025 //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
18026 // jscs:enable maximumLineLength
18027 //>>docs: http://api.jqueryui.com/explode-effect/
18028 //>>demos: http://jqueryui.com/effect/
18029
18030
18031
18032 var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
18033
18034 var i, j, left, top, mx, my,
18035 rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
18036 cells = rows,
18037 element = $( this ),
18038 mode = options.mode,
18039 show = mode === "show",
18040
18041 // Show and then visibility:hidden the element before calculating offset
18042 offset = element.show().css( "visibility", "hidden" ).offset(),
18043
18044 // Width and height of a piece
18045 width = Math.ceil( element.outerWidth() / cells ),
18046 height = Math.ceil( element.outerHeight() / rows ),
18047 pieces = [];
18048
18049 // Children animate complete:
18050 function childComplete() {
18051 pieces.push( this );
18052 if ( pieces.length === rows * cells ) {
18053 animComplete();
18054 }
18055 }
18056
18057 // Clone the element for each row and cell.
18058 for ( i = 0; i < rows; i++ ) { // ===>
18059 top = offset.top + i * height;
18060 my = i - ( rows - 1 ) / 2;
18061
18062 for ( j = 0; j < cells; j++ ) { // |||
18063 left = offset.left + j * width;
18064 mx = j - ( cells - 1 ) / 2;
18065
18066 // Create a clone of the now hidden main element that will be absolute positioned
18067 // within a wrapper div off the -left and -top equal to size of our pieces
18068 element
18069 .clone()
18070 .appendTo( "body" )
18071 .wrap( "<div></div>" )
18072 .css( {
18073 position: "absolute",
18074 visibility: "visible",
18075 left: -j * width,
18076 top: -i * height
18077 } )
18078
18079 // Select the wrapper - make it overflow: hidden and absolute positioned based on
18080 // where the original was located +left and +top equal to the size of pieces
18081 .parent()
18082 .addClass( "ui-effects-explode" )
18083 .css( {
18084 position: "absolute",
18085 overflow: "hidden",
18086 width: width,
18087 height: height,
18088 left: left + ( show ? mx * width : 0 ),
18089 top: top + ( show ? my * height : 0 ),
18090 opacity: show ? 0 : 1
18091 } )
18092 .animate( {
18093 left: left + ( show ? 0 : mx * width ),
18094 top: top + ( show ? 0 : my * height ),
18095 opacity: show ? 1 : 0
18096 }, options.duration || 500, options.easing, childComplete );
18097 }
18098 }
18099
18100 function animComplete() {
18101 element.css( {
18102 visibility: "visible"
18103 } );
18104 $( pieces ).remove();
18105 done();
18106 }
18107 } );
18108
18109
18110 /*!
18111 * jQuery UI Effects Fade 1.12.1
18112 * http://jqueryui.com
18113 *
18114 * Copyright jQuery Foundation and other contributors
18115 * Released under the MIT license.
18116 * http://jquery.org/license
18117 */
18118
18119 //>>label: Fade Effect
18120 //>>group: Effects
18121 //>>description: Fades the element.
18122 //>>docs: http://api.jqueryui.com/fade-effect/
18123 //>>demos: http://jqueryui.com/effect/
18124
18125
18126
18127 var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
18128 var show = options.mode === "show";
18129
18130 $( this )
18131 .css( "opacity", show ? 0 : 1 )
18132 .animate( {
18133 opacity: show ? 1 : 0
18134 }, {
18135 queue: false,
18136 duration: options.duration,
18137 easing: options.easing,
18138 complete: done
18139 } );
18140 } );
18141
18142
18143 /*!
18144 * jQuery UI Effects Fold 1.12.1
18145 * http://jqueryui.com
18146 *
18147 * Copyright jQuery Foundation and other contributors
18148 * Released under the MIT license.
18149 * http://jquery.org/license
18150 */
18151
18152 //>>label: Fold Effect
18153 //>>group: Effects
18154 //>>description: Folds an element first horizontally and then vertically.
18155 //>>docs: http://api.jqueryui.com/fold-effect/
18156 //>>demos: http://jqueryui.com/effect/
18157
18158
18159
18160 var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
18161
18162 // Create element
18163 var element = $( this ),
18164 mode = options.mode,
18165 show = mode === "show",
18166 hide = mode === "hide",
18167 size = options.size || 15,
18168 percent = /([0-9]+)%/.exec( size ),
18169 horizFirst = !!options.horizFirst,
18170 ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
18171 duration = options.duration / 2,
18172
18173 placeholder = $.effects.createPlaceholder( element ),
18174
18175 start = element.cssClip(),
18176 animation1 = { clip: $.extend( {}, start ) },
18177 animation2 = { clip: $.extend( {}, start ) },
18178
18179 distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
18180
18181 queuelen = element.queue().length;
18182
18183 if ( percent ) {
18184 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
18185 }
18186 animation1.clip[ ref[ 0 ] ] = size;
18187 animation2.clip[ ref[ 0 ] ] = size;
18188 animation2.clip[ ref[ 1 ] ] = 0;
18189
18190 if ( show ) {
18191 element.cssClip( animation2.clip );
18192 if ( placeholder ) {
18193 placeholder.css( $.effects.clipToBox( animation2 ) );
18194 }
18195
18196 animation2.clip = start;
18197 }
18198
18199 // Animate
18200 element
18201 .queue( function( next ) {
18202 if ( placeholder ) {
18203 placeholder
18204 .animate( $.effects.clipToBox( animation1 ), duration, options.easing )
18205 .animate( $.effects.clipToBox( animation2 ), duration, options.easing );
18206 }
18207
18208 next();
18209 } )
18210 .animate( animation1, duration, options.easing )
18211 .animate( animation2, duration, options.easing )
18212 .queue( done );
18213
18214 $.effects.unshift( element, queuelen, 4 );
18215 } );
18216
18217
18218 /*!
18219 * jQuery UI Effects Highlight 1.12.1
18220 * http://jqueryui.com
18221 *
18222 * Copyright jQuery Foundation and other contributors
18223 * Released under the MIT license.
18224 * http://jquery.org/license
18225 */
18226
18227 //>>label: Highlight Effect
18228 //>>group: Effects
18229 //>>description: Highlights the background of an element in a defined color for a custom duration.
18230 //>>docs: http://api.jqueryui.com/highlight-effect/
18231 //>>demos: http://jqueryui.com/effect/
18232
18233
18234
18235 var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
18236 var element = $( this ),
18237 animation = {
18238 backgroundColor: element.css( "backgroundColor" )
18239 };
18240
18241 if ( options.mode === "hide" ) {
18242 animation.opacity = 0;
18243 }
18244
18245 $.effects.saveStyle( element );
18246
18247 element
18248 .css( {
18249 backgroundImage: "none",
18250 backgroundColor: options.color || "#ffff99"
18251 } )
18252 .animate( animation, {
18253 queue: false,
18254 duration: options.duration,
18255 easing: options.easing,
18256 complete: done
18257 } );
18258 } );
18259
18260
18261 /*!
18262 * jQuery UI Effects Size 1.12.1
18263 * http://jqueryui.com
18264 *
18265 * Copyright jQuery Foundation and other contributors
18266 * Released under the MIT license.
18267 * http://jquery.org/license
18268 */
18269
18270 //>>label: Size Effect
18271 //>>group: Effects
18272 //>>description: Resize an element to a specified width and height.
18273 //>>docs: http://api.jqueryui.com/size-effect/
18274 //>>demos: http://jqueryui.com/effect/
18275
18276
18277
18278 var effectsEffectSize = $.effects.define( "size", function( options, done ) {
18279
18280 // Create element
18281 var baseline, factor, temp,
18282 element = $( this ),
18283
18284 // Copy for children
18285 cProps = [ "fontSize" ],
18286 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
18287 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
18288
18289 // Set options
18290 mode = options.mode,
18291 restore = mode !== "effect",
18292 scale = options.scale || "both",
18293 origin = options.origin || [ "middle", "center" ],
18294 position = element.css( "position" ),
18295 pos = element.position(),
18296 original = $.effects.scaledDimensions( element ),
18297 from = options.from || original,
18298 to = options.to || $.effects.scaledDimensions( element, 0 );
18299
18300 $.effects.createPlaceholder( element );
18301
18302 if ( mode === "show" ) {
18303 temp = from;
18304 from = to;
18305 to = temp;
18306 }
18307
18308 // Set scaling factor
18309 factor = {
18310 from: {
18311 y: from.height / original.height,
18312 x: from.width / original.width
18313 },
18314 to: {
18315 y: to.height / original.height,
18316 x: to.width / original.width
18317 }
18318 };
18319
18320 // Scale the css box
18321 if ( scale === "box" || scale === "both" ) {
18322
18323 // Vertical props scaling
18324 if ( factor.from.y !== factor.to.y ) {
18325 from = $.effects.setTransition( element, vProps, factor.from.y, from );
18326 to = $.effects.setTransition( element, vProps, factor.to.y, to );
18327 }
18328
18329 // Horizontal props scaling
18330 if ( factor.from.x !== factor.to.x ) {
18331 from = $.effects.setTransition( element, hProps, factor.from.x, from );
18332 to = $.effects.setTransition( element, hProps, factor.to.x, to );
18333 }
18334 }
18335
18336 // Scale the content
18337 if ( scale === "content" || scale === "both" ) {
18338
18339 // Vertical props scaling
18340 if ( factor.from.y !== factor.to.y ) {
18341 from = $.effects.setTransition( element, cProps, factor.from.y, from );
18342 to = $.effects.setTransition( element, cProps, factor.to.y, to );
18343 }
18344 }
18345
18346 // Adjust the position properties based on the provided origin points
18347 if ( origin ) {
18348 baseline = $.effects.getBaseline( origin, original );
18349 from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
18350 from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
18351 to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
18352 to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
18353 }
18354 element.css( from );
18355
18356 // Animate the children if desired
18357 if ( scale === "content" || scale === "both" ) {
18358
18359 vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
18360 hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
18361
18362 // Only animate children with width attributes specified
18363 // TODO: is this right? should we include anything with css width specified as well
18364 element.find( "*[width]" ).each( function() {
18365 var child = $( this ),
18366 childOriginal = $.effects.scaledDimensions( child ),
18367 childFrom = {
18368 height: childOriginal.height * factor.from.y,
18369 width: childOriginal.width * factor.from.x,
18370 outerHeight: childOriginal.outerHeight * factor.from.y,
18371 outerWidth: childOriginal.outerWidth * factor.from.x
18372 },
18373 childTo = {
18374 height: childOriginal.height * factor.to.y,
18375 width: childOriginal.width * factor.to.x,
18376 outerHeight: childOriginal.height * factor.to.y,
18377 outerWidth: childOriginal.width * factor.to.x
18378 };
18379
18380 // Vertical props scaling
18381 if ( factor.from.y !== factor.to.y ) {
18382 childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
18383 childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
18384 }
18385
18386 // Horizontal props scaling
18387 if ( factor.from.x !== factor.to.x ) {
18388 childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
18389 childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
18390 }
18391
18392 if ( restore ) {
18393 $.effects.saveStyle( child );
18394 }
18395
18396 // Animate children
18397 child.css( childFrom );
18398 child.animate( childTo, options.duration, options.easing, function() {
18399
18400 // Restore children
18401 if ( restore ) {
18402 $.effects.restoreStyle( child );
18403 }
18404 } );
18405 } );
18406 }
18407
18408 // Animate
18409 element.animate( to, {
18410 queue: false,
18411 duration: options.duration,
18412 easing: options.easing,
18413 complete: function() {
18414
18415 var offset = element.offset();
18416
18417 if ( to.opacity === 0 ) {
18418 element.css( "opacity", from.opacity );
18419 }
18420
18421 if ( !restore ) {
18422 element
18423 .css( "position", position === "static" ? "relative" : position )
18424 .offset( offset );
18425
18426 // Need to save style here so that automatic style restoration
18427 // doesn't restore to the original styles from before the animation.
18428 $.effects.saveStyle( element );
18429 }
18430
18431 done();
18432 }
18433 } );
18434
18435 } );
18436
18437
18438 /*!
18439 * jQuery UI Effects Scale 1.12.1
18440 * http://jqueryui.com
18441 *
18442 * Copyright jQuery Foundation and other contributors
18443 * Released under the MIT license.
18444 * http://jquery.org/license
18445 */
18446
18447 //>>label: Scale Effect
18448 //>>group: Effects
18449 //>>description: Grows or shrinks an element and its content.
18450 //>>docs: http://api.jqueryui.com/scale-effect/
18451 //>>demos: http://jqueryui.com/effect/
18452
18453
18454
18455 var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
18456
18457 // Create element
18458 var el = $( this ),
18459 mode = options.mode,
18460 percent = parseInt( options.percent, 10 ) ||
18461 ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
18462
18463 newOptions = $.extend( true, {
18464 from: $.effects.scaledDimensions( el ),
18465 to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
18466 origin: options.origin || [ "middle", "center" ]
18467 }, options );
18468
18469 // Fade option to support puff
18470 if ( options.fade ) {
18471 newOptions.from.opacity = 1;
18472 newOptions.to.opacity = 0;
18473 }
18474
18475 $.effects.effect.size.call( this, newOptions, done );
18476 } );
18477
18478
18479 /*!
18480 * jQuery UI Effects Puff 1.12.1
18481 * http://jqueryui.com
18482 *
18483 * Copyright jQuery Foundation and other contributors
18484 * Released under the MIT license.
18485 * http://jquery.org/license
18486 */
18487
18488 //>>label: Puff Effect
18489 //>>group: Effects
18490 //>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
18491 //>>docs: http://api.jqueryui.com/puff-effect/
18492 //>>demos: http://jqueryui.com/effect/
18493
18494
18495
18496 var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
18497 var newOptions = $.extend( true, {}, options, {
18498 fade: true,
18499 percent: parseInt( options.percent, 10 ) || 150
18500 } );
18501
18502 $.effects.effect.scale.call( this, newOptions, done );
18503 } );
18504
18505
18506 /*!
18507 * jQuery UI Effects Pulsate 1.12.1
18508 * http://jqueryui.com
18509 *
18510 * Copyright jQuery Foundation and other contributors
18511 * Released under the MIT license.
18512 * http://jquery.org/license
18513 */
18514
18515 //>>label: Pulsate Effect
18516 //>>group: Effects
18517 //>>description: Pulsates an element n times by changing the opacity to zero and back.
18518 //>>docs: http://api.jqueryui.com/pulsate-effect/
18519 //>>demos: http://jqueryui.com/effect/
18520
18521
18522
18523 var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
18524 var element = $( this ),
18525 mode = options.mode,
18526 show = mode === "show",
18527 hide = mode === "hide",
18528 showhide = show || hide,
18529
18530 // Showing or hiding leaves off the "last" animation
18531 anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
18532 duration = options.duration / anims,
18533 animateTo = 0,
18534 i = 1,
18535 queuelen = element.queue().length;
18536
18537 if ( show || !element.is( ":visible" ) ) {
18538 element.css( "opacity", 0 ).show();
18539 animateTo = 1;
18540 }
18541
18542 // Anims - 1 opacity "toggles"
18543 for ( ; i < anims; i++ ) {
18544 element.animate( { opacity: animateTo }, duration, options.easing );
18545 animateTo = 1 - animateTo;
18546 }
18547
18548 element.animate( { opacity: animateTo }, duration, options.easing );
18549
18550 element.queue( done );
18551
18552 $.effects.unshift( element, queuelen, anims + 1 );
18553 } );
18554
18555
18556 /*!
18557 * jQuery UI Effects Shake 1.12.1
18558 * http://jqueryui.com
18559 *
18560 * Copyright jQuery Foundation and other contributors
18561 * Released under the MIT license.
18562 * http://jquery.org/license
18563 */
18564
18565 //>>label: Shake Effect
18566 //>>group: Effects
18567 //>>description: Shakes an element horizontally or vertically n times.
18568 //>>docs: http://api.jqueryui.com/shake-effect/
18569 //>>demos: http://jqueryui.com/effect/
18570
18571
18572
18573 var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
18574
18575 var i = 1,
18576 element = $( this ),
18577 direction = options.direction || "left",
18578 distance = options.distance || 20,
18579 times = options.times || 3,
18580 anims = times * 2 + 1,
18581 speed = Math.round( options.duration / anims ),
18582 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
18583 positiveMotion = ( direction === "up" || direction === "left" ),
18584 animation = {},
18585 animation1 = {},
18586 animation2 = {},
18587
18588 queuelen = element.queue().length;
18589
18590 $.effects.createPlaceholder( element );
18591
18592 // Animation
18593 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
18594 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
18595 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
18596
18597 // Animate
18598 element.animate( animation, speed, options.easing );
18599
18600 // Shakes
18601 for ( ; i < times; i++ ) {
18602 element
18603 .animate( animation1, speed, options.easing )
18604 .animate( animation2, speed, options.easing );
18605 }
18606
18607 element
18608 .animate( animation1, speed, options.easing )
18609 .animate( animation, speed / 2, options.easing )
18610 .queue( done );
18611
18612 $.effects.unshift( element, queuelen, anims + 1 );
18613 } );
18614
18615
18616 /*!
18617 * jQuery UI Effects Slide 1.12.1
18618 * http://jqueryui.com
18619 *
18620 * Copyright jQuery Foundation and other contributors
18621 * Released under the MIT license.
18622 * http://jquery.org/license
18623 */
18624
18625 //>>label: Slide Effect
18626 //>>group: Effects
18627 //>>description: Slides an element in and out of the viewport.
18628 //>>docs: http://api.jqueryui.com/slide-effect/
18629 //>>demos: http://jqueryui.com/effect/
18630
18631
18632
18633 var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
18634 var startClip, startRef,
18635 element = $( this ),
18636 map = {
18637 up: [ "bottom", "top" ],
18638 down: [ "top", "bottom" ],
18639 left: [ "right", "left" ],
18640 right: [ "left", "right" ]
18641 },
18642 mode = options.mode,
18643 direction = options.direction || "left",
18644 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
18645 positiveMotion = ( direction === "up" || direction === "left" ),
18646 distance = options.distance ||
18647 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
18648 animation = {};
18649
18650 $.effects.createPlaceholder( element );
18651
18652 startClip = element.cssClip();
18653 startRef = element.position()[ ref ];
18654
18655 // Define hide animation
18656 animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
18657 animation.clip = element.cssClip();
18658 animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
18659
18660 // Reverse the animation if we're showing
18661 if ( mode === "show" ) {
18662 element.cssClip( animation.clip );
18663 element.css( ref, animation[ ref ] );
18664 animation.clip = startClip;
18665 animation[ ref ] = startRef;
18666 }
18667
18668 // Actually animate
18669 element.animate( animation, {
18670 queue: false,
18671 duration: options.duration,
18672 easing: options.easing,
18673 complete: done
18674 } );
18675 } );
18676
18677
18678 /*!
18679 * jQuery UI Effects Transfer 1.12.1
18680 * http://jqueryui.com
18681 *
18682 * Copyright jQuery Foundation and other contributors
18683 * Released under the MIT license.
18684 * http://jquery.org/license
18685 */
18686
18687 //>>label: Transfer Effect
18688 //>>group: Effects
18689 //>>description: Displays a transfer effect from one element to another.
18690 //>>docs: http://api.jqueryui.com/transfer-effect/
18691 //>>demos: http://jqueryui.com/effect/
18692
18693
18694
18695 var effect;
18696 if ( $.uiBackCompat !== false ) {
18697 effect = $.effects.define( "transfer", function( options, done ) {
18698 $( this ).transfer( options, done );
18699 } );
18700 }
18701 var effectsEffectTransfer = effect;
18702
18703
18704
18705
18706 }));