[SPIP] v3.2.12 -> v3.2.12 - Reinstallation avec le spip_loader
[lhc/web/www.git] / www / plugins-dist / jquery_ui / prive / javascript / ui / jquery-ui.js
1 /*! jQuery UI - v1.12.1 - 2016-09-14
2 * http://jqueryui.com
3 * Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
4 * Copyright jQuery Foundation and other contributors; Licensed MIT */
5
6 (function( factory ) {
7 if ( typeof define === "function" && define.amd ) {
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 Effects 1.12.1
1301 * http://jqueryui.com
1302 *
1303 * Copyright jQuery Foundation and other contributors
1304 * Released under the MIT license.
1305 * http://jquery.org/license
1306 */
1307
1308 //>>label: Effects Core
1309 //>>group: Effects
1310 // jscs:disable maximumLineLength
1311 //>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
1312 // jscs:enable maximumLineLength
1313 //>>docs: http://api.jqueryui.com/category/effects-core/
1314 //>>demos: http://jqueryui.com/effect/
1315
1316
1317
1318 var dataSpace = "ui-effects-",
1319 dataSpaceStyle = "ui-effects-style",
1320 dataSpaceAnimated = "ui-effects-animated",
1321
1322 // Create a local jQuery because jQuery Color relies on it and the
1323 // global may not exist with AMD and a custom build (#10199)
1324 jQuery = $;
1325
1326 $.effects = {
1327 effect: {}
1328 };
1329
1330 /*!
1331 * jQuery Color Animations v2.1.2
1332 * https://github.com/jquery/jquery-color
1333 *
1334 * Copyright 2014 jQuery Foundation and other contributors
1335 * Released under the MIT license.
1336 * http://jquery.org/license
1337 *
1338 * Date: Wed Jan 16 08:47:09 2013 -0600
1339 */
1340 ( function( jQuery, undefined ) {
1341
1342 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
1343 "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
1344
1345 // Plusequals test for += 100 -= 100
1346 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
1347
1348 // A set of RE's that can match strings and generate color tuples.
1349 stringParsers = [ {
1350 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1351 parse: function( execResult ) {
1352 return [
1353 execResult[ 1 ],
1354 execResult[ 2 ],
1355 execResult[ 3 ],
1356 execResult[ 4 ]
1357 ];
1358 }
1359 }, {
1360 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1361 parse: function( execResult ) {
1362 return [
1363 execResult[ 1 ] * 2.55,
1364 execResult[ 2 ] * 2.55,
1365 execResult[ 3 ] * 2.55,
1366 execResult[ 4 ]
1367 ];
1368 }
1369 }, {
1370
1371 // This regex ignores A-F because it's compared against an already lowercased string
1372 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
1373 parse: function( execResult ) {
1374 return [
1375 parseInt( execResult[ 1 ], 16 ),
1376 parseInt( execResult[ 2 ], 16 ),
1377 parseInt( execResult[ 3 ], 16 )
1378 ];
1379 }
1380 }, {
1381
1382 // This regex ignores A-F because it's compared against an already lowercased string
1383 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
1384 parse: function( execResult ) {
1385 return [
1386 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
1387 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
1388 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
1389 ];
1390 }
1391 }, {
1392 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
1393 space: "hsla",
1394 parse: function( execResult ) {
1395 return [
1396 execResult[ 1 ],
1397 execResult[ 2 ] / 100,
1398 execResult[ 3 ] / 100,
1399 execResult[ 4 ]
1400 ];
1401 }
1402 } ],
1403
1404 // JQuery.Color( )
1405 color = jQuery.Color = function( color, green, blue, alpha ) {
1406 return new jQuery.Color.fn.parse( color, green, blue, alpha );
1407 },
1408 spaces = {
1409 rgba: {
1410 props: {
1411 red: {
1412 idx: 0,
1413 type: "byte"
1414 },
1415 green: {
1416 idx: 1,
1417 type: "byte"
1418 },
1419 blue: {
1420 idx: 2,
1421 type: "byte"
1422 }
1423 }
1424 },
1425
1426 hsla: {
1427 props: {
1428 hue: {
1429 idx: 0,
1430 type: "degrees"
1431 },
1432 saturation: {
1433 idx: 1,
1434 type: "percent"
1435 },
1436 lightness: {
1437 idx: 2,
1438 type: "percent"
1439 }
1440 }
1441 }
1442 },
1443 propTypes = {
1444 "byte": {
1445 floor: true,
1446 max: 255
1447 },
1448 "percent": {
1449 max: 1
1450 },
1451 "degrees": {
1452 mod: 360,
1453 floor: true
1454 }
1455 },
1456 support = color.support = {},
1457
1458 // Element for support tests
1459 supportElem = jQuery( "<p>" )[ 0 ],
1460
1461 // Colors = jQuery.Color.names
1462 colors,
1463
1464 // Local aliases of functions called often
1465 each = jQuery.each;
1466
1467 // Determine rgba support immediately
1468 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
1469 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
1470
1471 // Define cache name and alpha properties
1472 // for rgba and hsla spaces
1473 each( spaces, function( spaceName, space ) {
1474 space.cache = "_" + spaceName;
1475 space.props.alpha = {
1476 idx: 3,
1477 type: "percent",
1478 def: 1
1479 };
1480 } );
1481
1482 function clamp( value, prop, allowEmpty ) {
1483 var type = propTypes[ prop.type ] || {};
1484
1485 if ( value == null ) {
1486 return ( allowEmpty || !prop.def ) ? null : prop.def;
1487 }
1488
1489 // ~~ is an short way of doing floor for positive numbers
1490 value = type.floor ? ~~value : parseFloat( value );
1491
1492 // IE will pass in empty strings as value for alpha,
1493 // which will hit this case
1494 if ( isNaN( value ) ) {
1495 return prop.def;
1496 }
1497
1498 if ( type.mod ) {
1499
1500 // We add mod before modding to make sure that negatives values
1501 // get converted properly: -10 -> 350
1502 return ( value + type.mod ) % type.mod;
1503 }
1504
1505 // For now all property types without mod have min and max
1506 return 0 > value ? 0 : type.max < value ? type.max : value;
1507 }
1508
1509 function stringParse( string ) {
1510 var inst = color(),
1511 rgba = inst._rgba = [];
1512
1513 string = string.toLowerCase();
1514
1515 each( stringParsers, function( i, parser ) {
1516 var parsed,
1517 match = parser.re.exec( string ),
1518 values = match && parser.parse( match ),
1519 spaceName = parser.space || "rgba";
1520
1521 if ( values ) {
1522 parsed = inst[ spaceName ]( values );
1523
1524 // If this was an rgba parse the assignment might happen twice
1525 // oh well....
1526 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
1527 rgba = inst._rgba = parsed._rgba;
1528
1529 // Exit each( stringParsers ) here because we matched
1530 return false;
1531 }
1532 } );
1533
1534 // Found a stringParser that handled it
1535 if ( rgba.length ) {
1536
1537 // If this came from a parsed string, force "transparent" when alpha is 0
1538 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
1539 if ( rgba.join() === "0,0,0,0" ) {
1540 jQuery.extend( rgba, colors.transparent );
1541 }
1542 return inst;
1543 }
1544
1545 // Named colors
1546 return colors[ string ];
1547 }
1548
1549 color.fn = jQuery.extend( color.prototype, {
1550 parse: function( red, green, blue, alpha ) {
1551 if ( red === undefined ) {
1552 this._rgba = [ null, null, null, null ];
1553 return this;
1554 }
1555 if ( red.jquery || red.nodeType ) {
1556 red = jQuery( red ).css( green );
1557 green = undefined;
1558 }
1559
1560 var inst = this,
1561 type = jQuery.type( red ),
1562 rgba = this._rgba = [];
1563
1564 // More than 1 argument specified - assume ( red, green, blue, alpha )
1565 if ( green !== undefined ) {
1566 red = [ red, green, blue, alpha ];
1567 type = "array";
1568 }
1569
1570 if ( type === "string" ) {
1571 return this.parse( stringParse( red ) || colors._default );
1572 }
1573
1574 if ( type === "array" ) {
1575 each( spaces.rgba.props, function( key, prop ) {
1576 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
1577 } );
1578 return this;
1579 }
1580
1581 if ( type === "object" ) {
1582 if ( red instanceof color ) {
1583 each( spaces, function( spaceName, space ) {
1584 if ( red[ space.cache ] ) {
1585 inst[ space.cache ] = red[ space.cache ].slice();
1586 }
1587 } );
1588 } else {
1589 each( spaces, function( spaceName, space ) {
1590 var cache = space.cache;
1591 each( space.props, function( key, prop ) {
1592
1593 // If the cache doesn't exist, and we know how to convert
1594 if ( !inst[ cache ] && space.to ) {
1595
1596 // If the value was null, we don't need to copy it
1597 // if the key was alpha, we don't need to copy it either
1598 if ( key === "alpha" || red[ key ] == null ) {
1599 return;
1600 }
1601 inst[ cache ] = space.to( inst._rgba );
1602 }
1603
1604 // This is the only case where we allow nulls for ALL properties.
1605 // call clamp with alwaysAllowEmpty
1606 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
1607 } );
1608
1609 // Everything defined but alpha?
1610 if ( inst[ cache ] &&
1611 jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
1612
1613 // Use the default of 1
1614 inst[ cache ][ 3 ] = 1;
1615 if ( space.from ) {
1616 inst._rgba = space.from( inst[ cache ] );
1617 }
1618 }
1619 } );
1620 }
1621 return this;
1622 }
1623 },
1624 is: function( compare ) {
1625 var is = color( compare ),
1626 same = true,
1627 inst = this;
1628
1629 each( spaces, function( _, space ) {
1630 var localCache,
1631 isCache = is[ space.cache ];
1632 if ( isCache ) {
1633 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
1634 each( space.props, function( _, prop ) {
1635 if ( isCache[ prop.idx ] != null ) {
1636 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
1637 return same;
1638 }
1639 } );
1640 }
1641 return same;
1642 } );
1643 return same;
1644 },
1645 _space: function() {
1646 var used = [],
1647 inst = this;
1648 each( spaces, function( spaceName, space ) {
1649 if ( inst[ space.cache ] ) {
1650 used.push( spaceName );
1651 }
1652 } );
1653 return used.pop();
1654 },
1655 transition: function( other, distance ) {
1656 var end = color( other ),
1657 spaceName = end._space(),
1658 space = spaces[ spaceName ],
1659 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
1660 start = startColor[ space.cache ] || space.to( startColor._rgba ),
1661 result = start.slice();
1662
1663 end = end[ space.cache ];
1664 each( space.props, function( key, prop ) {
1665 var index = prop.idx,
1666 startValue = start[ index ],
1667 endValue = end[ index ],
1668 type = propTypes[ prop.type ] || {};
1669
1670 // If null, don't override start value
1671 if ( endValue === null ) {
1672 return;
1673 }
1674
1675 // If null - use end
1676 if ( startValue === null ) {
1677 result[ index ] = endValue;
1678 } else {
1679 if ( type.mod ) {
1680 if ( endValue - startValue > type.mod / 2 ) {
1681 startValue += type.mod;
1682 } else if ( startValue - endValue > type.mod / 2 ) {
1683 startValue -= type.mod;
1684 }
1685 }
1686 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
1687 }
1688 } );
1689 return this[ spaceName ]( result );
1690 },
1691 blend: function( opaque ) {
1692
1693 // If we are already opaque - return ourself
1694 if ( this._rgba[ 3 ] === 1 ) {
1695 return this;
1696 }
1697
1698 var rgb = this._rgba.slice(),
1699 a = rgb.pop(),
1700 blend = color( opaque )._rgba;
1701
1702 return color( jQuery.map( rgb, function( v, i ) {
1703 return ( 1 - a ) * blend[ i ] + a * v;
1704 } ) );
1705 },
1706 toRgbaString: function() {
1707 var prefix = "rgba(",
1708 rgba = jQuery.map( this._rgba, function( v, i ) {
1709 return v == null ? ( i > 2 ? 1 : 0 ) : v;
1710 } );
1711
1712 if ( rgba[ 3 ] === 1 ) {
1713 rgba.pop();
1714 prefix = "rgb(";
1715 }
1716
1717 return prefix + rgba.join() + ")";
1718 },
1719 toHslaString: function() {
1720 var prefix = "hsla(",
1721 hsla = jQuery.map( this.hsla(), function( v, i ) {
1722 if ( v == null ) {
1723 v = i > 2 ? 1 : 0;
1724 }
1725
1726 // Catch 1 and 2
1727 if ( i && i < 3 ) {
1728 v = Math.round( v * 100 ) + "%";
1729 }
1730 return v;
1731 } );
1732
1733 if ( hsla[ 3 ] === 1 ) {
1734 hsla.pop();
1735 prefix = "hsl(";
1736 }
1737 return prefix + hsla.join() + ")";
1738 },
1739 toHexString: function( includeAlpha ) {
1740 var rgba = this._rgba.slice(),
1741 alpha = rgba.pop();
1742
1743 if ( includeAlpha ) {
1744 rgba.push( ~~( alpha * 255 ) );
1745 }
1746
1747 return "#" + jQuery.map( rgba, function( v ) {
1748
1749 // Default to 0 when nulls exist
1750 v = ( v || 0 ).toString( 16 );
1751 return v.length === 1 ? "0" + v : v;
1752 } ).join( "" );
1753 },
1754 toString: function() {
1755 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
1756 }
1757 } );
1758 color.fn.parse.prototype = color.fn;
1759
1760 // Hsla conversions adapted from:
1761 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
1762
1763 function hue2rgb( p, q, h ) {
1764 h = ( h + 1 ) % 1;
1765 if ( h * 6 < 1 ) {
1766 return p + ( q - p ) * h * 6;
1767 }
1768 if ( h * 2 < 1 ) {
1769 return q;
1770 }
1771 if ( h * 3 < 2 ) {
1772 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
1773 }
1774 return p;
1775 }
1776
1777 spaces.hsla.to = function( rgba ) {
1778 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
1779 return [ null, null, null, rgba[ 3 ] ];
1780 }
1781 var r = rgba[ 0 ] / 255,
1782 g = rgba[ 1 ] / 255,
1783 b = rgba[ 2 ] / 255,
1784 a = rgba[ 3 ],
1785 max = Math.max( r, g, b ),
1786 min = Math.min( r, g, b ),
1787 diff = max - min,
1788 add = max + min,
1789 l = add * 0.5,
1790 h, s;
1791
1792 if ( min === max ) {
1793 h = 0;
1794 } else if ( r === max ) {
1795 h = ( 60 * ( g - b ) / diff ) + 360;
1796 } else if ( g === max ) {
1797 h = ( 60 * ( b - r ) / diff ) + 120;
1798 } else {
1799 h = ( 60 * ( r - g ) / diff ) + 240;
1800 }
1801
1802 // Chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
1803 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
1804 if ( diff === 0 ) {
1805 s = 0;
1806 } else if ( l <= 0.5 ) {
1807 s = diff / add;
1808 } else {
1809 s = diff / ( 2 - add );
1810 }
1811 return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
1812 };
1813
1814 spaces.hsla.from = function( hsla ) {
1815 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
1816 return [ null, null, null, hsla[ 3 ] ];
1817 }
1818 var h = hsla[ 0 ] / 360,
1819 s = hsla[ 1 ],
1820 l = hsla[ 2 ],
1821 a = hsla[ 3 ],
1822 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
1823 p = 2 * l - q;
1824
1825 return [
1826 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
1827 Math.round( hue2rgb( p, q, h ) * 255 ),
1828 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
1829 a
1830 ];
1831 };
1832
1833 each( spaces, function( spaceName, space ) {
1834 var props = space.props,
1835 cache = space.cache,
1836 to = space.to,
1837 from = space.from;
1838
1839 // Makes rgba() and hsla()
1840 color.fn[ spaceName ] = function( value ) {
1841
1842 // Generate a cache for this space if it doesn't exist
1843 if ( to && !this[ cache ] ) {
1844 this[ cache ] = to( this._rgba );
1845 }
1846 if ( value === undefined ) {
1847 return this[ cache ].slice();
1848 }
1849
1850 var ret,
1851 type = jQuery.type( value ),
1852 arr = ( type === "array" || type === "object" ) ? value : arguments,
1853 local = this[ cache ].slice();
1854
1855 each( props, function( key, prop ) {
1856 var val = arr[ type === "object" ? key : prop.idx ];
1857 if ( val == null ) {
1858 val = local[ prop.idx ];
1859 }
1860 local[ prop.idx ] = clamp( val, prop );
1861 } );
1862
1863 if ( from ) {
1864 ret = color( from( local ) );
1865 ret[ cache ] = local;
1866 return ret;
1867 } else {
1868 return color( local );
1869 }
1870 };
1871
1872 // Makes red() green() blue() alpha() hue() saturation() lightness()
1873 each( props, function( key, prop ) {
1874
1875 // Alpha is included in more than one space
1876 if ( color.fn[ key ] ) {
1877 return;
1878 }
1879 color.fn[ key ] = function( value ) {
1880 var vtype = jQuery.type( value ),
1881 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
1882 local = this[ fn ](),
1883 cur = local[ prop.idx ],
1884 match;
1885
1886 if ( vtype === "undefined" ) {
1887 return cur;
1888 }
1889
1890 if ( vtype === "function" ) {
1891 value = value.call( this, cur );
1892 vtype = jQuery.type( value );
1893 }
1894 if ( value == null && prop.empty ) {
1895 return this;
1896 }
1897 if ( vtype === "string" ) {
1898 match = rplusequals.exec( value );
1899 if ( match ) {
1900 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
1901 }
1902 }
1903 local[ prop.idx ] = value;
1904 return this[ fn ]( local );
1905 };
1906 } );
1907 } );
1908
1909 // Add cssHook and .fx.step function for each named hook.
1910 // accept a space separated string of properties
1911 color.hook = function( hook ) {
1912 var hooks = hook.split( " " );
1913 each( hooks, function( i, hook ) {
1914 jQuery.cssHooks[ hook ] = {
1915 set: function( elem, value ) {
1916 var parsed, curElem,
1917 backgroundColor = "";
1918
1919 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" ||
1920 ( parsed = stringParse( value ) ) ) ) {
1921 value = color( parsed || value );
1922 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
1923 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
1924 while (
1925 ( backgroundColor === "" || backgroundColor === "transparent" ) &&
1926 curElem && curElem.style
1927 ) {
1928 try {
1929 backgroundColor = jQuery.css( curElem, "backgroundColor" );
1930 curElem = curElem.parentNode;
1931 } catch ( e ) {
1932 }
1933 }
1934
1935 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
1936 backgroundColor :
1937 "_default" );
1938 }
1939
1940 value = value.toRgbaString();
1941 }
1942 try {
1943 elem.style[ hook ] = value;
1944 } catch ( e ) {
1945
1946 // Wrapped to prevent IE from throwing errors on "invalid" values like
1947 // 'auto' or 'inherit'
1948 }
1949 }
1950 };
1951 jQuery.fx.step[ hook ] = function( fx ) {
1952 if ( !fx.colorInit ) {
1953 fx.start = color( fx.elem, hook );
1954 fx.end = color( fx.end );
1955 fx.colorInit = true;
1956 }
1957 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
1958 };
1959 } );
1960
1961 };
1962
1963 color.hook( stepHooks );
1964
1965 jQuery.cssHooks.borderColor = {
1966 expand: function( value ) {
1967 var expanded = {};
1968
1969 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
1970 expanded[ "border" + part + "Color" ] = value;
1971 } );
1972 return expanded;
1973 }
1974 };
1975
1976 // Basic color names only.
1977 // Usage of any of the other color names requires adding yourself or including
1978 // jquery.color.svg-names.js.
1979 colors = jQuery.Color.names = {
1980
1981 // 4.1. Basic color keywords
1982 aqua: "#00ffff",
1983 black: "#000000",
1984 blue: "#0000ff",
1985 fuchsia: "#ff00ff",
1986 gray: "#808080",
1987 green: "#008000",
1988 lime: "#00ff00",
1989 maroon: "#800000",
1990 navy: "#000080",
1991 olive: "#808000",
1992 purple: "#800080",
1993 red: "#ff0000",
1994 silver: "#c0c0c0",
1995 teal: "#008080",
1996 white: "#ffffff",
1997 yellow: "#ffff00",
1998
1999 // 4.2.3. "transparent" color keyword
2000 transparent: [ null, null, null, 0 ],
2001
2002 _default: "#ffffff"
2003 };
2004
2005 } )( jQuery );
2006
2007 /******************************************************************************/
2008 /****************************** CLASS ANIMATIONS ******************************/
2009 /******************************************************************************/
2010 ( function() {
2011
2012 var classAnimationActions = [ "add", "remove", "toggle" ],
2013 shorthandStyles = {
2014 border: 1,
2015 borderBottom: 1,
2016 borderColor: 1,
2017 borderLeft: 1,
2018 borderRight: 1,
2019 borderTop: 1,
2020 borderWidth: 1,
2021 margin: 1,
2022 padding: 1
2023 };
2024
2025 $.each(
2026 [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
2027 function( _, prop ) {
2028 $.fx.step[ prop ] = function( fx ) {
2029 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
2030 jQuery.style( fx.elem, prop, fx.end );
2031 fx.setAttr = true;
2032 }
2033 };
2034 }
2035 );
2036
2037 function getElementStyles( elem ) {
2038 var key, len,
2039 style = elem.ownerDocument.defaultView ?
2040 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
2041 elem.currentStyle,
2042 styles = {};
2043
2044 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
2045 len = style.length;
2046 while ( len-- ) {
2047 key = style[ len ];
2048 if ( typeof style[ key ] === "string" ) {
2049 styles[ $.camelCase( key ) ] = style[ key ];
2050 }
2051 }
2052
2053 // Support: Opera, IE <9
2054 } else {
2055 for ( key in style ) {
2056 if ( typeof style[ key ] === "string" ) {
2057 styles[ key ] = style[ key ];
2058 }
2059 }
2060 }
2061
2062 return styles;
2063 }
2064
2065 function styleDifference( oldStyle, newStyle ) {
2066 var diff = {},
2067 name, value;
2068
2069 for ( name in newStyle ) {
2070 value = newStyle[ name ];
2071 if ( oldStyle[ name ] !== value ) {
2072 if ( !shorthandStyles[ name ] ) {
2073 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
2074 diff[ name ] = value;
2075 }
2076 }
2077 }
2078 }
2079
2080 return diff;
2081 }
2082
2083 // Support: jQuery <1.8
2084 if ( !$.fn.addBack ) {
2085 $.fn.addBack = function( selector ) {
2086 return this.add( selector == null ?
2087 this.prevObject : this.prevObject.filter( selector )
2088 );
2089 };
2090 }
2091
2092 $.effects.animateClass = function( value, duration, easing, callback ) {
2093 var o = $.speed( duration, easing, callback );
2094
2095 return this.queue( function() {
2096 var animated = $( this ),
2097 baseClass = animated.attr( "class" ) || "",
2098 applyClassChange,
2099 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
2100
2101 // Map the animated objects to store the original styles.
2102 allAnimations = allAnimations.map( function() {
2103 var el = $( this );
2104 return {
2105 el: el,
2106 start: getElementStyles( this )
2107 };
2108 } );
2109
2110 // Apply class change
2111 applyClassChange = function() {
2112 $.each( classAnimationActions, function( i, action ) {
2113 if ( value[ action ] ) {
2114 animated[ action + "Class" ]( value[ action ] );
2115 }
2116 } );
2117 };
2118 applyClassChange();
2119
2120 // Map all animated objects again - calculate new styles and diff
2121 allAnimations = allAnimations.map( function() {
2122 this.end = getElementStyles( this.el[ 0 ] );
2123 this.diff = styleDifference( this.start, this.end );
2124 return this;
2125 } );
2126
2127 // Apply original class
2128 animated.attr( "class", baseClass );
2129
2130 // Map all animated objects again - this time collecting a promise
2131 allAnimations = allAnimations.map( function() {
2132 var styleInfo = this,
2133 dfd = $.Deferred(),
2134 opts = $.extend( {}, o, {
2135 queue: false,
2136 complete: function() {
2137 dfd.resolve( styleInfo );
2138 }
2139 } );
2140
2141 this.el.animate( this.diff, opts );
2142 return dfd.promise();
2143 } );
2144
2145 // Once all animations have completed:
2146 $.when.apply( $, allAnimations.get() ).done( function() {
2147
2148 // Set the final class
2149 applyClassChange();
2150
2151 // For each animated element,
2152 // clear all css properties that were animated
2153 $.each( arguments, function() {
2154 var el = this.el;
2155 $.each( this.diff, function( key ) {
2156 el.css( key, "" );
2157 } );
2158 } );
2159
2160 // This is guarnteed to be there if you use jQuery.speed()
2161 // it also handles dequeuing the next anim...
2162 o.complete.call( animated[ 0 ] );
2163 } );
2164 } );
2165 };
2166
2167 $.fn.extend( {
2168 addClass: ( function( orig ) {
2169 return function( classNames, speed, easing, callback ) {
2170 return speed ?
2171 $.effects.animateClass.call( this,
2172 { add: classNames }, speed, easing, callback ) :
2173 orig.apply( this, arguments );
2174 };
2175 } )( $.fn.addClass ),
2176
2177 removeClass: ( function( orig ) {
2178 return function( classNames, speed, easing, callback ) {
2179 return arguments.length > 1 ?
2180 $.effects.animateClass.call( this,
2181 { remove: classNames }, speed, easing, callback ) :
2182 orig.apply( this, arguments );
2183 };
2184 } )( $.fn.removeClass ),
2185
2186 toggleClass: ( function( orig ) {
2187 return function( classNames, force, speed, easing, callback ) {
2188 if ( typeof force === "boolean" || force === undefined ) {
2189 if ( !speed ) {
2190
2191 // Without speed parameter
2192 return orig.apply( this, arguments );
2193 } else {
2194 return $.effects.animateClass.call( this,
2195 ( force ? { add: classNames } : { remove: classNames } ),
2196 speed, easing, callback );
2197 }
2198 } else {
2199
2200 // Without force parameter
2201 return $.effects.animateClass.call( this,
2202 { toggle: classNames }, force, speed, easing );
2203 }
2204 };
2205 } )( $.fn.toggleClass ),
2206
2207 switchClass: function( remove, add, speed, easing, callback ) {
2208 return $.effects.animateClass.call( this, {
2209 add: add,
2210 remove: remove
2211 }, speed, easing, callback );
2212 }
2213 } );
2214
2215 } )();
2216
2217 /******************************************************************************/
2218 /*********************************** EFFECTS **********************************/
2219 /******************************************************************************/
2220
2221 ( function() {
2222
2223 if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
2224 $.expr.filters.animated = ( function( orig ) {
2225 return function( elem ) {
2226 return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
2227 };
2228 } )( $.expr.filters.animated );
2229 }
2230
2231 if ( $.uiBackCompat !== false ) {
2232 $.extend( $.effects, {
2233
2234 // Saves a set of properties in a data storage
2235 save: function( element, set ) {
2236 var i = 0, length = set.length;
2237 for ( ; i < length; i++ ) {
2238 if ( set[ i ] !== null ) {
2239 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
2240 }
2241 }
2242 },
2243
2244 // Restores a set of previously saved properties from a data storage
2245 restore: function( element, set ) {
2246 var val, i = 0, length = set.length;
2247 for ( ; i < length; i++ ) {
2248 if ( set[ i ] !== null ) {
2249 val = element.data( dataSpace + set[ i ] );
2250 element.css( set[ i ], val );
2251 }
2252 }
2253 },
2254
2255 setMode: function( el, mode ) {
2256 if ( mode === "toggle" ) {
2257 mode = el.is( ":hidden" ) ? "show" : "hide";
2258 }
2259 return mode;
2260 },
2261
2262 // Wraps the element around a wrapper that copies position properties
2263 createWrapper: function( element ) {
2264
2265 // If the element is already wrapped, return it
2266 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
2267 return element.parent();
2268 }
2269
2270 // Wrap the element
2271 var props = {
2272 width: element.outerWidth( true ),
2273 height: element.outerHeight( true ),
2274 "float": element.css( "float" )
2275 },
2276 wrapper = $( "<div></div>" )
2277 .addClass( "ui-effects-wrapper" )
2278 .css( {
2279 fontSize: "100%",
2280 background: "transparent",
2281 border: "none",
2282 margin: 0,
2283 padding: 0
2284 } ),
2285
2286 // Store the size in case width/height are defined in % - Fixes #5245
2287 size = {
2288 width: element.width(),
2289 height: element.height()
2290 },
2291 active = document.activeElement;
2292
2293 // Support: Firefox
2294 // Firefox incorrectly exposes anonymous content
2295 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
2296 try {
2297 active.id;
2298 } catch ( e ) {
2299 active = document.body;
2300 }
2301
2302 element.wrap( wrapper );
2303
2304 // Fixes #7595 - Elements lose focus when wrapped.
2305 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
2306 $( active ).trigger( "focus" );
2307 }
2308
2309 // Hotfix for jQuery 1.4 since some change in wrap() seems to actually
2310 // lose the reference to the wrapped element
2311 wrapper = element.parent();
2312
2313 // Transfer positioning properties to the wrapper
2314 if ( element.css( "position" ) === "static" ) {
2315 wrapper.css( { position: "relative" } );
2316 element.css( { position: "relative" } );
2317 } else {
2318 $.extend( props, {
2319 position: element.css( "position" ),
2320 zIndex: element.css( "z-index" )
2321 } );
2322 $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
2323 props[ pos ] = element.css( pos );
2324 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
2325 props[ pos ] = "auto";
2326 }
2327 } );
2328 element.css( {
2329 position: "relative",
2330 top: 0,
2331 left: 0,
2332 right: "auto",
2333 bottom: "auto"
2334 } );
2335 }
2336 element.css( size );
2337
2338 return wrapper.css( props ).show();
2339 },
2340
2341 removeWrapper: function( element ) {
2342 var active = document.activeElement;
2343
2344 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
2345 element.parent().replaceWith( element );
2346
2347 // Fixes #7595 - Elements lose focus when wrapped.
2348 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
2349 $( active ).trigger( "focus" );
2350 }
2351 }
2352
2353 return element;
2354 }
2355 } );
2356 }
2357
2358 $.extend( $.effects, {
2359 version: "1.12.1",
2360
2361 define: function( name, mode, effect ) {
2362 if ( !effect ) {
2363 effect = mode;
2364 mode = "effect";
2365 }
2366
2367 $.effects.effect[ name ] = effect;
2368 $.effects.effect[ name ].mode = mode;
2369
2370 return effect;
2371 },
2372
2373 scaledDimensions: function( element, percent, direction ) {
2374 if ( percent === 0 ) {
2375 return {
2376 height: 0,
2377 width: 0,
2378 outerHeight: 0,
2379 outerWidth: 0
2380 };
2381 }
2382
2383 var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
2384 y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
2385
2386 return {
2387 height: element.height() * y,
2388 width: element.width() * x,
2389 outerHeight: element.outerHeight() * y,
2390 outerWidth: element.outerWidth() * x
2391 };
2392
2393 },
2394
2395 clipToBox: function( animation ) {
2396 return {
2397 width: animation.clip.right - animation.clip.left,
2398 height: animation.clip.bottom - animation.clip.top,
2399 left: animation.clip.left,
2400 top: animation.clip.top
2401 };
2402 },
2403
2404 // Injects recently queued functions to be first in line (after "inprogress")
2405 unshift: function( element, queueLength, count ) {
2406 var queue = element.queue();
2407
2408 if ( queueLength > 1 ) {
2409 queue.splice.apply( queue,
2410 [ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
2411 }
2412 element.dequeue();
2413 },
2414
2415 saveStyle: function( element ) {
2416 element.data( dataSpaceStyle, element[ 0 ].style.cssText );
2417 },
2418
2419 restoreStyle: function( element ) {
2420 element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
2421 element.removeData( dataSpaceStyle );
2422 },
2423
2424 mode: function( element, mode ) {
2425 var hidden = element.is( ":hidden" );
2426
2427 if ( mode === "toggle" ) {
2428 mode = hidden ? "show" : "hide";
2429 }
2430 if ( hidden ? mode === "hide" : mode === "show" ) {
2431 mode = "none";
2432 }
2433 return mode;
2434 },
2435
2436 // Translates a [top,left] array into a baseline value
2437 getBaseline: function( origin, original ) {
2438 var y, x;
2439
2440 switch ( origin[ 0 ] ) {
2441 case "top":
2442 y = 0;
2443 break;
2444 case "middle":
2445 y = 0.5;
2446 break;
2447 case "bottom":
2448 y = 1;
2449 break;
2450 default:
2451 y = origin[ 0 ] / original.height;
2452 }
2453
2454 switch ( origin[ 1 ] ) {
2455 case "left":
2456 x = 0;
2457 break;
2458 case "center":
2459 x = 0.5;
2460 break;
2461 case "right":
2462 x = 1;
2463 break;
2464 default:
2465 x = origin[ 1 ] / original.width;
2466 }
2467
2468 return {
2469 x: x,
2470 y: y
2471 };
2472 },
2473
2474 // Creates a placeholder element so that the original element can be made absolute
2475 createPlaceholder: function( element ) {
2476 var placeholder,
2477 cssPosition = element.css( "position" ),
2478 position = element.position();
2479
2480 // Lock in margins first to account for form elements, which
2481 // will change margin if you explicitly set height
2482 // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
2483 // Support: Safari
2484 element.css( {
2485 marginTop: element.css( "marginTop" ),
2486 marginBottom: element.css( "marginBottom" ),
2487 marginLeft: element.css( "marginLeft" ),
2488 marginRight: element.css( "marginRight" )
2489 } )
2490 .outerWidth( element.outerWidth() )
2491 .outerHeight( element.outerHeight() );
2492
2493 if ( /^(static|relative)/.test( cssPosition ) ) {
2494 cssPosition = "absolute";
2495
2496 placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
2497
2498 // Convert inline to inline block to account for inline elements
2499 // that turn to inline block based on content (like img)
2500 display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
2501 "inline-block" :
2502 "block",
2503 visibility: "hidden",
2504
2505 // Margins need to be set to account for margin collapse
2506 marginTop: element.css( "marginTop" ),
2507 marginBottom: element.css( "marginBottom" ),
2508 marginLeft: element.css( "marginLeft" ),
2509 marginRight: element.css( "marginRight" ),
2510 "float": element.css( "float" )
2511 } )
2512 .outerWidth( element.outerWidth() )
2513 .outerHeight( element.outerHeight() )
2514 .addClass( "ui-effects-placeholder" );
2515
2516 element.data( dataSpace + "placeholder", placeholder );
2517 }
2518
2519 element.css( {
2520 position: cssPosition,
2521 left: position.left,
2522 top: position.top
2523 } );
2524
2525 return placeholder;
2526 },
2527
2528 removePlaceholder: function( element ) {
2529 var dataKey = dataSpace + "placeholder",
2530 placeholder = element.data( dataKey );
2531
2532 if ( placeholder ) {
2533 placeholder.remove();
2534 element.removeData( dataKey );
2535 }
2536 },
2537
2538 // Removes a placeholder if it exists and restores
2539 // properties that were modified during placeholder creation
2540 cleanUp: function( element ) {
2541 $.effects.restoreStyle( element );
2542 $.effects.removePlaceholder( element );
2543 },
2544
2545 setTransition: function( element, list, factor, value ) {
2546 value = value || {};
2547 $.each( list, function( i, x ) {
2548 var unit = element.cssUnit( x );
2549 if ( unit[ 0 ] > 0 ) {
2550 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
2551 }
2552 } );
2553 return value;
2554 }
2555 } );
2556
2557 // Return an effect options object for the given parameters:
2558 function _normalizeArguments( effect, options, speed, callback ) {
2559
2560 // Allow passing all options as the first parameter
2561 if ( $.isPlainObject( effect ) ) {
2562 options = effect;
2563 effect = effect.effect;
2564 }
2565
2566 // Convert to an object
2567 effect = { effect: effect };
2568
2569 // Catch (effect, null, ...)
2570 if ( options == null ) {
2571 options = {};
2572 }
2573
2574 // Catch (effect, callback)
2575 if ( $.isFunction( options ) ) {
2576 callback = options;
2577 speed = null;
2578 options = {};
2579 }
2580
2581 // Catch (effect, speed, ?)
2582 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
2583 callback = speed;
2584 speed = options;
2585 options = {};
2586 }
2587
2588 // Catch (effect, options, callback)
2589 if ( $.isFunction( speed ) ) {
2590 callback = speed;
2591 speed = null;
2592 }
2593
2594 // Add options to effect
2595 if ( options ) {
2596 $.extend( effect, options );
2597 }
2598
2599 speed = speed || options.duration;
2600 effect.duration = $.fx.off ? 0 :
2601 typeof speed === "number" ? speed :
2602 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
2603 $.fx.speeds._default;
2604
2605 effect.complete = callback || options.complete;
2606
2607 return effect;
2608 }
2609
2610 function standardAnimationOption( option ) {
2611
2612 // Valid standard speeds (nothing, number, named speed)
2613 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
2614 return true;
2615 }
2616
2617 // Invalid strings - treat as "normal" speed
2618 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
2619 return true;
2620 }
2621
2622 // Complete callback
2623 if ( $.isFunction( option ) ) {
2624 return true;
2625 }
2626
2627 // Options hash (but not naming an effect)
2628 if ( typeof option === "object" && !option.effect ) {
2629 return true;
2630 }
2631
2632 // Didn't match any standard API
2633 return false;
2634 }
2635
2636 $.fn.extend( {
2637 effect: function( /* effect, options, speed, callback */ ) {
2638 var args = _normalizeArguments.apply( this, arguments ),
2639 effectMethod = $.effects.effect[ args.effect ],
2640 defaultMode = effectMethod.mode,
2641 queue = args.queue,
2642 queueName = queue || "fx",
2643 complete = args.complete,
2644 mode = args.mode,
2645 modes = [],
2646 prefilter = function( next ) {
2647 var el = $( this ),
2648 normalizedMode = $.effects.mode( el, mode ) || defaultMode;
2649
2650 // Sentinel for duck-punching the :animated psuedo-selector
2651 el.data( dataSpaceAnimated, true );
2652
2653 // Save effect mode for later use,
2654 // we can't just call $.effects.mode again later,
2655 // as the .show() below destroys the initial state
2656 modes.push( normalizedMode );
2657
2658 // See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
2659 if ( defaultMode && ( normalizedMode === "show" ||
2660 ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
2661 el.show();
2662 }
2663
2664 if ( !defaultMode || normalizedMode !== "none" ) {
2665 $.effects.saveStyle( el );
2666 }
2667
2668 if ( $.isFunction( next ) ) {
2669 next();
2670 }
2671 };
2672
2673 if ( $.fx.off || !effectMethod ) {
2674
2675 // Delegate to the original method (e.g., .show()) if possible
2676 if ( mode ) {
2677 return this[ mode ]( args.duration, complete );
2678 } else {
2679 return this.each( function() {
2680 if ( complete ) {
2681 complete.call( this );
2682 }
2683 } );
2684 }
2685 }
2686
2687 function run( next ) {
2688 var elem = $( this );
2689
2690 function cleanup() {
2691 elem.removeData( dataSpaceAnimated );
2692
2693 $.effects.cleanUp( elem );
2694
2695 if ( args.mode === "hide" ) {
2696 elem.hide();
2697 }
2698
2699 done();
2700 }
2701
2702 function done() {
2703 if ( $.isFunction( complete ) ) {
2704 complete.call( elem[ 0 ] );
2705 }
2706
2707 if ( $.isFunction( next ) ) {
2708 next();
2709 }
2710 }
2711
2712 // Override mode option on a per element basis,
2713 // as toggle can be either show or hide depending on element state
2714 args.mode = modes.shift();
2715
2716 if ( $.uiBackCompat !== false && !defaultMode ) {
2717 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
2718
2719 // Call the core method to track "olddisplay" properly
2720 elem[ mode ]();
2721 done();
2722 } else {
2723 effectMethod.call( elem[ 0 ], args, done );
2724 }
2725 } else {
2726 if ( args.mode === "none" ) {
2727
2728 // Call the core method to track "olddisplay" properly
2729 elem[ mode ]();
2730 done();
2731 } else {
2732 effectMethod.call( elem[ 0 ], args, cleanup );
2733 }
2734 }
2735 }
2736
2737 // Run prefilter on all elements first to ensure that
2738 // any showing or hiding happens before placeholder creation,
2739 // which ensures that any layout changes are correctly captured.
2740 return queue === false ?
2741 this.each( prefilter ).each( run ) :
2742 this.queue( queueName, prefilter ).queue( queueName, run );
2743 },
2744
2745 show: ( function( orig ) {
2746 return function( option ) {
2747 if ( standardAnimationOption( option ) ) {
2748 return orig.apply( this, arguments );
2749 } else {
2750 var args = _normalizeArguments.apply( this, arguments );
2751 args.mode = "show";
2752 return this.effect.call( this, args );
2753 }
2754 };
2755 } )( $.fn.show ),
2756
2757 hide: ( function( orig ) {
2758 return function( option ) {
2759 if ( standardAnimationOption( option ) ) {
2760 return orig.apply( this, arguments );
2761 } else {
2762 var args = _normalizeArguments.apply( this, arguments );
2763 args.mode = "hide";
2764 return this.effect.call( this, args );
2765 }
2766 };
2767 } )( $.fn.hide ),
2768
2769 toggle: ( function( orig ) {
2770 return function( option ) {
2771 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
2772 return orig.apply( this, arguments );
2773 } else {
2774 var args = _normalizeArguments.apply( this, arguments );
2775 args.mode = "toggle";
2776 return this.effect.call( this, args );
2777 }
2778 };
2779 } )( $.fn.toggle ),
2780
2781 cssUnit: function( key ) {
2782 var style = this.css( key ),
2783 val = [];
2784
2785 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
2786 if ( style.indexOf( unit ) > 0 ) {
2787 val = [ parseFloat( style ), unit ];
2788 }
2789 } );
2790 return val;
2791 },
2792
2793 cssClip: function( clipObj ) {
2794 if ( clipObj ) {
2795 return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
2796 clipObj.bottom + "px " + clipObj.left + "px)" );
2797 }
2798 return parseClip( this.css( "clip" ), this );
2799 },
2800
2801 transfer: function( options, done ) {
2802 var element = $( this ),
2803 target = $( options.to ),
2804 targetFixed = target.css( "position" ) === "fixed",
2805 body = $( "body" ),
2806 fixTop = targetFixed ? body.scrollTop() : 0,
2807 fixLeft = targetFixed ? body.scrollLeft() : 0,
2808 endPosition = target.offset(),
2809 animation = {
2810 top: endPosition.top - fixTop,
2811 left: endPosition.left - fixLeft,
2812 height: target.innerHeight(),
2813 width: target.innerWidth()
2814 },
2815 startPosition = element.offset(),
2816 transfer = $( "<div class='ui-effects-transfer'></div>" )
2817 .appendTo( "body" )
2818 .addClass( options.className )
2819 .css( {
2820 top: startPosition.top - fixTop,
2821 left: startPosition.left - fixLeft,
2822 height: element.innerHeight(),
2823 width: element.innerWidth(),
2824 position: targetFixed ? "fixed" : "absolute"
2825 } )
2826 .animate( animation, options.duration, options.easing, function() {
2827 transfer.remove();
2828 if ( $.isFunction( done ) ) {
2829 done();
2830 }
2831 } );
2832 }
2833 } );
2834
2835 function parseClip( str, element ) {
2836 var outerWidth = element.outerWidth(),
2837 outerHeight = element.outerHeight(),
2838 clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
2839 values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
2840
2841 return {
2842 top: parseFloat( values[ 1 ] ) || 0,
2843 right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
2844 bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
2845 left: parseFloat( values[ 4 ] ) || 0
2846 };
2847 }
2848
2849 $.fx.step.clip = function( fx ) {
2850 if ( !fx.clipInit ) {
2851 fx.start = $( fx.elem ).cssClip();
2852 if ( typeof fx.end === "string" ) {
2853 fx.end = parseClip( fx.end, fx.elem );
2854 }
2855 fx.clipInit = true;
2856 }
2857
2858 $( fx.elem ).cssClip( {
2859 top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
2860 right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
2861 bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
2862 left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
2863 } );
2864 };
2865
2866 } )();
2867
2868 /******************************************************************************/
2869 /*********************************** EASING ***********************************/
2870 /******************************************************************************/
2871
2872 ( function() {
2873
2874 // Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
2875
2876 var baseEasings = {};
2877
2878 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
2879 baseEasings[ name ] = function( p ) {
2880 return Math.pow( p, i + 2 );
2881 };
2882 } );
2883
2884 $.extend( baseEasings, {
2885 Sine: function( p ) {
2886 return 1 - Math.cos( p * Math.PI / 2 );
2887 },
2888 Circ: function( p ) {
2889 return 1 - Math.sqrt( 1 - p * p );
2890 },
2891 Elastic: function( p ) {
2892 return p === 0 || p === 1 ? p :
2893 -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
2894 },
2895 Back: function( p ) {
2896 return p * p * ( 3 * p - 2 );
2897 },
2898 Bounce: function( p ) {
2899 var pow2,
2900 bounce = 4;
2901
2902 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
2903 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
2904 }
2905 } );
2906
2907 $.each( baseEasings, function( name, easeIn ) {
2908 $.easing[ "easeIn" + name ] = easeIn;
2909 $.easing[ "easeOut" + name ] = function( p ) {
2910 return 1 - easeIn( 1 - p );
2911 };
2912 $.easing[ "easeInOut" + name ] = function( p ) {
2913 return p < 0.5 ?
2914 easeIn( p * 2 ) / 2 :
2915 1 - easeIn( p * -2 + 2 ) / 2;
2916 };
2917 } );
2918
2919 } )();
2920
2921 var effect = $.effects;
2922
2923
2924 /*!
2925 * jQuery UI Effects Blind 1.12.1
2926 * http://jqueryui.com
2927 *
2928 * Copyright jQuery Foundation and other contributors
2929 * Released under the MIT license.
2930 * http://jquery.org/license
2931 */
2932
2933 //>>label: Blind Effect
2934 //>>group: Effects
2935 //>>description: Blinds the element.
2936 //>>docs: http://api.jqueryui.com/blind-effect/
2937 //>>demos: http://jqueryui.com/effect/
2938
2939
2940
2941 var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
2942 var map = {
2943 up: [ "bottom", "top" ],
2944 vertical: [ "bottom", "top" ],
2945 down: [ "top", "bottom" ],
2946 left: [ "right", "left" ],
2947 horizontal: [ "right", "left" ],
2948 right: [ "left", "right" ]
2949 },
2950 element = $( this ),
2951 direction = options.direction || "up",
2952 start = element.cssClip(),
2953 animate = { clip: $.extend( {}, start ) },
2954 placeholder = $.effects.createPlaceholder( element );
2955
2956 animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
2957
2958 if ( options.mode === "show" ) {
2959 element.cssClip( animate.clip );
2960 if ( placeholder ) {
2961 placeholder.css( $.effects.clipToBox( animate ) );
2962 }
2963
2964 animate.clip = start;
2965 }
2966
2967 if ( placeholder ) {
2968 placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
2969 }
2970
2971 element.animate( animate, {
2972 queue: false,
2973 duration: options.duration,
2974 easing: options.easing,
2975 complete: done
2976 } );
2977 } );
2978
2979
2980 /*!
2981 * jQuery UI Effects Bounce 1.12.1
2982 * http://jqueryui.com
2983 *
2984 * Copyright jQuery Foundation and other contributors
2985 * Released under the MIT license.
2986 * http://jquery.org/license
2987 */
2988
2989 //>>label: Bounce Effect
2990 //>>group: Effects
2991 //>>description: Bounces an element horizontally or vertically n times.
2992 //>>docs: http://api.jqueryui.com/bounce-effect/
2993 //>>demos: http://jqueryui.com/effect/
2994
2995
2996
2997 var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
2998 var upAnim, downAnim, refValue,
2999 element = $( this ),
3000
3001 // Defaults:
3002 mode = options.mode,
3003 hide = mode === "hide",
3004 show = mode === "show",
3005 direction = options.direction || "up",
3006 distance = options.distance,
3007 times = options.times || 5,
3008
3009 // Number of internal animations
3010 anims = times * 2 + ( show || hide ? 1 : 0 ),
3011 speed = options.duration / anims,
3012 easing = options.easing,
3013
3014 // Utility:
3015 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3016 motion = ( direction === "up" || direction === "left" ),
3017 i = 0,
3018
3019 queuelen = element.queue().length;
3020
3021 $.effects.createPlaceholder( element );
3022
3023 refValue = element.css( ref );
3024
3025 // Default distance for the BIGGEST bounce is the outer Distance / 3
3026 if ( !distance ) {
3027 distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
3028 }
3029
3030 if ( show ) {
3031 downAnim = { opacity: 1 };
3032 downAnim[ ref ] = refValue;
3033
3034 // If we are showing, force opacity 0 and set the initial position
3035 // then do the "first" animation
3036 element
3037 .css( "opacity", 0 )
3038 .css( ref, motion ? -distance * 2 : distance * 2 )
3039 .animate( downAnim, speed, easing );
3040 }
3041
3042 // Start at the smallest distance if we are hiding
3043 if ( hide ) {
3044 distance = distance / Math.pow( 2, times - 1 );
3045 }
3046
3047 downAnim = {};
3048 downAnim[ ref ] = refValue;
3049
3050 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
3051 for ( ; i < times; i++ ) {
3052 upAnim = {};
3053 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
3054
3055 element
3056 .animate( upAnim, speed, easing )
3057 .animate( downAnim, speed, easing );
3058
3059 distance = hide ? distance * 2 : distance / 2;
3060 }
3061
3062 // Last Bounce when Hiding
3063 if ( hide ) {
3064 upAnim = { opacity: 0 };
3065 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
3066
3067 element.animate( upAnim, speed, easing );
3068 }
3069
3070 element.queue( done );
3071
3072 $.effects.unshift( element, queuelen, anims + 1 );
3073 } );
3074
3075
3076 /*!
3077 * jQuery UI Effects Clip 1.12.1
3078 * http://jqueryui.com
3079 *
3080 * Copyright jQuery Foundation and other contributors
3081 * Released under the MIT license.
3082 * http://jquery.org/license
3083 */
3084
3085 //>>label: Clip Effect
3086 //>>group: Effects
3087 //>>description: Clips the element on and off like an old TV.
3088 //>>docs: http://api.jqueryui.com/clip-effect/
3089 //>>demos: http://jqueryui.com/effect/
3090
3091
3092
3093 var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
3094 var start,
3095 animate = {},
3096 element = $( this ),
3097 direction = options.direction || "vertical",
3098 both = direction === "both",
3099 horizontal = both || direction === "horizontal",
3100 vertical = both || direction === "vertical";
3101
3102 start = element.cssClip();
3103 animate.clip = {
3104 top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
3105 right: horizontal ? ( start.right - start.left ) / 2 : start.right,
3106 bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
3107 left: horizontal ? ( start.right - start.left ) / 2 : start.left
3108 };
3109
3110 $.effects.createPlaceholder( element );
3111
3112 if ( options.mode === "show" ) {
3113 element.cssClip( animate.clip );
3114 animate.clip = start;
3115 }
3116
3117 element.animate( animate, {
3118 queue: false,
3119 duration: options.duration,
3120 easing: options.easing,
3121 complete: done
3122 } );
3123
3124 } );
3125
3126
3127 /*!
3128 * jQuery UI Effects Drop 1.12.1
3129 * http://jqueryui.com
3130 *
3131 * Copyright jQuery Foundation and other contributors
3132 * Released under the MIT license.
3133 * http://jquery.org/license
3134 */
3135
3136 //>>label: Drop Effect
3137 //>>group: Effects
3138 //>>description: Moves an element in one direction and hides it at the same time.
3139 //>>docs: http://api.jqueryui.com/drop-effect/
3140 //>>demos: http://jqueryui.com/effect/
3141
3142
3143
3144 var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
3145
3146 var distance,
3147 element = $( this ),
3148 mode = options.mode,
3149 show = mode === "show",
3150 direction = options.direction || "left",
3151 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3152 motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
3153 oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
3154 animation = {
3155 opacity: 0
3156 };
3157
3158 $.effects.createPlaceholder( element );
3159
3160 distance = options.distance ||
3161 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
3162
3163 animation[ ref ] = motion + distance;
3164
3165 if ( show ) {
3166 element.css( animation );
3167
3168 animation[ ref ] = oppositeMotion + distance;
3169 animation.opacity = 1;
3170 }
3171
3172 // Animate
3173 element.animate( animation, {
3174 queue: false,
3175 duration: options.duration,
3176 easing: options.easing,
3177 complete: done
3178 } );
3179 } );
3180
3181
3182 /*!
3183 * jQuery UI Effects Explode 1.12.1
3184 * http://jqueryui.com
3185 *
3186 * Copyright jQuery Foundation and other contributors
3187 * Released under the MIT license.
3188 * http://jquery.org/license
3189 */
3190
3191 //>>label: Explode Effect
3192 //>>group: Effects
3193 // jscs:disable maximumLineLength
3194 //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
3195 // jscs:enable maximumLineLength
3196 //>>docs: http://api.jqueryui.com/explode-effect/
3197 //>>demos: http://jqueryui.com/effect/
3198
3199
3200
3201 var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
3202
3203 var i, j, left, top, mx, my,
3204 rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
3205 cells = rows,
3206 element = $( this ),
3207 mode = options.mode,
3208 show = mode === "show",
3209
3210 // Show and then visibility:hidden the element before calculating offset
3211 offset = element.show().css( "visibility", "hidden" ).offset(),
3212
3213 // Width and height of a piece
3214 width = Math.ceil( element.outerWidth() / cells ),
3215 height = Math.ceil( element.outerHeight() / rows ),
3216 pieces = [];
3217
3218 // Children animate complete:
3219 function childComplete() {
3220 pieces.push( this );
3221 if ( pieces.length === rows * cells ) {
3222 animComplete();
3223 }
3224 }
3225
3226 // Clone the element for each row and cell.
3227 for ( i = 0; i < rows; i++ ) { // ===>
3228 top = offset.top + i * height;
3229 my = i - ( rows - 1 ) / 2;
3230
3231 for ( j = 0; j < cells; j++ ) { // |||
3232 left = offset.left + j * width;
3233 mx = j - ( cells - 1 ) / 2;
3234
3235 // Create a clone of the now hidden main element that will be absolute positioned
3236 // within a wrapper div off the -left and -top equal to size of our pieces
3237 element
3238 .clone()
3239 .appendTo( "body" )
3240 .wrap( "<div></div>" )
3241 .css( {
3242 position: "absolute",
3243 visibility: "visible",
3244 left: -j * width,
3245 top: -i * height
3246 } )
3247
3248 // Select the wrapper - make it overflow: hidden and absolute positioned based on
3249 // where the original was located +left and +top equal to the size of pieces
3250 .parent()
3251 .addClass( "ui-effects-explode" )
3252 .css( {
3253 position: "absolute",
3254 overflow: "hidden",
3255 width: width,
3256 height: height,
3257 left: left + ( show ? mx * width : 0 ),
3258 top: top + ( show ? my * height : 0 ),
3259 opacity: show ? 0 : 1
3260 } )
3261 .animate( {
3262 left: left + ( show ? 0 : mx * width ),
3263 top: top + ( show ? 0 : my * height ),
3264 opacity: show ? 1 : 0
3265 }, options.duration || 500, options.easing, childComplete );
3266 }
3267 }
3268
3269 function animComplete() {
3270 element.css( {
3271 visibility: "visible"
3272 } );
3273 $( pieces ).remove();
3274 done();
3275 }
3276 } );
3277
3278
3279 /*!
3280 * jQuery UI Effects Fade 1.12.1
3281 * http://jqueryui.com
3282 *
3283 * Copyright jQuery Foundation and other contributors
3284 * Released under the MIT license.
3285 * http://jquery.org/license
3286 */
3287
3288 //>>label: Fade Effect
3289 //>>group: Effects
3290 //>>description: Fades the element.
3291 //>>docs: http://api.jqueryui.com/fade-effect/
3292 //>>demos: http://jqueryui.com/effect/
3293
3294
3295
3296 var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
3297 var show = options.mode === "show";
3298
3299 $( this )
3300 .css( "opacity", show ? 0 : 1 )
3301 .animate( {
3302 opacity: show ? 1 : 0
3303 }, {
3304 queue: false,
3305 duration: options.duration,
3306 easing: options.easing,
3307 complete: done
3308 } );
3309 } );
3310
3311
3312 /*!
3313 * jQuery UI Effects Fold 1.12.1
3314 * http://jqueryui.com
3315 *
3316 * Copyright jQuery Foundation and other contributors
3317 * Released under the MIT license.
3318 * http://jquery.org/license
3319 */
3320
3321 //>>label: Fold Effect
3322 //>>group: Effects
3323 //>>description: Folds an element first horizontally and then vertically.
3324 //>>docs: http://api.jqueryui.com/fold-effect/
3325 //>>demos: http://jqueryui.com/effect/
3326
3327
3328
3329 var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
3330
3331 // Create element
3332 var element = $( this ),
3333 mode = options.mode,
3334 show = mode === "show",
3335 hide = mode === "hide",
3336 size = options.size || 15,
3337 percent = /([0-9]+)%/.exec( size ),
3338 horizFirst = !!options.horizFirst,
3339 ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
3340 duration = options.duration / 2,
3341
3342 placeholder = $.effects.createPlaceholder( element ),
3343
3344 start = element.cssClip(),
3345 animation1 = { clip: $.extend( {}, start ) },
3346 animation2 = { clip: $.extend( {}, start ) },
3347
3348 distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
3349
3350 queuelen = element.queue().length;
3351
3352 if ( percent ) {
3353 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
3354 }
3355 animation1.clip[ ref[ 0 ] ] = size;
3356 animation2.clip[ ref[ 0 ] ] = size;
3357 animation2.clip[ ref[ 1 ] ] = 0;
3358
3359 if ( show ) {
3360 element.cssClip( animation2.clip );
3361 if ( placeholder ) {
3362 placeholder.css( $.effects.clipToBox( animation2 ) );
3363 }
3364
3365 animation2.clip = start;
3366 }
3367
3368 // Animate
3369 element
3370 .queue( function( next ) {
3371 if ( placeholder ) {
3372 placeholder
3373 .animate( $.effects.clipToBox( animation1 ), duration, options.easing )
3374 .animate( $.effects.clipToBox( animation2 ), duration, options.easing );
3375 }
3376
3377 next();
3378 } )
3379 .animate( animation1, duration, options.easing )
3380 .animate( animation2, duration, options.easing )
3381 .queue( done );
3382
3383 $.effects.unshift( element, queuelen, 4 );
3384 } );
3385
3386
3387 /*!
3388 * jQuery UI Effects Highlight 1.12.1
3389 * http://jqueryui.com
3390 *
3391 * Copyright jQuery Foundation and other contributors
3392 * Released under the MIT license.
3393 * http://jquery.org/license
3394 */
3395
3396 //>>label: Highlight Effect
3397 //>>group: Effects
3398 //>>description: Highlights the background of an element in a defined color for a custom duration.
3399 //>>docs: http://api.jqueryui.com/highlight-effect/
3400 //>>demos: http://jqueryui.com/effect/
3401
3402
3403
3404 var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
3405 var element = $( this ),
3406 animation = {
3407 backgroundColor: element.css( "backgroundColor" )
3408 };
3409
3410 if ( options.mode === "hide" ) {
3411 animation.opacity = 0;
3412 }
3413
3414 $.effects.saveStyle( element );
3415
3416 element
3417 .css( {
3418 backgroundImage: "none",
3419 backgroundColor: options.color || "#ffff99"
3420 } )
3421 .animate( animation, {
3422 queue: false,
3423 duration: options.duration,
3424 easing: options.easing,
3425 complete: done
3426 } );
3427 } );
3428
3429
3430 /*!
3431 * jQuery UI Effects Size 1.12.1
3432 * http://jqueryui.com
3433 *
3434 * Copyright jQuery Foundation and other contributors
3435 * Released under the MIT license.
3436 * http://jquery.org/license
3437 */
3438
3439 //>>label: Size Effect
3440 //>>group: Effects
3441 //>>description: Resize an element to a specified width and height.
3442 //>>docs: http://api.jqueryui.com/size-effect/
3443 //>>demos: http://jqueryui.com/effect/
3444
3445
3446
3447 var effectsEffectSize = $.effects.define( "size", function( options, done ) {
3448
3449 // Create element
3450 var baseline, factor, temp,
3451 element = $( this ),
3452
3453 // Copy for children
3454 cProps = [ "fontSize" ],
3455 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
3456 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
3457
3458 // Set options
3459 mode = options.mode,
3460 restore = mode !== "effect",
3461 scale = options.scale || "both",
3462 origin = options.origin || [ "middle", "center" ],
3463 position = element.css( "position" ),
3464 pos = element.position(),
3465 original = $.effects.scaledDimensions( element ),
3466 from = options.from || original,
3467 to = options.to || $.effects.scaledDimensions( element, 0 );
3468
3469 $.effects.createPlaceholder( element );
3470
3471 if ( mode === "show" ) {
3472 temp = from;
3473 from = to;
3474 to = temp;
3475 }
3476
3477 // Set scaling factor
3478 factor = {
3479 from: {
3480 y: from.height / original.height,
3481 x: from.width / original.width
3482 },
3483 to: {
3484 y: to.height / original.height,
3485 x: to.width / original.width
3486 }
3487 };
3488
3489 // Scale the css box
3490 if ( scale === "box" || scale === "both" ) {
3491
3492 // Vertical props scaling
3493 if ( factor.from.y !== factor.to.y ) {
3494 from = $.effects.setTransition( element, vProps, factor.from.y, from );
3495 to = $.effects.setTransition( element, vProps, factor.to.y, to );
3496 }
3497
3498 // Horizontal props scaling
3499 if ( factor.from.x !== factor.to.x ) {
3500 from = $.effects.setTransition( element, hProps, factor.from.x, from );
3501 to = $.effects.setTransition( element, hProps, factor.to.x, to );
3502 }
3503 }
3504
3505 // Scale the content
3506 if ( scale === "content" || scale === "both" ) {
3507
3508 // Vertical props scaling
3509 if ( factor.from.y !== factor.to.y ) {
3510 from = $.effects.setTransition( element, cProps, factor.from.y, from );
3511 to = $.effects.setTransition( element, cProps, factor.to.y, to );
3512 }
3513 }
3514
3515 // Adjust the position properties based on the provided origin points
3516 if ( origin ) {
3517 baseline = $.effects.getBaseline( origin, original );
3518 from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
3519 from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
3520 to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
3521 to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
3522 }
3523 element.css( from );
3524
3525 // Animate the children if desired
3526 if ( scale === "content" || scale === "both" ) {
3527
3528 vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
3529 hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
3530
3531 // Only animate children with width attributes specified
3532 // TODO: is this right? should we include anything with css width specified as well
3533 element.find( "*[width]" ).each( function() {
3534 var child = $( this ),
3535 childOriginal = $.effects.scaledDimensions( child ),
3536 childFrom = {
3537 height: childOriginal.height * factor.from.y,
3538 width: childOriginal.width * factor.from.x,
3539 outerHeight: childOriginal.outerHeight * factor.from.y,
3540 outerWidth: childOriginal.outerWidth * factor.from.x
3541 },
3542 childTo = {
3543 height: childOriginal.height * factor.to.y,
3544 width: childOriginal.width * factor.to.x,
3545 outerHeight: childOriginal.height * factor.to.y,
3546 outerWidth: childOriginal.width * factor.to.x
3547 };
3548
3549 // Vertical props scaling
3550 if ( factor.from.y !== factor.to.y ) {
3551 childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
3552 childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
3553 }
3554
3555 // Horizontal props scaling
3556 if ( factor.from.x !== factor.to.x ) {
3557 childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
3558 childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
3559 }
3560
3561 if ( restore ) {
3562 $.effects.saveStyle( child );
3563 }
3564
3565 // Animate children
3566 child.css( childFrom );
3567 child.animate( childTo, options.duration, options.easing, function() {
3568
3569 // Restore children
3570 if ( restore ) {
3571 $.effects.restoreStyle( child );
3572 }
3573 } );
3574 } );
3575 }
3576
3577 // Animate
3578 element.animate( to, {
3579 queue: false,
3580 duration: options.duration,
3581 easing: options.easing,
3582 complete: function() {
3583
3584 var offset = element.offset();
3585
3586 if ( to.opacity === 0 ) {
3587 element.css( "opacity", from.opacity );
3588 }
3589
3590 if ( !restore ) {
3591 element
3592 .css( "position", position === "static" ? "relative" : position )
3593 .offset( offset );
3594
3595 // Need to save style here so that automatic style restoration
3596 // doesn't restore to the original styles from before the animation.
3597 $.effects.saveStyle( element );
3598 }
3599
3600 done();
3601 }
3602 } );
3603
3604 } );
3605
3606
3607 /*!
3608 * jQuery UI Effects Scale 1.12.1
3609 * http://jqueryui.com
3610 *
3611 * Copyright jQuery Foundation and other contributors
3612 * Released under the MIT license.
3613 * http://jquery.org/license
3614 */
3615
3616 //>>label: Scale Effect
3617 //>>group: Effects
3618 //>>description: Grows or shrinks an element and its content.
3619 //>>docs: http://api.jqueryui.com/scale-effect/
3620 //>>demos: http://jqueryui.com/effect/
3621
3622
3623
3624 var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
3625
3626 // Create element
3627 var el = $( this ),
3628 mode = options.mode,
3629 percent = parseInt( options.percent, 10 ) ||
3630 ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
3631
3632 newOptions = $.extend( true, {
3633 from: $.effects.scaledDimensions( el ),
3634 to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
3635 origin: options.origin || [ "middle", "center" ]
3636 }, options );
3637
3638 // Fade option to support puff
3639 if ( options.fade ) {
3640 newOptions.from.opacity = 1;
3641 newOptions.to.opacity = 0;
3642 }
3643
3644 $.effects.effect.size.call( this, newOptions, done );
3645 } );
3646
3647
3648 /*!
3649 * jQuery UI Effects Puff 1.12.1
3650 * http://jqueryui.com
3651 *
3652 * Copyright jQuery Foundation and other contributors
3653 * Released under the MIT license.
3654 * http://jquery.org/license
3655 */
3656
3657 //>>label: Puff Effect
3658 //>>group: Effects
3659 //>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
3660 //>>docs: http://api.jqueryui.com/puff-effect/
3661 //>>demos: http://jqueryui.com/effect/
3662
3663
3664
3665 var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
3666 var newOptions = $.extend( true, {}, options, {
3667 fade: true,
3668 percent: parseInt( options.percent, 10 ) || 150
3669 } );
3670
3671 $.effects.effect.scale.call( this, newOptions, done );
3672 } );
3673
3674
3675 /*!
3676 * jQuery UI Effects Pulsate 1.12.1
3677 * http://jqueryui.com
3678 *
3679 * Copyright jQuery Foundation and other contributors
3680 * Released under the MIT license.
3681 * http://jquery.org/license
3682 */
3683
3684 //>>label: Pulsate Effect
3685 //>>group: Effects
3686 //>>description: Pulsates an element n times by changing the opacity to zero and back.
3687 //>>docs: http://api.jqueryui.com/pulsate-effect/
3688 //>>demos: http://jqueryui.com/effect/
3689
3690
3691
3692 var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
3693 var element = $( this ),
3694 mode = options.mode,
3695 show = mode === "show",
3696 hide = mode === "hide",
3697 showhide = show || hide,
3698
3699 // Showing or hiding leaves off the "last" animation
3700 anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
3701 duration = options.duration / anims,
3702 animateTo = 0,
3703 i = 1,
3704 queuelen = element.queue().length;
3705
3706 if ( show || !element.is( ":visible" ) ) {
3707 element.css( "opacity", 0 ).show();
3708 animateTo = 1;
3709 }
3710
3711 // Anims - 1 opacity "toggles"
3712 for ( ; i < anims; i++ ) {
3713 element.animate( { opacity: animateTo }, duration, options.easing );
3714 animateTo = 1 - animateTo;
3715 }
3716
3717 element.animate( { opacity: animateTo }, duration, options.easing );
3718
3719 element.queue( done );
3720
3721 $.effects.unshift( element, queuelen, anims + 1 );
3722 } );
3723
3724
3725 /*!
3726 * jQuery UI Effects Shake 1.12.1
3727 * http://jqueryui.com
3728 *
3729 * Copyright jQuery Foundation and other contributors
3730 * Released under the MIT license.
3731 * http://jquery.org/license
3732 */
3733
3734 //>>label: Shake Effect
3735 //>>group: Effects
3736 //>>description: Shakes an element horizontally or vertically n times.
3737 //>>docs: http://api.jqueryui.com/shake-effect/
3738 //>>demos: http://jqueryui.com/effect/
3739
3740
3741
3742 var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
3743
3744 var i = 1,
3745 element = $( this ),
3746 direction = options.direction || "left",
3747 distance = options.distance || 20,
3748 times = options.times || 3,
3749 anims = times * 2 + 1,
3750 speed = Math.round( options.duration / anims ),
3751 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3752 positiveMotion = ( direction === "up" || direction === "left" ),
3753 animation = {},
3754 animation1 = {},
3755 animation2 = {},
3756
3757 queuelen = element.queue().length;
3758
3759 $.effects.createPlaceholder( element );
3760
3761 // Animation
3762 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
3763 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
3764 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
3765
3766 // Animate
3767 element.animate( animation, speed, options.easing );
3768
3769 // Shakes
3770 for ( ; i < times; i++ ) {
3771 element
3772 .animate( animation1, speed, options.easing )
3773 .animate( animation2, speed, options.easing );
3774 }
3775
3776 element
3777 .animate( animation1, speed, options.easing )
3778 .animate( animation, speed / 2, options.easing )
3779 .queue( done );
3780
3781 $.effects.unshift( element, queuelen, anims + 1 );
3782 } );
3783
3784
3785 /*!
3786 * jQuery UI Effects Slide 1.12.1
3787 * http://jqueryui.com
3788 *
3789 * Copyright jQuery Foundation and other contributors
3790 * Released under the MIT license.
3791 * http://jquery.org/license
3792 */
3793
3794 //>>label: Slide Effect
3795 //>>group: Effects
3796 //>>description: Slides an element in and out of the viewport.
3797 //>>docs: http://api.jqueryui.com/slide-effect/
3798 //>>demos: http://jqueryui.com/effect/
3799
3800
3801
3802 var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
3803 var startClip, startRef,
3804 element = $( this ),
3805 map = {
3806 up: [ "bottom", "top" ],
3807 down: [ "top", "bottom" ],
3808 left: [ "right", "left" ],
3809 right: [ "left", "right" ]
3810 },
3811 mode = options.mode,
3812 direction = options.direction || "left",
3813 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
3814 positiveMotion = ( direction === "up" || direction === "left" ),
3815 distance = options.distance ||
3816 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
3817 animation = {};
3818
3819 $.effects.createPlaceholder( element );
3820
3821 startClip = element.cssClip();
3822 startRef = element.position()[ ref ];
3823
3824 // Define hide animation
3825 animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
3826 animation.clip = element.cssClip();
3827 animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
3828
3829 // Reverse the animation if we're showing
3830 if ( mode === "show" ) {
3831 element.cssClip( animation.clip );
3832 element.css( ref, animation[ ref ] );
3833 animation.clip = startClip;
3834 animation[ ref ] = startRef;
3835 }
3836
3837 // Actually animate
3838 element.animate( animation, {
3839 queue: false,
3840 duration: options.duration,
3841 easing: options.easing,
3842 complete: done
3843 } );
3844 } );
3845
3846
3847 /*!
3848 * jQuery UI Effects Transfer 1.12.1
3849 * http://jqueryui.com
3850 *
3851 * Copyright jQuery Foundation and other contributors
3852 * Released under the MIT license.
3853 * http://jquery.org/license
3854 */
3855
3856 //>>label: Transfer Effect
3857 //>>group: Effects
3858 //>>description: Displays a transfer effect from one element to another.
3859 //>>docs: http://api.jqueryui.com/transfer-effect/
3860 //>>demos: http://jqueryui.com/effect/
3861
3862
3863
3864 var effect;
3865 if ( $.uiBackCompat !== false ) {
3866 effect = $.effects.define( "transfer", function( options, done ) {
3867 $( this ).transfer( options, done );
3868 } );
3869 }
3870 var effectsEffectTransfer = effect;
3871
3872
3873 /*!
3874 * jQuery UI Focusable 1.12.1
3875 * http://jqueryui.com
3876 *
3877 * Copyright jQuery Foundation and other contributors
3878 * Released under the MIT license.
3879 * http://jquery.org/license
3880 */
3881
3882 //>>label: :focusable Selector
3883 //>>group: Core
3884 //>>description: Selects elements which can be focused.
3885 //>>docs: http://api.jqueryui.com/focusable-selector/
3886
3887
3888
3889 // Selectors
3890 $.ui.focusable = function( element, hasTabindex ) {
3891 var map, mapName, img, focusableIfVisible, fieldset,
3892 nodeName = element.nodeName.toLowerCase();
3893
3894 if ( "area" === nodeName ) {
3895 map = element.parentNode;
3896 mapName = map.name;
3897 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
3898 return false;
3899 }
3900 img = $( "img[usemap='#" + mapName + "']" );
3901 return img.length > 0 && img.is( ":visible" );
3902 }
3903
3904 if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
3905 focusableIfVisible = !element.disabled;
3906
3907 if ( focusableIfVisible ) {
3908
3909 // Form controls within a disabled fieldset are disabled.
3910 // However, controls within the fieldset's legend do not get disabled.
3911 // Since controls generally aren't placed inside legends, we skip
3912 // this portion of the check.
3913 fieldset = $( element ).closest( "fieldset" )[ 0 ];
3914 if ( fieldset ) {
3915 focusableIfVisible = !fieldset.disabled;
3916 }
3917 }
3918 } else if ( "a" === nodeName ) {
3919 focusableIfVisible = element.href || hasTabindex;
3920 } else {
3921 focusableIfVisible = hasTabindex;
3922 }
3923
3924 return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
3925 };
3926
3927 // Support: IE 8 only
3928 // IE 8 doesn't resolve inherit to visible/hidden for computed values
3929 function visible( element ) {
3930 var visibility = element.css( "visibility" );
3931 while ( visibility === "inherit" ) {
3932 element = element.parent();
3933 visibility = element.css( "visibility" );
3934 }
3935 return visibility !== "hidden";
3936 }
3937
3938 $.extend( $.expr[ ":" ], {
3939 focusable: function( element ) {
3940 return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
3941 }
3942 } );
3943
3944 var focusable = $.ui.focusable;
3945
3946
3947
3948
3949 // Support: IE8 Only
3950 // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
3951 // with a string, so we need to find the proper form.
3952 var form = $.fn.form = function() {
3953 return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
3954 };
3955
3956
3957 /*!
3958 * jQuery UI Form Reset Mixin 1.12.1
3959 * http://jqueryui.com
3960 *
3961 * Copyright jQuery Foundation and other contributors
3962 * Released under the MIT license.
3963 * http://jquery.org/license
3964 */
3965
3966 //>>label: Form Reset Mixin
3967 //>>group: Core
3968 //>>description: Refresh input widgets when their form is reset
3969 //>>docs: http://api.jqueryui.com/form-reset-mixin/
3970
3971
3972
3973 var formResetMixin = $.ui.formResetMixin = {
3974 _formResetHandler: function() {
3975 var form = $( this );
3976
3977 // Wait for the form reset to actually happen before refreshing
3978 setTimeout( function() {
3979 var instances = form.data( "ui-form-reset-instances" );
3980 $.each( instances, function() {
3981 this.refresh();
3982 } );
3983 } );
3984 },
3985
3986 _bindFormResetHandler: function() {
3987 this.form = this.element.form();
3988 if ( !this.form.length ) {
3989 return;
3990 }
3991
3992 var instances = this.form.data( "ui-form-reset-instances" ) || [];
3993 if ( !instances.length ) {
3994
3995 // We don't use _on() here because we use a single event handler per form
3996 this.form.on( "reset.ui-form-reset", this._formResetHandler );
3997 }
3998 instances.push( this );
3999 this.form.data( "ui-form-reset-instances", instances );
4000 },
4001
4002 _unbindFormResetHandler: function() {
4003 if ( !this.form.length ) {
4004 return;
4005 }
4006
4007 var instances = this.form.data( "ui-form-reset-instances" );
4008 instances.splice( $.inArray( this, instances ), 1 );
4009 if ( instances.length ) {
4010 this.form.data( "ui-form-reset-instances", instances );
4011 } else {
4012 this.form
4013 .removeData( "ui-form-reset-instances" )
4014 .off( "reset.ui-form-reset" );
4015 }
4016 }
4017 };
4018
4019
4020 /*!
4021 * jQuery UI Support for jQuery core 1.7.x 1.12.1
4022 * http://jqueryui.com
4023 *
4024 * Copyright jQuery Foundation and other contributors
4025 * Released under the MIT license.
4026 * http://jquery.org/license
4027 *
4028 */
4029
4030 //>>label: jQuery 1.7 Support
4031 //>>group: Core
4032 //>>description: Support version 1.7.x of jQuery core
4033
4034
4035
4036 // Support: jQuery 1.7 only
4037 // Not a great way to check versions, but since we only support 1.7+ and only
4038 // need to detect <1.8, this is a simple check that should suffice. Checking
4039 // for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0
4040 // and we'll never reach 1.70.0 (if we do, we certainly won't be supporting
4041 // 1.7 anymore). See #11197 for why we're not using feature detection.
4042 if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) {
4043
4044 // Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()
4045 // Unlike jQuery Core 1.8+, these only support numeric values to set the
4046 // dimensions in pixels
4047 $.each( [ "Width", "Height" ], function( i, name ) {
4048 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
4049 type = name.toLowerCase(),
4050 orig = {
4051 innerWidth: $.fn.innerWidth,
4052 innerHeight: $.fn.innerHeight,
4053 outerWidth: $.fn.outerWidth,
4054 outerHeight: $.fn.outerHeight
4055 };
4056
4057 function reduce( elem, size, border, margin ) {
4058 $.each( side, function() {
4059 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
4060 if ( border ) {
4061 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
4062 }
4063 if ( margin ) {
4064 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
4065 }
4066 } );
4067 return size;
4068 }
4069
4070 $.fn[ "inner" + name ] = function( size ) {
4071 if ( size === undefined ) {
4072 return orig[ "inner" + name ].call( this );
4073 }
4074
4075 return this.each( function() {
4076 $( this ).css( type, reduce( this, size ) + "px" );
4077 } );
4078 };
4079
4080 $.fn[ "outer" + name ] = function( size, margin ) {
4081 if ( typeof size !== "number" ) {
4082 return orig[ "outer" + name ].call( this, size );
4083 }
4084
4085 return this.each( function() {
4086 $( this ).css( type, reduce( this, size, true, margin ) + "px" );
4087 } );
4088 };
4089 } );
4090
4091 $.fn.addBack = function( selector ) {
4092 return this.add( selector == null ?
4093 this.prevObject : this.prevObject.filter( selector )
4094 );
4095 };
4096 }
4097
4098 ;
4099 /*!
4100 * jQuery UI Keycode 1.12.1
4101 * http://jqueryui.com
4102 *
4103 * Copyright jQuery Foundation and other contributors
4104 * Released under the MIT license.
4105 * http://jquery.org/license
4106 */
4107
4108 //>>label: Keycode
4109 //>>group: Core
4110 //>>description: Provide keycodes as keynames
4111 //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
4112
4113
4114 var keycode = $.ui.keyCode = {
4115 BACKSPACE: 8,
4116 COMMA: 188,
4117 DELETE: 46,
4118 DOWN: 40,
4119 END: 35,
4120 ENTER: 13,
4121 ESCAPE: 27,
4122 HOME: 36,
4123 LEFT: 37,
4124 PAGE_DOWN: 34,
4125 PAGE_UP: 33,
4126 PERIOD: 190,
4127 RIGHT: 39,
4128 SPACE: 32,
4129 TAB: 9,
4130 UP: 38
4131 };
4132
4133
4134
4135
4136 // Internal use only
4137 var escapeSelector = $.ui.escapeSelector = ( function() {
4138 var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
4139 return function( selector ) {
4140 return selector.replace( selectorEscape, "\\$1" );
4141 };
4142 } )();
4143
4144
4145 /*!
4146 * jQuery UI Labels 1.12.1
4147 * http://jqueryui.com
4148 *
4149 * Copyright jQuery Foundation and other contributors
4150 * Released under the MIT license.
4151 * http://jquery.org/license
4152 */
4153
4154 //>>label: labels
4155 //>>group: Core
4156 //>>description: Find all the labels associated with a given input
4157 //>>docs: http://api.jqueryui.com/labels/
4158
4159
4160
4161 var labels = $.fn.labels = function() {
4162 var ancestor, selector, id, labels, ancestors;
4163
4164 // Check control.labels first
4165 if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
4166 return this.pushStack( this[ 0 ].labels );
4167 }
4168
4169 // Support: IE <= 11, FF <= 37, Android <= 2.3 only
4170 // Above browsers do not support control.labels. Everything below is to support them
4171 // as well as document fragments. control.labels does not work on document fragments
4172 labels = this.eq( 0 ).parents( "label" );
4173
4174 // Look for the label based on the id
4175 id = this.attr( "id" );
4176 if ( id ) {
4177
4178 // We don't search against the document in case the element
4179 // is disconnected from the DOM
4180 ancestor = this.eq( 0 ).parents().last();
4181
4182 // Get a full set of top level ancestors
4183 ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
4184
4185 // Create a selector for the label based on the id
4186 selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
4187
4188 labels = labels.add( ancestors.find( selector ).addBack( selector ) );
4189
4190 }
4191
4192 // Return whatever we have found for labels
4193 return this.pushStack( labels );
4194 };
4195
4196
4197 /*!
4198 * jQuery UI Scroll Parent 1.12.1
4199 * http://jqueryui.com
4200 *
4201 * Copyright jQuery Foundation and other contributors
4202 * Released under the MIT license.
4203 * http://jquery.org/license
4204 */
4205
4206 //>>label: scrollParent
4207 //>>group: Core
4208 //>>description: Get the closest ancestor element that is scrollable.
4209 //>>docs: http://api.jqueryui.com/scrollParent/
4210
4211
4212
4213 var scrollParent = $.fn.scrollParent = function( includeHidden ) {
4214 var position = this.css( "position" ),
4215 excludeStaticParent = position === "absolute",
4216 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
4217 scrollParent = this.parents().filter( function() {
4218 var parent = $( this );
4219 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
4220 return false;
4221 }
4222 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
4223 parent.css( "overflow-x" ) );
4224 } ).eq( 0 );
4225
4226 return position === "fixed" || !scrollParent.length ?
4227 $( this[ 0 ].ownerDocument || document ) :
4228 scrollParent;
4229 };
4230
4231
4232 /*!
4233 * jQuery UI Tabbable 1.12.1
4234 * http://jqueryui.com
4235 *
4236 * Copyright jQuery Foundation and other contributors
4237 * Released under the MIT license.
4238 * http://jquery.org/license
4239 */
4240
4241 //>>label: :tabbable Selector
4242 //>>group: Core
4243 //>>description: Selects elements which can be tabbed to.
4244 //>>docs: http://api.jqueryui.com/tabbable-selector/
4245
4246
4247
4248 var tabbable = $.extend( $.expr[ ":" ], {
4249 tabbable: function( element ) {
4250 var tabIndex = $.attr( element, "tabindex" ),
4251 hasTabindex = tabIndex != null;
4252 return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
4253 }
4254 } );
4255
4256
4257 /*!
4258 * jQuery UI Unique ID 1.12.1
4259 * http://jqueryui.com
4260 *
4261 * Copyright jQuery Foundation and other contributors
4262 * Released under the MIT license.
4263 * http://jquery.org/license
4264 */
4265
4266 //>>label: uniqueId
4267 //>>group: Core
4268 //>>description: Functions to generate and remove uniqueId's
4269 //>>docs: http://api.jqueryui.com/uniqueId/
4270
4271
4272
4273 var uniqueId = $.fn.extend( {
4274 uniqueId: ( function() {
4275 var uuid = 0;
4276
4277 return function() {
4278 return this.each( function() {
4279 if ( !this.id ) {
4280 this.id = "ui-id-" + ( ++uuid );
4281 }
4282 } );
4283 };
4284 } )(),
4285
4286 removeUniqueId: function() {
4287 return this.each( function() {
4288 if ( /^ui-id-\d+$/.test( this.id ) ) {
4289 $( this ).removeAttr( "id" );
4290 }
4291 } );
4292 }
4293 } );
4294
4295
4296 /*!
4297 * jQuery UI Accordion 1.12.1
4298 * http://jqueryui.com
4299 *
4300 * Copyright jQuery Foundation and other contributors
4301 * Released under the MIT license.
4302 * http://jquery.org/license
4303 */
4304
4305 //>>label: Accordion
4306 //>>group: Widgets
4307 // jscs:disable maximumLineLength
4308 //>>description: Displays collapsible content panels for presenting information in a limited amount of space.
4309 // jscs:enable maximumLineLength
4310 //>>docs: http://api.jqueryui.com/accordion/
4311 //>>demos: http://jqueryui.com/accordion/
4312 //>>css.structure: ../../themes/base/core.css
4313 //>>css.structure: ../../themes/base/accordion.css
4314 //>>css.theme: ../../themes/base/theme.css
4315
4316
4317
4318 var widgetsAccordion = $.widget( "ui.accordion", {
4319 version: "1.12.1",
4320 options: {
4321 active: 0,
4322 animate: {},
4323 classes: {
4324 "ui-accordion-header": "ui-corner-top",
4325 "ui-accordion-header-collapsed": "ui-corner-all",
4326 "ui-accordion-content": "ui-corner-bottom"
4327 },
4328 collapsible: false,
4329 event: "click",
4330 header: "> li > :first-child, > :not(li):even",
4331 heightStyle: "auto",
4332 icons: {
4333 activeHeader: "ui-icon-triangle-1-s",
4334 header: "ui-icon-triangle-1-e"
4335 },
4336
4337 // Callbacks
4338 activate: null,
4339 beforeActivate: null
4340 },
4341
4342 hideProps: {
4343 borderTopWidth: "hide",
4344 borderBottomWidth: "hide",
4345 paddingTop: "hide",
4346 paddingBottom: "hide",
4347 height: "hide"
4348 },
4349
4350 showProps: {
4351 borderTopWidth: "show",
4352 borderBottomWidth: "show",
4353 paddingTop: "show",
4354 paddingBottom: "show",
4355 height: "show"
4356 },
4357
4358 _create: function() {
4359 var options = this.options;
4360
4361 this.prevShow = this.prevHide = $();
4362 this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
4363 this.element.attr( "role", "tablist" );
4364
4365 // Don't allow collapsible: false and active: false / null
4366 if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
4367 options.active = 0;
4368 }
4369
4370 this._processPanels();
4371
4372 // handle negative values
4373 if ( options.active < 0 ) {
4374 options.active += this.headers.length;
4375 }
4376 this._refresh();
4377 },
4378
4379 _getCreateEventData: function() {
4380 return {
4381 header: this.active,
4382 panel: !this.active.length ? $() : this.active.next()
4383 };
4384 },
4385
4386 _createIcons: function() {
4387 var icon, children,
4388 icons = this.options.icons;
4389
4390 if ( icons ) {
4391 icon = $( "<span>" );
4392 this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
4393 icon.prependTo( this.headers );
4394 children = this.active.children( ".ui-accordion-header-icon" );
4395 this._removeClass( children, icons.header )
4396 ._addClass( children, null, icons.activeHeader )
4397 ._addClass( this.headers, "ui-accordion-icons" );
4398 }
4399 },
4400
4401 _destroyIcons: function() {
4402 this._removeClass( this.headers, "ui-accordion-icons" );
4403 this.headers.children( ".ui-accordion-header-icon" ).remove();
4404 },
4405
4406 _destroy: function() {
4407 var contents;
4408
4409 // Clean up main element
4410 this.element.removeAttr( "role" );
4411
4412 // Clean up headers
4413 this.headers
4414 .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
4415 .removeUniqueId();
4416
4417 this._destroyIcons();
4418
4419 // Clean up content panels
4420 contents = this.headers.next()
4421 .css( "display", "" )
4422 .removeAttr( "role aria-hidden aria-labelledby" )
4423 .removeUniqueId();
4424
4425 if ( this.options.heightStyle !== "content" ) {
4426 contents.css( "height", "" );
4427 }
4428 },
4429
4430 _setOption: function( key, value ) {
4431 if ( key === "active" ) {
4432
4433 // _activate() will handle invalid values and update this.options
4434 this._activate( value );
4435 return;
4436 }
4437
4438 if ( key === "event" ) {
4439 if ( this.options.event ) {
4440 this._off( this.headers, this.options.event );
4441 }
4442 this._setupEvents( value );
4443 }
4444
4445 this._super( key, value );
4446
4447 // Setting collapsible: false while collapsed; open first panel
4448 if ( key === "collapsible" && !value && this.options.active === false ) {
4449 this._activate( 0 );
4450 }
4451
4452 if ( key === "icons" ) {
4453 this._destroyIcons();
4454 if ( value ) {
4455 this._createIcons();
4456 }
4457 }
4458 },
4459
4460 _setOptionDisabled: function( value ) {
4461 this._super( value );
4462
4463 this.element.attr( "aria-disabled", value );
4464
4465 // Support: IE8 Only
4466 // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
4467 // so we need to add the disabled class to the headers and panels
4468 this._toggleClass( null, "ui-state-disabled", !!value );
4469 this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
4470 !!value );
4471 },
4472
4473 _keydown: function( event ) {
4474 if ( event.altKey || event.ctrlKey ) {
4475 return;
4476 }
4477
4478 var keyCode = $.ui.keyCode,
4479 length = this.headers.length,
4480 currentIndex = this.headers.index( event.target ),
4481 toFocus = false;
4482
4483 switch ( event.keyCode ) {
4484 case keyCode.RIGHT:
4485 case keyCode.DOWN:
4486 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
4487 break;
4488 case keyCode.LEFT:
4489 case keyCode.UP:
4490 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
4491 break;
4492 case keyCode.SPACE:
4493 case keyCode.ENTER:
4494 this._eventHandler( event );
4495 break;
4496 case keyCode.HOME:
4497 toFocus = this.headers[ 0 ];
4498 break;
4499 case keyCode.END:
4500 toFocus = this.headers[ length - 1 ];
4501 break;
4502 }
4503
4504 if ( toFocus ) {
4505 $( event.target ).attr( "tabIndex", -1 );
4506 $( toFocus ).attr( "tabIndex", 0 );
4507 $( toFocus ).trigger( "focus" );
4508 event.preventDefault();
4509 }
4510 },
4511
4512 _panelKeyDown: function( event ) {
4513 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
4514 $( event.currentTarget ).prev().trigger( "focus" );
4515 }
4516 },
4517
4518 refresh: function() {
4519 var options = this.options;
4520 this._processPanels();
4521
4522 // Was collapsed or no panel
4523 if ( ( options.active === false && options.collapsible === true ) ||
4524 !this.headers.length ) {
4525 options.active = false;
4526 this.active = $();
4527
4528 // active false only when collapsible is true
4529 } else if ( options.active === false ) {
4530 this._activate( 0 );
4531
4532 // was active, but active panel is gone
4533 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
4534
4535 // all remaining panel are disabled
4536 if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
4537 options.active = false;
4538 this.active = $();
4539
4540 // activate previous panel
4541 } else {
4542 this._activate( Math.max( 0, options.active - 1 ) );
4543 }
4544
4545 // was active, active panel still exists
4546 } else {
4547
4548 // make sure active index is correct
4549 options.active = this.headers.index( this.active );
4550 }
4551
4552 this._destroyIcons();
4553
4554 this._refresh();
4555 },
4556
4557 _processPanels: function() {
4558 var prevHeaders = this.headers,
4559 prevPanels = this.panels;
4560
4561 this.headers = this.element.find( this.options.header );
4562 this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
4563 "ui-state-default" );
4564
4565 this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
4566 this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
4567
4568 // Avoid memory leaks (#10056)
4569 if ( prevPanels ) {
4570 this._off( prevHeaders.not( this.headers ) );
4571 this._off( prevPanels.not( this.panels ) );
4572 }
4573 },
4574
4575 _refresh: function() {
4576 var maxHeight,
4577 options = this.options,
4578 heightStyle = options.heightStyle,
4579 parent = this.element.parent();
4580
4581 this.active = this._findActive( options.active );
4582 this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
4583 ._removeClass( this.active, "ui-accordion-header-collapsed" );
4584 this._addClass( this.active.next(), "ui-accordion-content-active" );
4585 this.active.next().show();
4586
4587 this.headers
4588 .attr( "role", "tab" )
4589 .each( function() {
4590 var header = $( this ),
4591 headerId = header.uniqueId().attr( "id" ),
4592 panel = header.next(),
4593 panelId = panel.uniqueId().attr( "id" );
4594 header.attr( "aria-controls", panelId );
4595 panel.attr( "aria-labelledby", headerId );
4596 } )
4597 .next()
4598 .attr( "role", "tabpanel" );
4599
4600 this.headers
4601 .not( this.active )
4602 .attr( {
4603 "aria-selected": "false",
4604 "aria-expanded": "false",
4605 tabIndex: -1
4606 } )
4607 .next()
4608 .attr( {
4609 "aria-hidden": "true"
4610 } )
4611 .hide();
4612
4613 // Make sure at least one header is in the tab order
4614 if ( !this.active.length ) {
4615 this.headers.eq( 0 ).attr( "tabIndex", 0 );
4616 } else {
4617 this.active.attr( {
4618 "aria-selected": "true",
4619 "aria-expanded": "true",
4620 tabIndex: 0
4621 } )
4622 .next()
4623 .attr( {
4624 "aria-hidden": "false"
4625 } );
4626 }
4627
4628 this._createIcons();
4629
4630 this._setupEvents( options.event );
4631
4632 if ( heightStyle === "fill" ) {
4633 maxHeight = parent.height();
4634 this.element.siblings( ":visible" ).each( function() {
4635 var elem = $( this ),
4636 position = elem.css( "position" );
4637
4638 if ( position === "absolute" || position === "fixed" ) {
4639 return;
4640 }
4641 maxHeight -= elem.outerHeight( true );
4642 } );
4643
4644 this.headers.each( function() {
4645 maxHeight -= $( this ).outerHeight( true );
4646 } );
4647
4648 this.headers.next()
4649 .each( function() {
4650 $( this ).height( Math.max( 0, maxHeight -
4651 $( this ).innerHeight() + $( this ).height() ) );
4652 } )
4653 .css( "overflow", "auto" );
4654 } else if ( heightStyle === "auto" ) {
4655 maxHeight = 0;
4656 this.headers.next()
4657 .each( function() {
4658 var isVisible = $( this ).is( ":visible" );
4659 if ( !isVisible ) {
4660 $( this ).show();
4661 }
4662 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
4663 if ( !isVisible ) {
4664 $( this ).hide();
4665 }
4666 } )
4667 .height( maxHeight );
4668 }
4669 },
4670
4671 _activate: function( index ) {
4672 var active = this._findActive( index )[ 0 ];
4673
4674 // Trying to activate the already active panel
4675 if ( active === this.active[ 0 ] ) {
4676 return;
4677 }
4678
4679 // Trying to collapse, simulate a click on the currently active header
4680 active = active || this.active[ 0 ];
4681
4682 this._eventHandler( {
4683 target: active,
4684 currentTarget: active,
4685 preventDefault: $.noop
4686 } );
4687 },
4688
4689 _findActive: function( selector ) {
4690 return typeof selector === "number" ? this.headers.eq( selector ) : $();
4691 },
4692
4693 _setupEvents: function( event ) {
4694 var events = {
4695 keydown: "_keydown"
4696 };
4697 if ( event ) {
4698 $.each( event.split( " " ), function( index, eventName ) {
4699 events[ eventName ] = "_eventHandler";
4700 } );
4701 }
4702
4703 this._off( this.headers.add( this.headers.next() ) );
4704 this._on( this.headers, events );
4705 this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
4706 this._hoverable( this.headers );
4707 this._focusable( this.headers );
4708 },
4709
4710 _eventHandler: function( event ) {
4711 var activeChildren, clickedChildren,
4712 options = this.options,
4713 active = this.active,
4714 clicked = $( event.currentTarget ),
4715 clickedIsActive = clicked[ 0 ] === active[ 0 ],
4716 collapsing = clickedIsActive && options.collapsible,
4717 toShow = collapsing ? $() : clicked.next(),
4718 toHide = active.next(),
4719 eventData = {
4720 oldHeader: active,
4721 oldPanel: toHide,
4722 newHeader: collapsing ? $() : clicked,
4723 newPanel: toShow
4724 };
4725
4726 event.preventDefault();
4727
4728 if (
4729
4730 // click on active header, but not collapsible
4731 ( clickedIsActive && !options.collapsible ) ||
4732
4733 // allow canceling activation
4734 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
4735 return;
4736 }
4737
4738 options.active = collapsing ? false : this.headers.index( clicked );
4739
4740 // When the call to ._toggle() comes after the class changes
4741 // it causes a very odd bug in IE 8 (see #6720)
4742 this.active = clickedIsActive ? $() : clicked;
4743 this._toggle( eventData );
4744
4745 // Switch classes
4746 // corner classes on the previously active header stay after the animation
4747 this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
4748 if ( options.icons ) {
4749 activeChildren = active.children( ".ui-accordion-header-icon" );
4750 this._removeClass( activeChildren, null, options.icons.activeHeader )
4751 ._addClass( activeChildren, null, options.icons.header );
4752 }
4753
4754 if ( !clickedIsActive ) {
4755 this._removeClass( clicked, "ui-accordion-header-collapsed" )
4756 ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
4757 if ( options.icons ) {
4758 clickedChildren = clicked.children( ".ui-accordion-header-icon" );
4759 this._removeClass( clickedChildren, null, options.icons.header )
4760 ._addClass( clickedChildren, null, options.icons.activeHeader );
4761 }
4762
4763 this._addClass( clicked.next(), "ui-accordion-content-active" );
4764 }
4765 },
4766
4767 _toggle: function( data ) {
4768 var toShow = data.newPanel,
4769 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
4770
4771 // Handle activating a panel during the animation for another activation
4772 this.prevShow.add( this.prevHide ).stop( true, true );
4773 this.prevShow = toShow;
4774 this.prevHide = toHide;
4775
4776 if ( this.options.animate ) {
4777 this._animate( toShow, toHide, data );
4778 } else {
4779 toHide.hide();
4780 toShow.show();
4781 this._toggleComplete( data );
4782 }
4783
4784 toHide.attr( {
4785 "aria-hidden": "true"
4786 } );
4787 toHide.prev().attr( {
4788 "aria-selected": "false",
4789 "aria-expanded": "false"
4790 } );
4791
4792 // if we're switching panels, remove the old header from the tab order
4793 // if we're opening from collapsed state, remove the previous header from the tab order
4794 // if we're collapsing, then keep the collapsing header in the tab order
4795 if ( toShow.length && toHide.length ) {
4796 toHide.prev().attr( {
4797 "tabIndex": -1,
4798 "aria-expanded": "false"
4799 } );
4800 } else if ( toShow.length ) {
4801 this.headers.filter( function() {
4802 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
4803 } )
4804 .attr( "tabIndex", -1 );
4805 }
4806
4807 toShow
4808 .attr( "aria-hidden", "false" )
4809 .prev()
4810 .attr( {
4811 "aria-selected": "true",
4812 "aria-expanded": "true",
4813 tabIndex: 0
4814 } );
4815 },
4816
4817 _animate: function( toShow, toHide, data ) {
4818 var total, easing, duration,
4819 that = this,
4820 adjust = 0,
4821 boxSizing = toShow.css( "box-sizing" ),
4822 down = toShow.length &&
4823 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
4824 animate = this.options.animate || {},
4825 options = down && animate.down || animate,
4826 complete = function() {
4827 that._toggleComplete( data );
4828 };
4829
4830 if ( typeof options === "number" ) {
4831 duration = options;
4832 }
4833 if ( typeof options === "string" ) {
4834 easing = options;
4835 }
4836
4837 // fall back from options to animation in case of partial down settings
4838 easing = easing || options.easing || animate.easing;
4839 duration = duration || options.duration || animate.duration;
4840
4841 if ( !toHide.length ) {
4842 return toShow.animate( this.showProps, duration, easing, complete );
4843 }
4844 if ( !toShow.length ) {
4845 return toHide.animate( this.hideProps, duration, easing, complete );
4846 }
4847
4848 total = toShow.show().outerHeight();
4849 toHide.animate( this.hideProps, {
4850 duration: duration,
4851 easing: easing,
4852 step: function( now, fx ) {
4853 fx.now = Math.round( now );
4854 }
4855 } );
4856 toShow
4857 .hide()
4858 .animate( this.showProps, {
4859 duration: duration,
4860 easing: easing,
4861 complete: complete,
4862 step: function( now, fx ) {
4863 fx.now = Math.round( now );
4864 if ( fx.prop !== "height" ) {
4865 if ( boxSizing === "content-box" ) {
4866 adjust += fx.now;
4867 }
4868 } else if ( that.options.heightStyle !== "content" ) {
4869 fx.now = Math.round( total - toHide.outerHeight() - adjust );
4870 adjust = 0;
4871 }
4872 }
4873 } );
4874 },
4875
4876 _toggleComplete: function( data ) {
4877 var toHide = data.oldPanel,
4878 prev = toHide.prev();
4879
4880 this._removeClass( toHide, "ui-accordion-content-active" );
4881 this._removeClass( prev, "ui-accordion-header-active" )
4882 ._addClass( prev, "ui-accordion-header-collapsed" );
4883
4884 // Work around for rendering bug in IE (#5421)
4885 if ( toHide.length ) {
4886 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
4887 }
4888 this._trigger( "activate", null, data );
4889 }
4890 } );
4891
4892
4893
4894 var safeActiveElement = $.ui.safeActiveElement = function( document ) {
4895 var activeElement;
4896
4897 // Support: IE 9 only
4898 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
4899 try {
4900 activeElement = document.activeElement;
4901 } catch ( error ) {
4902 activeElement = document.body;
4903 }
4904
4905 // Support: IE 9 - 11 only
4906 // IE may return null instead of an element
4907 // Interestingly, this only seems to occur when NOT in an iframe
4908 if ( !activeElement ) {
4909 activeElement = document.body;
4910 }
4911
4912 // Support: IE 11 only
4913 // IE11 returns a seemingly empty object in some cases when accessing
4914 // document.activeElement from an <iframe>
4915 if ( !activeElement.nodeName ) {
4916 activeElement = document.body;
4917 }
4918
4919 return activeElement;
4920 };
4921
4922
4923 /*!
4924 * jQuery UI Menu 1.12.1
4925 * http://jqueryui.com
4926 *
4927 * Copyright jQuery Foundation and other contributors
4928 * Released under the MIT license.
4929 * http://jquery.org/license
4930 */
4931
4932 //>>label: Menu
4933 //>>group: Widgets
4934 //>>description: Creates nestable menus.
4935 //>>docs: http://api.jqueryui.com/menu/
4936 //>>demos: http://jqueryui.com/menu/
4937 //>>css.structure: ../../themes/base/core.css
4938 //>>css.structure: ../../themes/base/menu.css
4939 //>>css.theme: ../../themes/base/theme.css
4940
4941
4942
4943 var widgetsMenu = $.widget( "ui.menu", {
4944 version: "1.12.1",
4945 defaultElement: "<ul>",
4946 delay: 300,
4947 options: {
4948 icons: {
4949 submenu: "ui-icon-caret-1-e"
4950 },
4951 items: "> *",
4952 menus: "ul",
4953 position: {
4954 my: "left top",
4955 at: "right top"
4956 },
4957 role: "menu",
4958
4959 // Callbacks
4960 blur: null,
4961 focus: null,
4962 select: null
4963 },
4964
4965 _create: function() {
4966 this.activeMenu = this.element;
4967
4968 // Flag used to prevent firing of the click handler
4969 // as the event bubbles up through nested menus
4970 this.mouseHandled = false;
4971 this.element
4972 .uniqueId()
4973 .attr( {
4974 role: this.options.role,
4975 tabIndex: 0
4976 } );
4977
4978 this._addClass( "ui-menu", "ui-widget ui-widget-content" );
4979 this._on( {
4980
4981 // Prevent focus from sticking to links inside menu after clicking
4982 // them (focus should always stay on UL during navigation).
4983 "mousedown .ui-menu-item": function( event ) {
4984 event.preventDefault();
4985 },
4986 "click .ui-menu-item": function( event ) {
4987 var target = $( event.target );
4988 var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
4989 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
4990 this.select( event );
4991
4992 // Only set the mouseHandled flag if the event will bubble, see #9469.
4993 if ( !event.isPropagationStopped() ) {
4994 this.mouseHandled = true;
4995 }
4996
4997 // Open submenu on click
4998 if ( target.has( ".ui-menu" ).length ) {
4999 this.expand( event );
5000 } else if ( !this.element.is( ":focus" ) &&
5001 active.closest( ".ui-menu" ).length ) {
5002
5003 // Redirect focus to the menu
5004 this.element.trigger( "focus", [ true ] );
5005
5006 // If the active item is on the top level, let it stay active.
5007 // Otherwise, blur the active item since it is no longer visible.
5008 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
5009 clearTimeout( this.timer );
5010 }
5011 }
5012 }
5013 },
5014 "mouseenter .ui-menu-item": function( event ) {
5015
5016 // Ignore mouse events while typeahead is active, see #10458.
5017 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
5018 // is over an item in the menu
5019 if ( this.previousFilter ) {
5020 return;
5021 }
5022
5023 var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
5024 target = $( event.currentTarget );
5025
5026 // Ignore bubbled events on parent items, see #11641
5027 if ( actualTarget[ 0 ] !== target[ 0 ] ) {
5028 return;
5029 }
5030
5031 // Remove ui-state-active class from siblings of the newly focused menu item
5032 // to avoid a jump caused by adjacent elements both having a class with a border
5033 this._removeClass( target.siblings().children( ".ui-state-active" ),
5034 null, "ui-state-active" );
5035 this.focus( event, target );
5036 },
5037 mouseleave: "collapseAll",
5038 "mouseleave .ui-menu": "collapseAll",
5039 focus: function( event, keepActiveItem ) {
5040
5041 // If there's already an active item, keep it active
5042 // If not, activate the first item
5043 var item = this.active || this.element.find( this.options.items ).eq( 0 );
5044
5045 if ( !keepActiveItem ) {
5046 this.focus( event, item );
5047 }
5048 },
5049 blur: function( event ) {
5050 this._delay( function() {
5051 var notContained = !$.contains(
5052 this.element[ 0 ],
5053 $.ui.safeActiveElement( this.document[ 0 ] )
5054 );
5055 if ( notContained ) {
5056 this.collapseAll( event );
5057 }
5058 } );
5059 },
5060 keydown: "_keydown"
5061 } );
5062
5063 this.refresh();
5064
5065 // Clicks outside of a menu collapse any open menus
5066 this._on( this.document, {
5067 click: function( event ) {
5068 if ( this._closeOnDocumentClick( event ) ) {
5069 this.collapseAll( event );
5070 }
5071
5072 // Reset the mouseHandled flag
5073 this.mouseHandled = false;
5074 }
5075 } );
5076 },
5077
5078 _destroy: function() {
5079 var items = this.element.find( ".ui-menu-item" )
5080 .removeAttr( "role aria-disabled" ),
5081 submenus = items.children( ".ui-menu-item-wrapper" )
5082 .removeUniqueId()
5083 .removeAttr( "tabIndex role aria-haspopup" );
5084
5085 // Destroy (sub)menus
5086 this.element
5087 .removeAttr( "aria-activedescendant" )
5088 .find( ".ui-menu" ).addBack()
5089 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
5090 "tabIndex" )
5091 .removeUniqueId()
5092 .show();
5093
5094 submenus.children().each( function() {
5095 var elem = $( this );
5096 if ( elem.data( "ui-menu-submenu-caret" ) ) {
5097 elem.remove();
5098 }
5099 } );
5100 },
5101
5102 _keydown: function( event ) {
5103 var match, prev, character, skip,
5104 preventDefault = true;
5105
5106 switch ( event.keyCode ) {
5107 case $.ui.keyCode.PAGE_UP:
5108 this.previousPage( event );
5109 break;
5110 case $.ui.keyCode.PAGE_DOWN:
5111 this.nextPage( event );
5112 break;
5113 case $.ui.keyCode.HOME:
5114 this._move( "first", "first", event );
5115 break;
5116 case $.ui.keyCode.END:
5117 this._move( "last", "last", event );
5118 break;
5119 case $.ui.keyCode.UP:
5120 this.previous( event );
5121 break;
5122 case $.ui.keyCode.DOWN:
5123 this.next( event );
5124 break;
5125 case $.ui.keyCode.LEFT:
5126 this.collapse( event );
5127 break;
5128 case $.ui.keyCode.RIGHT:
5129 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5130 this.expand( event );
5131 }
5132 break;
5133 case $.ui.keyCode.ENTER:
5134 case $.ui.keyCode.SPACE:
5135 this._activate( event );
5136 break;
5137 case $.ui.keyCode.ESCAPE:
5138 this.collapse( event );
5139 break;
5140 default:
5141 preventDefault = false;
5142 prev = this.previousFilter || "";
5143 skip = false;
5144
5145 // Support number pad values
5146 character = event.keyCode >= 96 && event.keyCode <= 105 ?
5147 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
5148
5149 clearTimeout( this.filterTimer );
5150
5151 if ( character === prev ) {
5152 skip = true;
5153 } else {
5154 character = prev + character;
5155 }
5156
5157 match = this._filterMenuItems( character );
5158 match = skip && match.index( this.active.next() ) !== -1 ?
5159 this.active.nextAll( ".ui-menu-item" ) :
5160 match;
5161
5162 // If no matches on the current filter, reset to the last character pressed
5163 // to move down the menu to the first item that starts with that character
5164 if ( !match.length ) {
5165 character = String.fromCharCode( event.keyCode );
5166 match = this._filterMenuItems( character );
5167 }
5168
5169 if ( match.length ) {
5170 this.focus( event, match );
5171 this.previousFilter = character;
5172 this.filterTimer = this._delay( function() {
5173 delete this.previousFilter;
5174 }, 1000 );
5175 } else {
5176 delete this.previousFilter;
5177 }
5178 }
5179
5180 if ( preventDefault ) {
5181 event.preventDefault();
5182 }
5183 },
5184
5185 _activate: function( event ) {
5186 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
5187 if ( this.active.children( "[aria-haspopup='true']" ).length ) {
5188 this.expand( event );
5189 } else {
5190 this.select( event );
5191 }
5192 }
5193 },
5194
5195 refresh: function() {
5196 var menus, items, newSubmenus, newItems, newWrappers,
5197 that = this,
5198 icon = this.options.icons.submenu,
5199 submenus = this.element.find( this.options.menus );
5200
5201 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
5202
5203 // Initialize nested menus
5204 newSubmenus = submenus.filter( ":not(.ui-menu)" )
5205 .hide()
5206 .attr( {
5207 role: this.options.role,
5208 "aria-hidden": "true",
5209 "aria-expanded": "false"
5210 } )
5211 .each( function() {
5212 var menu = $( this ),
5213 item = menu.prev(),
5214 submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
5215
5216 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
5217 item
5218 .attr( "aria-haspopup", "true" )
5219 .prepend( submenuCaret );
5220 menu.attr( "aria-labelledby", item.attr( "id" ) );
5221 } );
5222
5223 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
5224
5225 menus = submenus.add( this.element );
5226 items = menus.find( this.options.items );
5227
5228 // Initialize menu-items containing spaces and/or dashes only as dividers
5229 items.not( ".ui-menu-item" ).each( function() {
5230 var item = $( this );
5231 if ( that._isDivider( item ) ) {
5232 that._addClass( item, "ui-menu-divider", "ui-widget-content" );
5233 }
5234 } );
5235
5236 // Don't refresh list items that are already adapted
5237 newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
5238 newWrappers = newItems.children()
5239 .not( ".ui-menu" )
5240 .uniqueId()
5241 .attr( {
5242 tabIndex: -1,
5243 role: this._itemRole()
5244 } );
5245 this._addClass( newItems, "ui-menu-item" )
5246 ._addClass( newWrappers, "ui-menu-item-wrapper" );
5247
5248 // Add aria-disabled attribute to any disabled menu item
5249 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
5250
5251 // If the active item has been removed, blur the menu
5252 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
5253 this.blur();
5254 }
5255 },
5256
5257 _itemRole: function() {
5258 return {
5259 menu: "menuitem",
5260 listbox: "option"
5261 }[ this.options.role ];
5262 },
5263
5264 _setOption: function( key, value ) {
5265 if ( key === "icons" ) {
5266 var icons = this.element.find( ".ui-menu-icon" );
5267 this._removeClass( icons, null, this.options.icons.submenu )
5268 ._addClass( icons, null, value.submenu );
5269 }
5270 this._super( key, value );
5271 },
5272
5273 _setOptionDisabled: function( value ) {
5274 this._super( value );
5275
5276 this.element.attr( "aria-disabled", String( value ) );
5277 this._toggleClass( null, "ui-state-disabled", !!value );
5278 },
5279
5280 focus: function( event, item ) {
5281 var nested, focused, activeParent;
5282 this.blur( event, event && event.type === "focus" );
5283
5284 this._scrollIntoView( item );
5285
5286 this.active = item.first();
5287
5288 focused = this.active.children( ".ui-menu-item-wrapper" );
5289 this._addClass( focused, null, "ui-state-active" );
5290
5291 // Only update aria-activedescendant if there's a role
5292 // otherwise we assume focus is managed elsewhere
5293 if ( this.options.role ) {
5294 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
5295 }
5296
5297 // Highlight active parent menu item, if any
5298 activeParent = this.active
5299 .parent()
5300 .closest( ".ui-menu-item" )
5301 .children( ".ui-menu-item-wrapper" );
5302 this._addClass( activeParent, null, "ui-state-active" );
5303
5304 if ( event && event.type === "keydown" ) {
5305 this._close();
5306 } else {
5307 this.timer = this._delay( function() {
5308 this._close();
5309 }, this.delay );
5310 }
5311
5312 nested = item.children( ".ui-menu" );
5313 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
5314 this._startOpening( nested );
5315 }
5316 this.activeMenu = item.parent();
5317
5318 this._trigger( "focus", event, { item: item } );
5319 },
5320
5321 _scrollIntoView: function( item ) {
5322 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
5323 if ( this._hasScroll() ) {
5324 borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
5325 paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
5326 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
5327 scroll = this.activeMenu.scrollTop();
5328 elementHeight = this.activeMenu.height();
5329 itemHeight = item.outerHeight();
5330
5331 if ( offset < 0 ) {
5332 this.activeMenu.scrollTop( scroll + offset );
5333 } else if ( offset + itemHeight > elementHeight ) {
5334 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
5335 }
5336 }
5337 },
5338
5339 blur: function( event, fromFocus ) {
5340 if ( !fromFocus ) {
5341 clearTimeout( this.timer );
5342 }
5343
5344 if ( !this.active ) {
5345 return;
5346 }
5347
5348 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
5349 null, "ui-state-active" );
5350
5351 this._trigger( "blur", event, { item: this.active } );
5352 this.active = null;
5353 },
5354
5355 _startOpening: function( submenu ) {
5356 clearTimeout( this.timer );
5357
5358 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
5359 // shift in the submenu position when mousing over the caret icon
5360 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
5361 return;
5362 }
5363
5364 this.timer = this._delay( function() {
5365 this._close();
5366 this._open( submenu );
5367 }, this.delay );
5368 },
5369
5370 _open: function( submenu ) {
5371 var position = $.extend( {
5372 of: this.active
5373 }, this.options.position );
5374
5375 clearTimeout( this.timer );
5376 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
5377 .hide()
5378 .attr( "aria-hidden", "true" );
5379
5380 submenu
5381 .show()
5382 .removeAttr( "aria-hidden" )
5383 .attr( "aria-expanded", "true" )
5384 .position( position );
5385 },
5386
5387 collapseAll: function( event, all ) {
5388 clearTimeout( this.timer );
5389 this.timer = this._delay( function() {
5390
5391 // If we were passed an event, look for the submenu that contains the event
5392 var currentMenu = all ? this.element :
5393 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
5394
5395 // If we found no valid submenu ancestor, use the main menu to close all
5396 // sub menus anyway
5397 if ( !currentMenu.length ) {
5398 currentMenu = this.element;
5399 }
5400
5401 this._close( currentMenu );
5402
5403 this.blur( event );
5404
5405 // Work around active item staying active after menu is blurred
5406 this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
5407
5408 this.activeMenu = currentMenu;
5409 }, this.delay );
5410 },
5411
5412 // With no arguments, closes the currently active menu - if nothing is active
5413 // it closes all menus. If passed an argument, it will search for menus BELOW
5414 _close: function( startMenu ) {
5415 if ( !startMenu ) {
5416 startMenu = this.active ? this.active.parent() : this.element;
5417 }
5418
5419 startMenu.find( ".ui-menu" )
5420 .hide()
5421 .attr( "aria-hidden", "true" )
5422 .attr( "aria-expanded", "false" );
5423 },
5424
5425 _closeOnDocumentClick: function( event ) {
5426 return !$( event.target ).closest( ".ui-menu" ).length;
5427 },
5428
5429 _isDivider: function( item ) {
5430
5431 // Match hyphen, em dash, en dash
5432 return !/[^\-\u2014\u2013\s]/.test( item.text() );
5433 },
5434
5435 collapse: function( event ) {
5436 var newItem = this.active &&
5437 this.active.parent().closest( ".ui-menu-item", this.element );
5438 if ( newItem && newItem.length ) {
5439 this._close();
5440 this.focus( event, newItem );
5441 }
5442 },
5443
5444 expand: function( event ) {
5445 var newItem = this.active &&
5446 this.active
5447 .children( ".ui-menu " )
5448 .find( this.options.items )
5449 .first();
5450
5451 if ( newItem && newItem.length ) {
5452 this._open( newItem.parent() );
5453
5454 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
5455 this._delay( function() {
5456 this.focus( event, newItem );
5457 } );
5458 }
5459 },
5460
5461 next: function( event ) {
5462 this._move( "next", "first", event );
5463 },
5464
5465 previous: function( event ) {
5466 this._move( "prev", "last", event );
5467 },
5468
5469 isFirstItem: function() {
5470 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
5471 },
5472
5473 isLastItem: function() {
5474 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
5475 },
5476
5477 _move: function( direction, filter, event ) {
5478 var next;
5479 if ( this.active ) {
5480 if ( direction === "first" || direction === "last" ) {
5481 next = this.active
5482 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
5483 .eq( -1 );
5484 } else {
5485 next = this.active
5486 [ direction + "All" ]( ".ui-menu-item" )
5487 .eq( 0 );
5488 }
5489 }
5490 if ( !next || !next.length || !this.active ) {
5491 next = this.activeMenu.find( this.options.items )[ filter ]();
5492 }
5493
5494 this.focus( event, next );
5495 },
5496
5497 nextPage: function( event ) {
5498 var item, base, height;
5499
5500 if ( !this.active ) {
5501 this.next( event );
5502 return;
5503 }
5504 if ( this.isLastItem() ) {
5505 return;
5506 }
5507 if ( this._hasScroll() ) {
5508 base = this.active.offset().top;
5509 height = this.element.height();
5510 this.active.nextAll( ".ui-menu-item" ).each( function() {
5511 item = $( this );
5512 return item.offset().top - base - height < 0;
5513 } );
5514
5515 this.focus( event, item );
5516 } else {
5517 this.focus( event, this.activeMenu.find( this.options.items )
5518 [ !this.active ? "first" : "last" ]() );
5519 }
5520 },
5521
5522 previousPage: function( event ) {
5523 var item, base, height;
5524 if ( !this.active ) {
5525 this.next( event );
5526 return;
5527 }
5528 if ( this.isFirstItem() ) {
5529 return;
5530 }
5531 if ( this._hasScroll() ) {
5532 base = this.active.offset().top;
5533 height = this.element.height();
5534 this.active.prevAll( ".ui-menu-item" ).each( function() {
5535 item = $( this );
5536 return item.offset().top - base + height > 0;
5537 } );
5538
5539 this.focus( event, item );
5540 } else {
5541 this.focus( event, this.activeMenu.find( this.options.items ).first() );
5542 }
5543 },
5544
5545 _hasScroll: function() {
5546 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
5547 },
5548
5549 select: function( event ) {
5550
5551 // TODO: It should never be possible to not have an active item at this
5552 // point, but the tests don't trigger mouseenter before click.
5553 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
5554 var ui = { item: this.active };
5555 if ( !this.active.has( ".ui-menu" ).length ) {
5556 this.collapseAll( event, true );
5557 }
5558 this._trigger( "select", event, ui );
5559 },
5560
5561 _filterMenuItems: function( character ) {
5562 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
5563 regex = new RegExp( "^" + escapedCharacter, "i" );
5564
5565 return this.activeMenu
5566 .find( this.options.items )
5567
5568 // Only match on items, not dividers or other content (#10571)
5569 .filter( ".ui-menu-item" )
5570 .filter( function() {
5571 return regex.test(
5572 $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
5573 } );
5574 }
5575 } );
5576
5577
5578 /*!
5579 * jQuery UI Autocomplete 1.12.1
5580 * http://jqueryui.com
5581 *
5582 * Copyright jQuery Foundation and other contributors
5583 * Released under the MIT license.
5584 * http://jquery.org/license
5585 */
5586
5587 //>>label: Autocomplete
5588 //>>group: Widgets
5589 //>>description: Lists suggested words as the user is typing.
5590 //>>docs: http://api.jqueryui.com/autocomplete/
5591 //>>demos: http://jqueryui.com/autocomplete/
5592 //>>css.structure: ../../themes/base/core.css
5593 //>>css.structure: ../../themes/base/autocomplete.css
5594 //>>css.theme: ../../themes/base/theme.css
5595
5596
5597
5598 $.widget( "ui.autocomplete", {
5599 version: "1.12.1",
5600 defaultElement: "<input>",
5601 options: {
5602 appendTo: null,
5603 autoFocus: false,
5604 delay: 300,
5605 minLength: 1,
5606 position: {
5607 my: "left top",
5608 at: "left bottom",
5609 collision: "none"
5610 },
5611 source: null,
5612
5613 // Callbacks
5614 change: null,
5615 close: null,
5616 focus: null,
5617 open: null,
5618 response: null,
5619 search: null,
5620 select: null
5621 },
5622
5623 requestIndex: 0,
5624 pending: 0,
5625
5626 _create: function() {
5627
5628 // Some browsers only repeat keydown events, not keypress events,
5629 // so we use the suppressKeyPress flag to determine if we've already
5630 // handled the keydown event. #7269
5631 // Unfortunately the code for & in keypress is the same as the up arrow,
5632 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
5633 // events when we know the keydown event was used to modify the
5634 // search term. #7799
5635 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
5636 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
5637 isTextarea = nodeName === "textarea",
5638 isInput = nodeName === "input";
5639
5640 // Textareas are always multi-line
5641 // Inputs are always single-line, even if inside a contentEditable element
5642 // IE also treats inputs as contentEditable
5643 // All other element types are determined by whether or not they're contentEditable
5644 this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
5645
5646 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
5647 this.isNewMenu = true;
5648
5649 this._addClass( "ui-autocomplete-input" );
5650 this.element.attr( "autocomplete", "off" );
5651
5652 this._on( this.element, {
5653 keydown: function( event ) {
5654 if ( this.element.prop( "readOnly" ) ) {
5655 suppressKeyPress = true;
5656 suppressInput = true;
5657 suppressKeyPressRepeat = true;
5658 return;
5659 }
5660
5661 suppressKeyPress = false;
5662 suppressInput = false;
5663 suppressKeyPressRepeat = false;
5664 var keyCode = $.ui.keyCode;
5665 switch ( event.keyCode ) {
5666 case keyCode.PAGE_UP:
5667 suppressKeyPress = true;
5668 this._move( "previousPage", event );
5669 break;
5670 case keyCode.PAGE_DOWN:
5671 suppressKeyPress = true;
5672 this._move( "nextPage", event );
5673 break;
5674 case keyCode.UP:
5675 suppressKeyPress = true;
5676 this._keyEvent( "previous", event );
5677 break;
5678 case keyCode.DOWN:
5679 suppressKeyPress = true;
5680 this._keyEvent( "next", event );
5681 break;
5682 case keyCode.ENTER:
5683
5684 // when menu is open and has focus
5685 if ( this.menu.active ) {
5686
5687 // #6055 - Opera still allows the keypress to occur
5688 // which causes forms to submit
5689 suppressKeyPress = true;
5690 event.preventDefault();
5691 this.menu.select( event );
5692 }
5693 break;
5694 case keyCode.TAB:
5695 if ( this.menu.active ) {
5696 this.menu.select( event );
5697 }
5698 break;
5699 case keyCode.ESCAPE:
5700 if ( this.menu.element.is( ":visible" ) ) {
5701 if ( !this.isMultiLine ) {
5702 this._value( this.term );
5703 }
5704 this.close( event );
5705
5706 // Different browsers have different default behavior for escape
5707 // Single press can mean undo or clear
5708 // Double press in IE means clear the whole form
5709 event.preventDefault();
5710 }
5711 break;
5712 default:
5713 suppressKeyPressRepeat = true;
5714
5715 // search timeout should be triggered before the input value is changed
5716 this._searchTimeout( event );
5717 break;
5718 }
5719 },
5720 keypress: function( event ) {
5721 if ( suppressKeyPress ) {
5722 suppressKeyPress = false;
5723 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5724 event.preventDefault();
5725 }
5726 return;
5727 }
5728 if ( suppressKeyPressRepeat ) {
5729 return;
5730 }
5731
5732 // Replicate some key handlers to allow them to repeat in Firefox and Opera
5733 var keyCode = $.ui.keyCode;
5734 switch ( event.keyCode ) {
5735 case keyCode.PAGE_UP:
5736 this._move( "previousPage", event );
5737 break;
5738 case keyCode.PAGE_DOWN:
5739 this._move( "nextPage", event );
5740 break;
5741 case keyCode.UP:
5742 this._keyEvent( "previous", event );
5743 break;
5744 case keyCode.DOWN:
5745 this._keyEvent( "next", event );
5746 break;
5747 }
5748 },
5749 input: function( event ) {
5750 if ( suppressInput ) {
5751 suppressInput = false;
5752 event.preventDefault();
5753 return;
5754 }
5755 this._searchTimeout( event );
5756 },
5757 focus: function() {
5758 this.selectedItem = null;
5759 this.previous = this._value();
5760 },
5761 blur: function( event ) {
5762 if ( this.cancelBlur ) {
5763 delete this.cancelBlur;
5764 return;
5765 }
5766
5767 clearTimeout( this.searching );
5768 this.close( event );
5769 this._change( event );
5770 }
5771 } );
5772
5773 this._initSource();
5774 this.menu = $( "<ul>" )
5775 .appendTo( this._appendTo() )
5776 .menu( {
5777
5778 // disable ARIA support, the live region takes care of that
5779 role: null
5780 } )
5781 .hide()
5782 .menu( "instance" );
5783
5784 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
5785 this._on( this.menu.element, {
5786 mousedown: function( event ) {
5787
5788 // prevent moving focus out of the text field
5789 event.preventDefault();
5790
5791 // IE doesn't prevent moving focus even with event.preventDefault()
5792 // so we set a flag to know when we should ignore the blur event
5793 this.cancelBlur = true;
5794 this._delay( function() {
5795 delete this.cancelBlur;
5796
5797 // Support: IE 8 only
5798 // Right clicking a menu item or selecting text from the menu items will
5799 // result in focus moving out of the input. However, we've already received
5800 // and ignored the blur event because of the cancelBlur flag set above. So
5801 // we restore focus to ensure that the menu closes properly based on the user's
5802 // next actions.
5803 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
5804 this.element.trigger( "focus" );
5805 }
5806 } );
5807 },
5808 menufocus: function( event, ui ) {
5809 var label, item;
5810
5811 // support: Firefox
5812 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
5813 if ( this.isNewMenu ) {
5814 this.isNewMenu = false;
5815 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
5816 this.menu.blur();
5817
5818 this.document.one( "mousemove", function() {
5819 $( event.target ).trigger( event.originalEvent );
5820 } );
5821
5822 return;
5823 }
5824 }
5825
5826 item = ui.item.data( "ui-autocomplete-item" );
5827 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
5828
5829 // use value to match what will end up in the input, if it was a key event
5830 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
5831 this._value( item.value );
5832 }
5833 }
5834
5835 // Announce the value in the liveRegion
5836 label = ui.item.attr( "aria-label" ) || item.value;
5837 if ( label && $.trim( label ).length ) {
5838 this.liveRegion.children().hide();
5839 $( "<div>" ).text( label ).appendTo( this.liveRegion );
5840 }
5841 },
5842 menuselect: function( event, ui ) {
5843 var item = ui.item.data( "ui-autocomplete-item" ),
5844 previous = this.previous;
5845
5846 // Only trigger when focus was lost (click on menu)
5847 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
5848 this.element.trigger( "focus" );
5849 this.previous = previous;
5850
5851 // #6109 - IE triggers two focus events and the second
5852 // is asynchronous, so we need to reset the previous
5853 // term synchronously and asynchronously :-(
5854 this._delay( function() {
5855 this.previous = previous;
5856 this.selectedItem = item;
5857 } );
5858 }
5859
5860 if ( false !== this._trigger( "select", event, { item: item } ) ) {
5861 this._value( item.value );
5862 }
5863
5864 // reset the term after the select event
5865 // this allows custom select handling to work properly
5866 this.term = this._value();
5867
5868 this.close( event );
5869 this.selectedItem = item;
5870 }
5871 } );
5872
5873 this.liveRegion = $( "<div>", {
5874 role: "status",
5875 "aria-live": "assertive",
5876 "aria-relevant": "additions"
5877 } )
5878 .appendTo( this.document[ 0 ].body );
5879
5880 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
5881
5882 // Turning off autocomplete prevents the browser from remembering the
5883 // value when navigating through history, so we re-enable autocomplete
5884 // if the page is unloaded before the widget is destroyed. #7790
5885 this._on( this.window, {
5886 beforeunload: function() {
5887 this.element.removeAttr( "autocomplete" );
5888 }
5889 } );
5890 },
5891
5892 _destroy: function() {
5893 clearTimeout( this.searching );
5894 this.element.removeAttr( "autocomplete" );
5895 this.menu.element.remove();
5896 this.liveRegion.remove();
5897 },
5898
5899 _setOption: function( key, value ) {
5900 this._super( key, value );
5901 if ( key === "source" ) {
5902 this._initSource();
5903 }
5904 if ( key === "appendTo" ) {
5905 this.menu.element.appendTo( this._appendTo() );
5906 }
5907 if ( key === "disabled" && value && this.xhr ) {
5908 this.xhr.abort();
5909 }
5910 },
5911
5912 _isEventTargetInWidget: function( event ) {
5913 var menuElement = this.menu.element[ 0 ];
5914
5915 return event.target === this.element[ 0 ] ||
5916 event.target === menuElement ||
5917 $.contains( menuElement, event.target );
5918 },
5919
5920 _closeOnClickOutside: function( event ) {
5921 if ( !this._isEventTargetInWidget( event ) ) {
5922 this.close();
5923 }
5924 },
5925
5926 _appendTo: function() {
5927 var element = this.options.appendTo;
5928
5929 if ( element ) {
5930 element = element.jquery || element.nodeType ?
5931 $( element ) :
5932 this.document.find( element ).eq( 0 );
5933 }
5934
5935 if ( !element || !element[ 0 ] ) {
5936 element = this.element.closest( ".ui-front, dialog" );
5937 }
5938
5939 if ( !element.length ) {
5940 element = this.document[ 0 ].body;
5941 }
5942
5943 return element;
5944 },
5945
5946 _initSource: function() {
5947 var array, url,
5948 that = this;
5949 if ( $.isArray( this.options.source ) ) {
5950 array = this.options.source;
5951 this.source = function( request, response ) {
5952 response( $.ui.autocomplete.filter( array, request.term ) );
5953 };
5954 } else if ( typeof this.options.source === "string" ) {
5955 url = this.options.source;
5956 this.source = function( request, response ) {
5957 if ( that.xhr ) {
5958 that.xhr.abort();
5959 }
5960 that.xhr = $.ajax( {
5961 url: url,
5962 data: request,
5963 dataType: "json",
5964 success: function( data ) {
5965 response( data );
5966 },
5967 error: function() {
5968 response( [] );
5969 }
5970 } );
5971 };
5972 } else {
5973 this.source = this.options.source;
5974 }
5975 },
5976
5977 _searchTimeout: function( event ) {
5978 clearTimeout( this.searching );
5979 this.searching = this._delay( function() {
5980
5981 // Search if the value has changed, or if the user retypes the same value (see #7434)
5982 var equalValues = this.term === this._value(),
5983 menuVisible = this.menu.element.is( ":visible" ),
5984 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
5985
5986 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
5987 this.selectedItem = null;
5988 this.search( null, event );
5989 }
5990 }, this.options.delay );
5991 },
5992
5993 search: function( value, event ) {
5994 value = value != null ? value : this._value();
5995
5996 // Always save the actual value, not the one passed as an argument
5997 this.term = this._value();
5998
5999 if ( value.length < this.options.minLength ) {
6000 return this.close( event );
6001 }
6002
6003 if ( this._trigger( "search", event ) === false ) {
6004 return;
6005 }
6006
6007 return this._search( value );
6008 },
6009
6010 _search: function( value ) {
6011 this.pending++;
6012 this._addClass( "ui-autocomplete-loading" );
6013 this.cancelSearch = false;
6014
6015 this.source( { term: value }, this._response() );
6016 },
6017
6018 _response: function() {
6019 var index = ++this.requestIndex;
6020
6021 return $.proxy( function( content ) {
6022 if ( index === this.requestIndex ) {
6023 this.__response( content );
6024 }
6025
6026 this.pending--;
6027 if ( !this.pending ) {
6028 this._removeClass( "ui-autocomplete-loading" );
6029 }
6030 }, this );
6031 },
6032
6033 __response: function( content ) {
6034 if ( content ) {
6035 content = this._normalize( content );
6036 }
6037 this._trigger( "response", null, { content: content } );
6038 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
6039 this._suggest( content );
6040 this._trigger( "open" );
6041 } else {
6042
6043 // use ._close() instead of .close() so we don't cancel future searches
6044 this._close();
6045 }
6046 },
6047
6048 close: function( event ) {
6049 this.cancelSearch = true;
6050 this._close( event );
6051 },
6052
6053 _close: function( event ) {
6054
6055 // Remove the handler that closes the menu on outside clicks
6056 this._off( this.document, "mousedown" );
6057
6058 if ( this.menu.element.is( ":visible" ) ) {
6059 this.menu.element.hide();
6060 this.menu.blur();
6061 this.isNewMenu = true;
6062 this._trigger( "close", event );
6063 }
6064 },
6065
6066 _change: function( event ) {
6067 if ( this.previous !== this._value() ) {
6068 this._trigger( "change", event, { item: this.selectedItem } );
6069 }
6070 },
6071
6072 _normalize: function( items ) {
6073
6074 // assume all items have the right format when the first item is complete
6075 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
6076 return items;
6077 }
6078 return $.map( items, function( item ) {
6079 if ( typeof item === "string" ) {
6080 return {
6081 label: item,
6082 value: item
6083 };
6084 }
6085 return $.extend( {}, item, {
6086 label: item.label || item.value,
6087 value: item.value || item.label
6088 } );
6089 } );
6090 },
6091
6092 _suggest: function( items ) {
6093 var ul = this.menu.element.empty();
6094 this._renderMenu( ul, items );
6095 this.isNewMenu = true;
6096 this.menu.refresh();
6097
6098 // Size and position menu
6099 ul.show();
6100 this._resizeMenu();
6101 ul.position( $.extend( {
6102 of: this.element
6103 }, this.options.position ) );
6104
6105 if ( this.options.autoFocus ) {
6106 this.menu.next();
6107 }
6108
6109 // Listen for interactions outside of the widget (#6642)
6110 this._on( this.document, {
6111 mousedown: "_closeOnClickOutside"
6112 } );
6113 },
6114
6115 _resizeMenu: function() {
6116 var ul = this.menu.element;
6117 ul.outerWidth( Math.max(
6118
6119 // Firefox wraps long text (possibly a rounding bug)
6120 // so we add 1px to avoid the wrapping (#7513)
6121 ul.width( "" ).outerWidth() + 1,
6122 this.element.outerWidth()
6123 ) );
6124 },
6125
6126 _renderMenu: function( ul, items ) {
6127 var that = this;
6128 $.each( items, function( index, item ) {
6129 that._renderItemData( ul, item );
6130 } );
6131 },
6132
6133 _renderItemData: function( ul, item ) {
6134 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
6135 },
6136
6137 _renderItem: function( ul, item ) {
6138 return $( "<li>" )
6139 .append( $( "<div>" ).text( item.label ) )
6140 .appendTo( ul );
6141 },
6142
6143 _move: function( direction, event ) {
6144 if ( !this.menu.element.is( ":visible" ) ) {
6145 this.search( null, event );
6146 return;
6147 }
6148 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
6149 this.menu.isLastItem() && /^next/.test( direction ) ) {
6150
6151 if ( !this.isMultiLine ) {
6152 this._value( this.term );
6153 }
6154
6155 this.menu.blur();
6156 return;
6157 }
6158 this.menu[ direction ]( event );
6159 },
6160
6161 widget: function() {
6162 return this.menu.element;
6163 },
6164
6165 _value: function() {
6166 return this.valueMethod.apply( this.element, arguments );
6167 },
6168
6169 _keyEvent: function( keyEvent, event ) {
6170 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
6171 this._move( keyEvent, event );
6172
6173 // Prevents moving cursor to beginning/end of the text field in some browsers
6174 event.preventDefault();
6175 }
6176 },
6177
6178 // Support: Chrome <=50
6179 // We should be able to just use this.element.prop( "isContentEditable" )
6180 // but hidden elements always report false in Chrome.
6181 // https://code.google.com/p/chromium/issues/detail?id=313082
6182 _isContentEditable: function( element ) {
6183 if ( !element.length ) {
6184 return false;
6185 }
6186
6187 var editable = element.prop( "contentEditable" );
6188
6189 if ( editable === "inherit" ) {
6190 return this._isContentEditable( element.parent() );
6191 }
6192
6193 return editable === "true";
6194 }
6195 } );
6196
6197 $.extend( $.ui.autocomplete, {
6198 escapeRegex: function( value ) {
6199 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
6200 },
6201 filter: function( array, term ) {
6202 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
6203 return $.grep( array, function( value ) {
6204 return matcher.test( value.label || value.value || value );
6205 } );
6206 }
6207 } );
6208
6209 // Live region extension, adding a `messages` option
6210 // NOTE: This is an experimental API. We are still investigating
6211 // a full solution for string manipulation and internationalization.
6212 $.widget( "ui.autocomplete", $.ui.autocomplete, {
6213 options: {
6214 messages: {
6215 noResults: "No search results.",
6216 results: function( amount ) {
6217 return amount + ( amount > 1 ? " results are" : " result is" ) +
6218 " available, use up and down arrow keys to navigate.";
6219 }
6220 }
6221 },
6222
6223 __response: function( content ) {
6224 var message;
6225 this._superApply( arguments );
6226 if ( this.options.disabled || this.cancelSearch ) {
6227 return;
6228 }
6229 if ( content && content.length ) {
6230 message = this.options.messages.results( content.length );
6231 } else {
6232 message = this.options.messages.noResults;
6233 }
6234 this.liveRegion.children().hide();
6235 $( "<div>" ).text( message ).appendTo( this.liveRegion );
6236 }
6237 } );
6238
6239 var widgetsAutocomplete = $.ui.autocomplete;
6240
6241
6242 /*!
6243 * jQuery UI Controlgroup 1.12.1
6244 * http://jqueryui.com
6245 *
6246 * Copyright jQuery Foundation and other contributors
6247 * Released under the MIT license.
6248 * http://jquery.org/license
6249 */
6250
6251 //>>label: Controlgroup
6252 //>>group: Widgets
6253 //>>description: Visually groups form control widgets
6254 //>>docs: http://api.jqueryui.com/controlgroup/
6255 //>>demos: http://jqueryui.com/controlgroup/
6256 //>>css.structure: ../../themes/base/core.css
6257 //>>css.structure: ../../themes/base/controlgroup.css
6258 //>>css.theme: ../../themes/base/theme.css
6259
6260
6261 var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
6262
6263 var widgetsControlgroup = $.widget( "ui.controlgroup", {
6264 version: "1.12.1",
6265 defaultElement: "<div>",
6266 options: {
6267 direction: "horizontal",
6268 disabled: null,
6269 onlyVisible: true,
6270 items: {
6271 "button": "input[type=button], input[type=submit], input[type=reset], button, a",
6272 "controlgroupLabel": ".ui-controlgroup-label",
6273 "checkboxradio": "input[type='checkbox'], input[type='radio']",
6274 "selectmenu": "select",
6275 "spinner": ".ui-spinner-input"
6276 }
6277 },
6278
6279 _create: function() {
6280 this._enhance();
6281 },
6282
6283 // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
6284 _enhance: function() {
6285 this.element.attr( "role", "toolbar" );
6286 this.refresh();
6287 },
6288
6289 _destroy: function() {
6290 this._callChildMethod( "destroy" );
6291 this.childWidgets.removeData( "ui-controlgroup-data" );
6292 this.element.removeAttr( "role" );
6293 if ( this.options.items.controlgroupLabel ) {
6294 this.element
6295 .find( this.options.items.controlgroupLabel )
6296 .find( ".ui-controlgroup-label-contents" )
6297 .contents().unwrap();
6298 }
6299 },
6300
6301 _initWidgets: function() {
6302 var that = this,
6303 childWidgets = [];
6304
6305 // First we iterate over each of the items options
6306 $.each( this.options.items, function( widget, selector ) {
6307 var labels;
6308 var options = {};
6309
6310 // Make sure the widget has a selector set
6311 if ( !selector ) {
6312 return;
6313 }
6314
6315 if ( widget === "controlgroupLabel" ) {
6316 labels = that.element.find( selector );
6317 labels.each( function() {
6318 var element = $( this );
6319
6320 if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
6321 return;
6322 }
6323 element.contents()
6324 .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
6325 } );
6326 that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
6327 childWidgets = childWidgets.concat( labels.get() );
6328 return;
6329 }
6330
6331 // Make sure the widget actually exists
6332 if ( !$.fn[ widget ] ) {
6333 return;
6334 }
6335
6336 // We assume everything is in the middle to start because we can't determine
6337 // first / last elements until all enhancments are done.
6338 if ( that[ "_" + widget + "Options" ] ) {
6339 options = that[ "_" + widget + "Options" ]( "middle" );
6340 } else {
6341 options = { classes: {} };
6342 }
6343
6344 // Find instances of this widget inside controlgroup and init them
6345 that.element
6346 .find( selector )
6347 .each( function() {
6348 var element = $( this );
6349 var instance = element[ widget ]( "instance" );
6350
6351 // We need to clone the default options for this type of widget to avoid
6352 // polluting the variable options which has a wider scope than a single widget.
6353 var instanceOptions = $.widget.extend( {}, options );
6354
6355 // If the button is the child of a spinner ignore it
6356 // TODO: Find a more generic solution
6357 if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
6358 return;
6359 }
6360
6361 // Create the widget if it doesn't exist
6362 if ( !instance ) {
6363 instance = element[ widget ]()[ widget ]( "instance" );
6364 }
6365 if ( instance ) {
6366 instanceOptions.classes =
6367 that._resolveClassesValues( instanceOptions.classes, instance );
6368 }
6369 element[ widget ]( instanceOptions );
6370
6371 // Store an instance of the controlgroup to be able to reference
6372 // from the outermost element for changing options and refresh
6373 var widgetElement = element[ widget ]( "widget" );
6374 $.data( widgetElement[ 0 ], "ui-controlgroup-data",
6375 instance ? instance : element[ widget ]( "instance" ) );
6376
6377 childWidgets.push( widgetElement[ 0 ] );
6378 } );
6379 } );
6380
6381 this.childWidgets = $( $.unique( childWidgets ) );
6382 this._addClass( this.childWidgets, "ui-controlgroup-item" );
6383 },
6384
6385 _callChildMethod: function( method ) {
6386 this.childWidgets.each( function() {
6387 var element = $( this ),
6388 data = element.data( "ui-controlgroup-data" );
6389 if ( data && data[ method ] ) {
6390 data[ method ]();
6391 }
6392 } );
6393 },
6394
6395 _updateCornerClass: function( element, position ) {
6396 var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
6397 var add = this._buildSimpleOptions( position, "label" ).classes.label;
6398
6399 this._removeClass( element, null, remove );
6400 this._addClass( element, null, add );
6401 },
6402
6403 _buildSimpleOptions: function( position, key ) {
6404 var direction = this.options.direction === "vertical";
6405 var result = {
6406 classes: {}
6407 };
6408 result.classes[ key ] = {
6409 "middle": "",
6410 "first": "ui-corner-" + ( direction ? "top" : "left" ),
6411 "last": "ui-corner-" + ( direction ? "bottom" : "right" ),
6412 "only": "ui-corner-all"
6413 }[ position ];
6414
6415 return result;
6416 },
6417
6418 _spinnerOptions: function( position ) {
6419 var options = this._buildSimpleOptions( position, "ui-spinner" );
6420
6421 options.classes[ "ui-spinner-up" ] = "";
6422 options.classes[ "ui-spinner-down" ] = "";
6423
6424 return options;
6425 },
6426
6427 _buttonOptions: function( position ) {
6428 return this._buildSimpleOptions( position, "ui-button" );
6429 },
6430
6431 _checkboxradioOptions: function( position ) {
6432 return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
6433 },
6434
6435 _selectmenuOptions: function( position ) {
6436 var direction = this.options.direction === "vertical";
6437 return {
6438 width: direction ? "auto" : false,
6439 classes: {
6440 middle: {
6441 "ui-selectmenu-button-open": "",
6442 "ui-selectmenu-button-closed": ""
6443 },
6444 first: {
6445 "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
6446 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
6447 },
6448 last: {
6449 "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
6450 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
6451 },
6452 only: {
6453 "ui-selectmenu-button-open": "ui-corner-top",
6454 "ui-selectmenu-button-closed": "ui-corner-all"
6455 }
6456
6457 }[ position ]
6458 };
6459 },
6460
6461 _resolveClassesValues: function( classes, instance ) {
6462 var result = {};
6463 $.each( classes, function( key ) {
6464 var current = instance.options.classes[ key ] || "";
6465 current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
6466 result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
6467 } );
6468 return result;
6469 },
6470
6471 _setOption: function( key, value ) {
6472 if ( key === "direction" ) {
6473 this._removeClass( "ui-controlgroup-" + this.options.direction );
6474 }
6475
6476 this._super( key, value );
6477 if ( key === "disabled" ) {
6478 this._callChildMethod( value ? "disable" : "enable" );
6479 return;
6480 }
6481
6482 this.refresh();
6483 },
6484
6485 refresh: function() {
6486 var children,
6487 that = this;
6488
6489 this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
6490
6491 if ( this.options.direction === "horizontal" ) {
6492 this._addClass( null, "ui-helper-clearfix" );
6493 }
6494 this._initWidgets();
6495
6496 children = this.childWidgets;
6497
6498 // We filter here because we need to track all childWidgets not just the visible ones
6499 if ( this.options.onlyVisible ) {
6500 children = children.filter( ":visible" );
6501 }
6502
6503 if ( children.length ) {
6504
6505 // We do this last because we need to make sure all enhancment is done
6506 // before determining first and last
6507 $.each( [ "first", "last" ], function( index, value ) {
6508 var instance = children[ value ]().data( "ui-controlgroup-data" );
6509
6510 if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
6511 var options = that[ "_" + instance.widgetName + "Options" ](
6512 children.length === 1 ? "only" : value
6513 );
6514 options.classes = that._resolveClassesValues( options.classes, instance );
6515 instance.element[ instance.widgetName ]( options );
6516 } else {
6517 that._updateCornerClass( children[ value ](), value );
6518 }
6519 } );
6520
6521 // Finally call the refresh method on each of the child widgets.
6522 this._callChildMethod( "refresh" );
6523 }
6524 }
6525 } );
6526
6527 /*!
6528 * jQuery UI Checkboxradio 1.12.1
6529 * http://jqueryui.com
6530 *
6531 * Copyright jQuery Foundation and other contributors
6532 * Released under the MIT license.
6533 * http://jquery.org/license
6534 */
6535
6536 //>>label: Checkboxradio
6537 //>>group: Widgets
6538 //>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
6539 //>>docs: http://api.jqueryui.com/checkboxradio/
6540 //>>demos: http://jqueryui.com/checkboxradio/
6541 //>>css.structure: ../../themes/base/core.css
6542 //>>css.structure: ../../themes/base/button.css
6543 //>>css.structure: ../../themes/base/checkboxradio.css
6544 //>>css.theme: ../../themes/base/theme.css
6545
6546
6547
6548 $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
6549 version: "1.12.1",
6550 options: {
6551 disabled: null,
6552 label: null,
6553 icon: true,
6554 classes: {
6555 "ui-checkboxradio-label": "ui-corner-all",
6556 "ui-checkboxradio-icon": "ui-corner-all"
6557 }
6558 },
6559
6560 _getCreateOptions: function() {
6561 var disabled, labels;
6562 var that = this;
6563 var options = this._super() || {};
6564
6565 // We read the type here, because it makes more sense to throw a element type error first,
6566 // rather then the error for lack of a label. Often if its the wrong type, it
6567 // won't have a label (e.g. calling on a div, btn, etc)
6568 this._readType();
6569
6570 labels = this.element.labels();
6571
6572 // If there are multiple labels, use the last one
6573 this.label = $( labels[ labels.length - 1 ] );
6574 if ( !this.label.length ) {
6575 $.error( "No label found for checkboxradio widget" );
6576 }
6577
6578 this.originalLabel = "";
6579
6580 // We need to get the label text but this may also need to make sure it does not contain the
6581 // input itself.
6582 this.label.contents().not( this.element[ 0 ] ).each( function() {
6583
6584 // The label contents could be text, html, or a mix. We concat each element to get a
6585 // string representation of the label, without the input as part of it.
6586 that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
6587 } );
6588
6589 // Set the label option if we found label text
6590 if ( this.originalLabel ) {
6591 options.label = this.originalLabel;
6592 }
6593
6594 disabled = this.element[ 0 ].disabled;
6595 if ( disabled != null ) {
6596 options.disabled = disabled;
6597 }
6598 return options;
6599 },
6600
6601 _create: function() {
6602 var checked = this.element[ 0 ].checked;
6603
6604 this._bindFormResetHandler();
6605
6606 if ( this.options.disabled == null ) {
6607 this.options.disabled = this.element[ 0 ].disabled;
6608 }
6609
6610 this._setOption( "disabled", this.options.disabled );
6611 this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
6612 this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
6613
6614 if ( this.type === "radio" ) {
6615 this._addClass( this.label, "ui-checkboxradio-radio-label" );
6616 }
6617
6618 if ( this.options.label && this.options.label !== this.originalLabel ) {
6619 this._updateLabel();
6620 } else if ( this.originalLabel ) {
6621 this.options.label = this.originalLabel;
6622 }
6623
6624 this._enhance();
6625
6626 if ( checked ) {
6627 this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
6628 if ( this.icon ) {
6629 this._addClass( this.icon, null, "ui-state-hover" );
6630 }
6631 }
6632
6633 this._on( {
6634 change: "_toggleClasses",
6635 focus: function() {
6636 this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
6637 },
6638 blur: function() {
6639 this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
6640 }
6641 } );
6642 },
6643
6644 _readType: function() {
6645 var nodeName = this.element[ 0 ].nodeName.toLowerCase();
6646 this.type = this.element[ 0 ].type;
6647 if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
6648 $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
6649 " and element.type=" + this.type );
6650 }
6651 },
6652
6653 // Support jQuery Mobile enhanced option
6654 _enhance: function() {
6655 this._updateIcon( this.element[ 0 ].checked );
6656 },
6657
6658 widget: function() {
6659 return this.label;
6660 },
6661
6662 _getRadioGroup: function() {
6663 var group;
6664 var name = this.element[ 0 ].name;
6665 var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
6666
6667 if ( !name ) {
6668 return $( [] );
6669 }
6670
6671 if ( this.form.length ) {
6672 group = $( this.form[ 0 ].elements ).filter( nameSelector );
6673 } else {
6674
6675 // Not inside a form, check all inputs that also are not inside a form
6676 group = $( nameSelector ).filter( function() {
6677 return $( this ).form().length === 0;
6678 } );
6679 }
6680
6681 return group.not( this.element );
6682 },
6683
6684 _toggleClasses: function() {
6685 var checked = this.element[ 0 ].checked;
6686 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
6687
6688 if ( this.options.icon && this.type === "checkbox" ) {
6689 this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
6690 ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
6691 }
6692
6693 if ( this.type === "radio" ) {
6694 this._getRadioGroup()
6695 .each( function() {
6696 var instance = $( this ).checkboxradio( "instance" );
6697
6698 if ( instance ) {
6699 instance._removeClass( instance.label,
6700 "ui-checkboxradio-checked", "ui-state-active" );
6701 }
6702 } );
6703 }
6704 },
6705
6706 _destroy: function() {
6707 this._unbindFormResetHandler();
6708
6709 if ( this.icon ) {
6710 this.icon.remove();
6711 this.iconSpace.remove();
6712 }
6713 },
6714
6715 _setOption: function( key, value ) {
6716
6717 // We don't allow the value to be set to nothing
6718 if ( key === "label" && !value ) {
6719 return;
6720 }
6721
6722 this._super( key, value );
6723
6724 if ( key === "disabled" ) {
6725 this._toggleClass( this.label, null, "ui-state-disabled", value );
6726 this.element[ 0 ].disabled = value;
6727
6728 // Don't refresh when setting disabled
6729 return;
6730 }
6731 this.refresh();
6732 },
6733
6734 _updateIcon: function( checked ) {
6735 var toAdd = "ui-icon ui-icon-background ";
6736
6737 if ( this.options.icon ) {
6738 if ( !this.icon ) {
6739 this.icon = $( "<span>" );
6740 this.iconSpace = $( "<span> </span>" );
6741 this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
6742 }
6743
6744 if ( this.type === "checkbox" ) {
6745 toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
6746 this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
6747 } else {
6748 toAdd += "ui-icon-blank";
6749 }
6750 this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
6751 if ( !checked ) {
6752 this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
6753 }
6754 this.icon.prependTo( this.label ).after( this.iconSpace );
6755 } else if ( this.icon !== undefined ) {
6756 this.icon.remove();
6757 this.iconSpace.remove();
6758 delete this.icon;
6759 }
6760 },
6761
6762 _updateLabel: function() {
6763
6764 // Remove the contents of the label ( minus the icon, icon space, and input )
6765 var contents = this.label.contents().not( this.element[ 0 ] );
6766 if ( this.icon ) {
6767 contents = contents.not( this.icon[ 0 ] );
6768 }
6769 if ( this.iconSpace ) {
6770 contents = contents.not( this.iconSpace[ 0 ] );
6771 }
6772 contents.remove();
6773
6774 this.label.append( this.options.label );
6775 },
6776
6777 refresh: function() {
6778 var checked = this.element[ 0 ].checked,
6779 isDisabled = this.element[ 0 ].disabled;
6780
6781 this._updateIcon( checked );
6782 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
6783 if ( this.options.label !== null ) {
6784 this._updateLabel();
6785 }
6786
6787 if ( isDisabled !== this.options.disabled ) {
6788 this._setOptions( { "disabled": isDisabled } );
6789 }
6790 }
6791
6792 } ] );
6793
6794 var widgetsCheckboxradio = $.ui.checkboxradio;
6795
6796
6797 /*!
6798 * jQuery UI Button 1.12.1
6799 * http://jqueryui.com
6800 *
6801 * Copyright jQuery Foundation and other contributors
6802 * Released under the MIT license.
6803 * http://jquery.org/license
6804 */
6805
6806 //>>label: Button
6807 //>>group: Widgets
6808 //>>description: Enhances a form with themeable buttons.
6809 //>>docs: http://api.jqueryui.com/button/
6810 //>>demos: http://jqueryui.com/button/
6811 //>>css.structure: ../../themes/base/core.css
6812 //>>css.structure: ../../themes/base/button.css
6813 //>>css.theme: ../../themes/base/theme.css
6814
6815
6816
6817 $.widget( "ui.button", {
6818 version: "1.12.1",
6819 defaultElement: "<button>",
6820 options: {
6821 classes: {
6822 "ui-button": "ui-corner-all"
6823 },
6824 disabled: null,
6825 icon: null,
6826 iconPosition: "beginning",
6827 label: null,
6828 showLabel: true
6829 },
6830
6831 _getCreateOptions: function() {
6832 var disabled,
6833
6834 // This is to support cases like in jQuery Mobile where the base widget does have
6835 // an implementation of _getCreateOptions
6836 options = this._super() || {};
6837
6838 this.isInput = this.element.is( "input" );
6839
6840 disabled = this.element[ 0 ].disabled;
6841 if ( disabled != null ) {
6842 options.disabled = disabled;
6843 }
6844
6845 this.originalLabel = this.isInput ? this.element.val() : this.element.html();
6846 if ( this.originalLabel ) {
6847 options.label = this.originalLabel;
6848 }
6849
6850 return options;
6851 },
6852
6853 _create: function() {
6854 if ( !this.option.showLabel & !this.options.icon ) {
6855 this.options.showLabel = true;
6856 }
6857
6858 // We have to check the option again here even though we did in _getCreateOptions,
6859 // because null may have been passed on init which would override what was set in
6860 // _getCreateOptions
6861 if ( this.options.disabled == null ) {
6862 this.options.disabled = this.element[ 0 ].disabled || false;
6863 }
6864
6865 this.hasTitle = !!this.element.attr( "title" );
6866
6867 // Check to see if the label needs to be set or if its already correct
6868 if ( this.options.label && this.options.label !== this.originalLabel ) {
6869 if ( this.isInput ) {
6870 this.element.val( this.options.label );
6871 } else {
6872 this.element.html( this.options.label );
6873 }
6874 }
6875 this._addClass( "ui-button", "ui-widget" );
6876 this._setOption( "disabled", this.options.disabled );
6877 this._enhance();
6878
6879 if ( this.element.is( "a" ) ) {
6880 this._on( {
6881 "keyup": function( event ) {
6882 if ( event.keyCode === $.ui.keyCode.SPACE ) {
6883 event.preventDefault();
6884
6885 // Support: PhantomJS <= 1.9, IE 8 Only
6886 // If a native click is available use it so we actually cause navigation
6887 // otherwise just trigger a click event
6888 if ( this.element[ 0 ].click ) {
6889 this.element[ 0 ].click();
6890 } else {
6891 this.element.trigger( "click" );
6892 }
6893 }
6894 }
6895 } );
6896 }
6897 },
6898
6899 _enhance: function() {
6900 if ( !this.element.is( "button" ) ) {
6901 this.element.attr( "role", "button" );
6902 }
6903
6904 if ( this.options.icon ) {
6905 this._updateIcon( "icon", this.options.icon );
6906 this._updateTooltip();
6907 }
6908 },
6909
6910 _updateTooltip: function() {
6911 this.title = this.element.attr( "title" );
6912
6913 if ( !this.options.showLabel && !this.title ) {
6914 this.element.attr( "title", this.options.label );
6915 }
6916 },
6917
6918 _updateIcon: function( option, value ) {
6919 var icon = option !== "iconPosition",
6920 position = icon ? this.options.iconPosition : value,
6921 displayBlock = position === "top" || position === "bottom";
6922
6923 // Create icon
6924 if ( !this.icon ) {
6925 this.icon = $( "<span>" );
6926
6927 this._addClass( this.icon, "ui-button-icon", "ui-icon" );
6928
6929 if ( !this.options.showLabel ) {
6930 this._addClass( "ui-button-icon-only" );
6931 }
6932 } else if ( icon ) {
6933
6934 // If we are updating the icon remove the old icon class
6935 this._removeClass( this.icon, null, this.options.icon );
6936 }
6937
6938 // If we are updating the icon add the new icon class
6939 if ( icon ) {
6940 this._addClass( this.icon, null, value );
6941 }
6942
6943 this._attachIcon( position );
6944
6945 // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
6946 // the iconSpace if there is one.
6947 if ( displayBlock ) {
6948 this._addClass( this.icon, null, "ui-widget-icon-block" );
6949 if ( this.iconSpace ) {
6950 this.iconSpace.remove();
6951 }
6952 } else {
6953
6954 // Position is beginning or end so remove the ui-widget-icon-block class and add the
6955 // space if it does not exist
6956 if ( !this.iconSpace ) {
6957 this.iconSpace = $( "<span> </span>" );
6958 this._addClass( this.iconSpace, "ui-button-icon-space" );
6959 }
6960 this._removeClass( this.icon, null, "ui-wiget-icon-block" );
6961 this._attachIconSpace( position );
6962 }
6963 },
6964
6965 _destroy: function() {
6966 this.element.removeAttr( "role" );
6967
6968 if ( this.icon ) {
6969 this.icon.remove();
6970 }
6971 if ( this.iconSpace ) {
6972 this.iconSpace.remove();
6973 }
6974 if ( !this.hasTitle ) {
6975 this.element.removeAttr( "title" );
6976 }
6977 },
6978
6979 _attachIconSpace: function( iconPosition ) {
6980 this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
6981 },
6982
6983 _attachIcon: function( iconPosition ) {
6984 this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
6985 },
6986
6987 _setOptions: function( options ) {
6988 var newShowLabel = options.showLabel === undefined ?
6989 this.options.showLabel :
6990 options.showLabel,
6991 newIcon = options.icon === undefined ? this.options.icon : options.icon;
6992
6993 if ( !newShowLabel && !newIcon ) {
6994 options.showLabel = true;
6995 }
6996 this._super( options );
6997 },
6998
6999 _setOption: function( key, value ) {
7000 if ( key === "icon" ) {
7001 if ( value ) {
7002 this._updateIcon( key, value );
7003 } else if ( this.icon ) {
7004 this.icon.remove();
7005 if ( this.iconSpace ) {
7006 this.iconSpace.remove();
7007 }
7008 }
7009 }
7010
7011 if ( key === "iconPosition" ) {
7012 this._updateIcon( key, value );
7013 }
7014
7015 // Make sure we can't end up with a button that has neither text nor icon
7016 if ( key === "showLabel" ) {
7017 this._toggleClass( "ui-button-icon-only", null, !value );
7018 this._updateTooltip();
7019 }
7020
7021 if ( key === "label" ) {
7022 if ( this.isInput ) {
7023 this.element.val( value );
7024 } else {
7025
7026 // If there is an icon, append it, else nothing then append the value
7027 // this avoids removal of the icon when setting label text
7028 this.element.html( value );
7029 if ( this.icon ) {
7030 this._attachIcon( this.options.iconPosition );
7031 this._attachIconSpace( this.options.iconPosition );
7032 }
7033 }
7034 }
7035
7036 this._super( key, value );
7037
7038 if ( key === "disabled" ) {
7039 this._toggleClass( null, "ui-state-disabled", value );
7040 this.element[ 0 ].disabled = value;
7041 if ( value ) {
7042 this.element.blur();
7043 }
7044 }
7045 },
7046
7047 refresh: function() {
7048
7049 // Make sure to only check disabled if its an element that supports this otherwise
7050 // check for the disabled class to determine state
7051 var isDisabled = this.element.is( "input, button" ) ?
7052 this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
7053
7054 if ( isDisabled !== this.options.disabled ) {
7055 this._setOptions( { disabled: isDisabled } );
7056 }
7057
7058 this._updateTooltip();
7059 }
7060 } );
7061
7062 // DEPRECATED
7063 if ( $.uiBackCompat !== false ) {
7064
7065 // Text and Icons options
7066 $.widget( "ui.button", $.ui.button, {
7067 options: {
7068 text: true,
7069 icons: {
7070 primary: null,
7071 secondary: null
7072 }
7073 },
7074
7075 _create: function() {
7076 if ( this.options.showLabel && !this.options.text ) {
7077 this.options.showLabel = this.options.text;
7078 }
7079 if ( !this.options.showLabel && this.options.text ) {
7080 this.options.text = this.options.showLabel;
7081 }
7082 if ( !this.options.icon && ( this.options.icons.primary ||
7083 this.options.icons.secondary ) ) {
7084 if ( this.options.icons.primary ) {
7085 this.options.icon = this.options.icons.primary;
7086 } else {
7087 this.options.icon = this.options.icons.secondary;
7088 this.options.iconPosition = "end";
7089 }
7090 } else if ( this.options.icon ) {
7091 this.options.icons.primary = this.options.icon;
7092 }
7093 this._super();
7094 },
7095
7096 _setOption: function( key, value ) {
7097 if ( key === "text" ) {
7098 this._super( "showLabel", value );
7099 return;
7100 }
7101 if ( key === "showLabel" ) {
7102 this.options.text = value;
7103 }
7104 if ( key === "icon" ) {
7105 this.options.icons.primary = value;
7106 }
7107 if ( key === "icons" ) {
7108 if ( value.primary ) {
7109 this._super( "icon", value.primary );
7110 this._super( "iconPosition", "beginning" );
7111 } else if ( value.secondary ) {
7112 this._super( "icon", value.secondary );
7113 this._super( "iconPosition", "end" );
7114 }
7115 }
7116 this._superApply( arguments );
7117 }
7118 } );
7119
7120 $.fn.button = ( function( orig ) {
7121 return function() {
7122 if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
7123 ( this.length && this[ 0 ].tagName === "INPUT" && (
7124 this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
7125 ) ) ) {
7126 return orig.apply( this, arguments );
7127 }
7128 if ( !$.ui.checkboxradio ) {
7129 $.error( "Checkboxradio widget missing" );
7130 }
7131 if ( arguments.length === 0 ) {
7132 return this.checkboxradio( {
7133 "icon": false
7134 } );
7135 }
7136 return this.checkboxradio.apply( this, arguments );
7137 };
7138 } )( $.fn.button );
7139
7140 $.fn.buttonset = function() {
7141 if ( !$.ui.controlgroup ) {
7142 $.error( "Controlgroup widget missing" );
7143 }
7144 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
7145 return this.controlgroup.apply( this,
7146 [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
7147 }
7148 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
7149 return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
7150 }
7151 if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
7152 arguments[ 0 ].items = {
7153 button: arguments[ 0 ].items
7154 };
7155 }
7156 return this.controlgroup.apply( this, arguments );
7157 };
7158 }
7159
7160 var widgetsButton = $.ui.button;
7161
7162
7163 // jscs:disable maximumLineLength
7164 /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
7165 /*!
7166 * jQuery UI Datepicker 1.12.1
7167 * http://jqueryui.com
7168 *
7169 * Copyright jQuery Foundation and other contributors
7170 * Released under the MIT license.
7171 * http://jquery.org/license
7172 */
7173
7174 //>>label: Datepicker
7175 //>>group: Widgets
7176 //>>description: Displays a calendar from an input or inline for selecting dates.
7177 //>>docs: http://api.jqueryui.com/datepicker/
7178 //>>demos: http://jqueryui.com/datepicker/
7179 //>>css.structure: ../../themes/base/core.css
7180 //>>css.structure: ../../themes/base/datepicker.css
7181 //>>css.theme: ../../themes/base/theme.css
7182
7183
7184
7185 $.extend( $.ui, { datepicker: { version: "1.12.1" } } );
7186
7187 var datepicker_instActive;
7188
7189 function datepicker_getZindex( elem ) {
7190 var position, value;
7191 while ( elem.length && elem[ 0 ] !== document ) {
7192
7193 // Ignore z-index if position is set to a value where z-index is ignored by the browser
7194 // This makes behavior of this function consistent across browsers
7195 // WebKit always returns auto if the element is positioned
7196 position = elem.css( "position" );
7197 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
7198
7199 // IE returns 0 when zIndex is not specified
7200 // other browsers return a string
7201 // we ignore the case of nested elements with an explicit value of 0
7202 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
7203 value = parseInt( elem.css( "zIndex" ), 10 );
7204 if ( !isNaN( value ) && value !== 0 ) {
7205 return value;
7206 }
7207 }
7208 elem = elem.parent();
7209 }
7210
7211 return 0;
7212 }
7213 /* Date picker manager.
7214 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
7215 Settings for (groups of) date pickers are maintained in an instance object,
7216 allowing multiple different settings on the same page. */
7217
7218 function Datepicker() {
7219 this._curInst = null; // The current instance in use
7220 this._keyEvent = false; // If the last event was a key event
7221 this._disabledInputs = []; // List of date picker inputs that have been disabled
7222 this._datepickerShowing = false; // True if the popup picker is showing , false if not
7223 this._inDialog = false; // True if showing within a "dialog", false if not
7224 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
7225 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
7226 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
7227 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
7228 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
7229 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
7230 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
7231 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
7232 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
7233 this.regional = []; // Available regional settings, indexed by language code
7234 this.regional[ "" ] = { // Default regional settings
7235 closeText: "Done", // Display text for close link
7236 prevText: "Prev", // Display text for previous month link
7237 nextText: "Next", // Display text for next month link
7238 currentText: "Today", // Display text for current month link
7239 monthNames: [ "January","February","March","April","May","June",
7240 "July","August","September","October","November","December" ], // Names of months for drop-down and formatting
7241 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
7242 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
7243 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
7244 dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
7245 weekHeader: "Wk", // Column header for week of the year
7246 dateFormat: "mm/dd/yy", // See format options on parseDate
7247 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
7248 isRTL: false, // True if right-to-left language, false if left-to-right
7249 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
7250 yearSuffix: "" // Additional text to append to the year in the month headers
7251 };
7252 this._defaults = { // Global defaults for all the date picker instances
7253 showOn: "focus", // "focus" for popup on focus,
7254 // "button" for trigger button, or "both" for either
7255 showAnim: "fadeIn", // Name of jQuery animation for popup
7256 showOptions: {}, // Options for enhanced animations
7257 defaultDate: null, // Used when field is blank: actual date,
7258 // +/-number for offset from today, null for today
7259 appendText: "", // Display text following the input box, e.g. showing the format
7260 buttonText: "...", // Text for trigger button
7261 buttonImage: "", // URL for trigger button image
7262 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
7263 hideIfNoPrevNext: false, // True to hide next/previous month links
7264 // if not applicable, false to just disable them
7265 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
7266 gotoCurrent: false, // True if today link goes back to current selection instead
7267 changeMonth: false, // True if month can be selected directly, false if only prev/next
7268 changeYear: false, // True if year can be selected directly, false if only prev/next
7269 yearRange: "c-10:c+10", // Range of years to display in drop-down,
7270 // either relative to today's year (-nn:+nn), relative to currently displayed year
7271 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
7272 showOtherMonths: false, // True to show dates in other months, false to leave blank
7273 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
7274 showWeek: false, // True to show week of the year, false to not show it
7275 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
7276 // takes a Date and returns the number of the week for it
7277 shortYearCutoff: "+10", // Short year values < this are in the current century,
7278 // > this are in the previous century,
7279 // string value starting with "+" for current year + value
7280 minDate: null, // The earliest selectable date, or null for no limit
7281 maxDate: null, // The latest selectable date, or null for no limit
7282 duration: "fast", // Duration of display/closure
7283 beforeShowDay: null, // Function that takes a date and returns an array with
7284 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
7285 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
7286 beforeShow: null, // Function that takes an input field and
7287 // returns a set of custom settings for the date picker
7288 onSelect: null, // Define a callback function when a date is selected
7289 onChangeMonthYear: null, // Define a callback function when the month or year is changed
7290 onClose: null, // Define a callback function when the datepicker is closed
7291 numberOfMonths: 1, // Number of months to show at a time
7292 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
7293 stepMonths: 1, // Number of months to step back/forward
7294 stepBigMonths: 12, // Number of months to step back/forward for the big links
7295 altField: "", // Selector for an alternate field to store selected dates into
7296 altFormat: "", // The date format to use for the alternate field
7297 constrainInput: true, // The input is constrained by the current date format
7298 showButtonPanel: false, // True to show button panel, false to not show it
7299 autoSize: false, // True to size the input for the date format, false to leave as is
7300 disabled: false // The initial disabled state
7301 };
7302 $.extend( this._defaults, this.regional[ "" ] );
7303 this.regional.en = $.extend( true, {}, this.regional[ "" ] );
7304 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
7305 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
7306 }
7307
7308 $.extend( Datepicker.prototype, {
7309 /* Class name added to elements to indicate already configured with a date picker. */
7310 markerClassName: "hasDatepicker",
7311
7312 //Keep track of the maximum number of rows displayed (see #7043)
7313 maxRows: 4,
7314
7315 // TODO rename to "widget" when switching to widget factory
7316 _widgetDatepicker: function() {
7317 return this.dpDiv;
7318 },
7319
7320 /* Override the default settings for all instances of the date picker.
7321 * @param settings object - the new settings to use as defaults (anonymous object)
7322 * @return the manager object
7323 */
7324 setDefaults: function( settings ) {
7325 datepicker_extendRemove( this._defaults, settings || {} );
7326 return this;
7327 },
7328
7329 /* Attach the date picker to a jQuery selection.
7330 * @param target element - the target input field or division or span
7331 * @param settings object - the new settings to use for this date picker instance (anonymous)
7332 */
7333 _attachDatepicker: function( target, settings ) {
7334 var nodeName, inline, inst;
7335 nodeName = target.nodeName.toLowerCase();
7336 inline = ( nodeName === "div" || nodeName === "span" );
7337 if ( !target.id ) {
7338 this.uuid += 1;
7339 target.id = "dp" + this.uuid;
7340 }
7341 inst = this._newInst( $( target ), inline );
7342 inst.settings = $.extend( {}, settings || {} );
7343 if ( nodeName === "input" ) {
7344 this._connectDatepicker( target, inst );
7345 } else if ( inline ) {
7346 this._inlineDatepicker( target, inst );
7347 }
7348 },
7349
7350 /* Create a new instance object. */
7351 _newInst: function( target, inline ) {
7352 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
7353 return { id: id, input: target, // associated target
7354 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
7355 drawMonth: 0, drawYear: 0, // month being drawn
7356 inline: inline, // is datepicker inline or not
7357 dpDiv: ( !inline ? this.dpDiv : // presentation div
7358 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
7359 },
7360
7361 /* Attach the date picker to an input field. */
7362 _connectDatepicker: function( target, inst ) {
7363 var input = $( target );
7364 inst.append = $( [] );
7365 inst.trigger = $( [] );
7366 if ( input.hasClass( this.markerClassName ) ) {
7367 return;
7368 }
7369 this._attachments( input, inst );
7370 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
7371 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
7372 this._autoSize( inst );
7373 $.data( target, "datepicker", inst );
7374
7375 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
7376 if ( inst.settings.disabled ) {
7377 this._disableDatepicker( target );
7378 }
7379 },
7380
7381 /* Make attachments based on settings. */
7382 _attachments: function( input, inst ) {
7383 var showOn, buttonText, buttonImage,
7384 appendText = this._get( inst, "appendText" ),
7385 isRTL = this._get( inst, "isRTL" );
7386
7387 if ( inst.append ) {
7388 inst.append.remove();
7389 }
7390 if ( appendText ) {
7391 inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
7392 input[ isRTL ? "before" : "after" ]( inst.append );
7393 }
7394
7395 input.off( "focus", this._showDatepicker );
7396
7397 if ( inst.trigger ) {
7398 inst.trigger.remove();
7399 }
7400
7401 showOn = this._get( inst, "showOn" );
7402 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
7403 input.on( "focus", this._showDatepicker );
7404 }
7405 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
7406 buttonText = this._get( inst, "buttonText" );
7407 buttonImage = this._get( inst, "buttonImage" );
7408 inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
7409 $( "<img/>" ).addClass( this._triggerClass ).
7410 attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
7411 $( "<button type='button'></button>" ).addClass( this._triggerClass ).
7412 html( !buttonImage ? buttonText : $( "<img/>" ).attr(
7413 { src:buttonImage, alt:buttonText, title:buttonText } ) ) );
7414 input[ isRTL ? "before" : "after" ]( inst.trigger );
7415 inst.trigger.on( "click", function() {
7416 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
7417 $.datepicker._hideDatepicker();
7418 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
7419 $.datepicker._hideDatepicker();
7420 $.datepicker._showDatepicker( input[ 0 ] );
7421 } else {
7422 $.datepicker._showDatepicker( input[ 0 ] );
7423 }
7424 return false;
7425 } );
7426 }
7427 },
7428
7429 /* Apply the maximum length for the date format. */
7430 _autoSize: function( inst ) {
7431 if ( this._get( inst, "autoSize" ) && !inst.inline ) {
7432 var findMax, max, maxI, i,
7433 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
7434 dateFormat = this._get( inst, "dateFormat" );
7435
7436 if ( dateFormat.match( /[DM]/ ) ) {
7437 findMax = function( names ) {
7438 max = 0;
7439 maxI = 0;
7440 for ( i = 0; i < names.length; i++ ) {
7441 if ( names[ i ].length > max ) {
7442 max = names[ i ].length;
7443 maxI = i;
7444 }
7445 }
7446 return maxI;
7447 };
7448 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
7449 "monthNames" : "monthNamesShort" ) ) ) );
7450 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
7451 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
7452 }
7453 inst.input.attr( "size", this._formatDate( inst, date ).length );
7454 }
7455 },
7456
7457 /* Attach an inline date picker to a div. */
7458 _inlineDatepicker: function( target, inst ) {
7459 var divSpan = $( target );
7460 if ( divSpan.hasClass( this.markerClassName ) ) {
7461 return;
7462 }
7463 divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
7464 $.data( target, "datepicker", inst );
7465 this._setDate( inst, this._getDefaultDate( inst ), true );
7466 this._updateDatepicker( inst );
7467 this._updateAlternate( inst );
7468
7469 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
7470 if ( inst.settings.disabled ) {
7471 this._disableDatepicker( target );
7472 }
7473
7474 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
7475 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
7476 inst.dpDiv.css( "display", "block" );
7477 },
7478
7479 /* Pop-up the date picker in a "dialog" box.
7480 * @param input element - ignored
7481 * @param date string or Date - the initial date to display
7482 * @param onSelect function - the function to call when a date is selected
7483 * @param settings object - update the dialog date picker instance's settings (anonymous object)
7484 * @param pos int[2] - coordinates for the dialog's position within the screen or
7485 * event - with x/y coordinates or
7486 * leave empty for default (screen centre)
7487 * @return the manager object
7488 */
7489 _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
7490 var id, browserWidth, browserHeight, scrollX, scrollY,
7491 inst = this._dialogInst; // internal instance
7492
7493 if ( !inst ) {
7494 this.uuid += 1;
7495 id = "dp" + this.uuid;
7496 this._dialogInput = $( "<input type='text' id='" + id +
7497 "' style='position: absolute; top: -100px; width: 0px;'/>" );
7498 this._dialogInput.on( "keydown", this._doKeyDown );
7499 $( "body" ).append( this._dialogInput );
7500 inst = this._dialogInst = this._newInst( this._dialogInput, false );
7501 inst.settings = {};
7502 $.data( this._dialogInput[ 0 ], "datepicker", inst );
7503 }
7504 datepicker_extendRemove( inst.settings, settings || {} );
7505 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
7506 this._dialogInput.val( date );
7507
7508 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
7509 if ( !this._pos ) {
7510 browserWidth = document.documentElement.clientWidth;
7511 browserHeight = document.documentElement.clientHeight;
7512 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
7513 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
7514 this._pos = // should use actual width/height below
7515 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
7516 }
7517
7518 // Move input on screen for focus, but hidden behind dialog
7519 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
7520 inst.settings.onSelect = onSelect;
7521 this._inDialog = true;
7522 this.dpDiv.addClass( this._dialogClass );
7523 this._showDatepicker( this._dialogInput[ 0 ] );
7524 if ( $.blockUI ) {
7525 $.blockUI( this.dpDiv );
7526 }
7527 $.data( this._dialogInput[ 0 ], "datepicker", inst );
7528 return this;
7529 },
7530
7531 /* Detach a datepicker from its control.
7532 * @param target element - the target input field or division or span
7533 */
7534 _destroyDatepicker: function( target ) {
7535 var nodeName,
7536 $target = $( target ),
7537 inst = $.data( target, "datepicker" );
7538
7539 if ( !$target.hasClass( this.markerClassName ) ) {
7540 return;
7541 }
7542
7543 nodeName = target.nodeName.toLowerCase();
7544 $.removeData( target, "datepicker" );
7545 if ( nodeName === "input" ) {
7546 inst.append.remove();
7547 inst.trigger.remove();
7548 $target.removeClass( this.markerClassName ).
7549 off( "focus", this._showDatepicker ).
7550 off( "keydown", this._doKeyDown ).
7551 off( "keypress", this._doKeyPress ).
7552 off( "keyup", this._doKeyUp );
7553 } else if ( nodeName === "div" || nodeName === "span" ) {
7554 $target.removeClass( this.markerClassName ).empty();
7555 }
7556
7557 if ( datepicker_instActive === inst ) {
7558 datepicker_instActive = null;
7559 }
7560 },
7561
7562 /* Enable the date picker to a jQuery selection.
7563 * @param target element - the target input field or division or span
7564 */
7565 _enableDatepicker: function( target ) {
7566 var nodeName, inline,
7567 $target = $( target ),
7568 inst = $.data( target, "datepicker" );
7569
7570 if ( !$target.hasClass( this.markerClassName ) ) {
7571 return;
7572 }
7573
7574 nodeName = target.nodeName.toLowerCase();
7575 if ( nodeName === "input" ) {
7576 target.disabled = false;
7577 inst.trigger.filter( "button" ).
7578 each( function() { this.disabled = false; } ).end().
7579 filter( "img" ).css( { opacity: "1.0", cursor: "" } );
7580 } else if ( nodeName === "div" || nodeName === "span" ) {
7581 inline = $target.children( "." + this._inlineClass );
7582 inline.children().removeClass( "ui-state-disabled" );
7583 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
7584 prop( "disabled", false );
7585 }
7586 this._disabledInputs = $.map( this._disabledInputs,
7587 function( value ) { return ( value === target ? null : value ); } ); // delete entry
7588 },
7589
7590 /* Disable the date picker to a jQuery selection.
7591 * @param target element - the target input field or division or span
7592 */
7593 _disableDatepicker: function( target ) {
7594 var nodeName, inline,
7595 $target = $( target ),
7596 inst = $.data( target, "datepicker" );
7597
7598 if ( !$target.hasClass( this.markerClassName ) ) {
7599 return;
7600 }
7601
7602 nodeName = target.nodeName.toLowerCase();
7603 if ( nodeName === "input" ) {
7604 target.disabled = true;
7605 inst.trigger.filter( "button" ).
7606 each( function() { this.disabled = true; } ).end().
7607 filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
7608 } else if ( nodeName === "div" || nodeName === "span" ) {
7609 inline = $target.children( "." + this._inlineClass );
7610 inline.children().addClass( "ui-state-disabled" );
7611 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
7612 prop( "disabled", true );
7613 }
7614 this._disabledInputs = $.map( this._disabledInputs,
7615 function( value ) { return ( value === target ? null : value ); } ); // delete entry
7616 this._disabledInputs[ this._disabledInputs.length ] = target;
7617 },
7618
7619 /* Is the first field in a jQuery collection disabled as a datepicker?
7620 * @param target element - the target input field or division or span
7621 * @return boolean - true if disabled, false if enabled
7622 */
7623 _isDisabledDatepicker: function( target ) {
7624 if ( !target ) {
7625 return false;
7626 }
7627 for ( var i = 0; i < this._disabledInputs.length; i++ ) {
7628 if ( this._disabledInputs[ i ] === target ) {
7629 return true;
7630 }
7631 }
7632 return false;
7633 },
7634
7635 /* Retrieve the instance data for the target control.
7636 * @param target element - the target input field or division or span
7637 * @return object - the associated instance data
7638 * @throws error if a jQuery problem getting data
7639 */
7640 _getInst: function( target ) {
7641 try {
7642 return $.data( target, "datepicker" );
7643 }
7644 catch ( err ) {
7645 throw "Missing instance data for this datepicker";
7646 }
7647 },
7648
7649 /* Update or retrieve the settings for a date picker attached to an input field or division.
7650 * @param target element - the target input field or division or span
7651 * @param name object - the new settings to update or
7652 * string - the name of the setting to change or retrieve,
7653 * when retrieving also "all" for all instance settings or
7654 * "defaults" for all global defaults
7655 * @param value any - the new value for the setting
7656 * (omit if above is an object or to retrieve a value)
7657 */
7658 _optionDatepicker: function( target, name, value ) {
7659 var settings, date, minDate, maxDate,
7660 inst = this._getInst( target );
7661
7662 if ( arguments.length === 2 && typeof name === "string" ) {
7663 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
7664 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
7665 this._get( inst, name ) ) : null ) );
7666 }
7667
7668 settings = name || {};
7669 if ( typeof name === "string" ) {
7670 settings = {};
7671 settings[ name ] = value;
7672 }
7673
7674 if ( inst ) {
7675 if ( this._curInst === inst ) {
7676 this._hideDatepicker();
7677 }
7678
7679 date = this._getDateDatepicker( target, true );
7680 minDate = this._getMinMaxDate( inst, "min" );
7681 maxDate = this._getMinMaxDate( inst, "max" );
7682 datepicker_extendRemove( inst.settings, settings );
7683
7684 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
7685 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
7686 inst.settings.minDate = this._formatDate( inst, minDate );
7687 }
7688 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
7689 inst.settings.maxDate = this._formatDate( inst, maxDate );
7690 }
7691 if ( "disabled" in settings ) {
7692 if ( settings.disabled ) {
7693 this._disableDatepicker( target );
7694 } else {
7695 this._enableDatepicker( target );
7696 }
7697 }
7698 this._attachments( $( target ), inst );
7699 this._autoSize( inst );
7700 this._setDate( inst, date );
7701 this._updateAlternate( inst );
7702 this._updateDatepicker( inst );
7703 }
7704 },
7705
7706 // Change method deprecated
7707 _changeDatepicker: function( target, name, value ) {
7708 this._optionDatepicker( target, name, value );
7709 },
7710
7711 /* Redraw the date picker attached to an input field or division.
7712 * @param target element - the target input field or division or span
7713 */
7714 _refreshDatepicker: function( target ) {
7715 var inst = this._getInst( target );
7716 if ( inst ) {
7717 this._updateDatepicker( inst );
7718 }
7719 },
7720
7721 /* Set the dates for a jQuery selection.
7722 * @param target element - the target input field or division or span
7723 * @param date Date - the new date
7724 */
7725 _setDateDatepicker: function( target, date ) {
7726 var inst = this._getInst( target );
7727 if ( inst ) {
7728 this._setDate( inst, date );
7729 this._updateDatepicker( inst );
7730 this._updateAlternate( inst );
7731 }
7732 },
7733
7734 /* Get the date(s) for the first entry in a jQuery selection.
7735 * @param target element - the target input field or division or span
7736 * @param noDefault boolean - true if no default date is to be used
7737 * @return Date - the current date
7738 */
7739 _getDateDatepicker: function( target, noDefault ) {
7740 var inst = this._getInst( target );
7741 if ( inst && !inst.inline ) {
7742 this._setDateFromField( inst, noDefault );
7743 }
7744 return ( inst ? this._getDate( inst ) : null );
7745 },
7746
7747 /* Handle keystrokes. */
7748 _doKeyDown: function( event ) {
7749 var onSelect, dateStr, sel,
7750 inst = $.datepicker._getInst( event.target ),
7751 handled = true,
7752 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
7753
7754 inst._keyEvent = true;
7755 if ( $.datepicker._datepickerShowing ) {
7756 switch ( event.keyCode ) {
7757 case 9: $.datepicker._hideDatepicker();
7758 handled = false;
7759 break; // hide on tab out
7760 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
7761 $.datepicker._currentClass + ")", inst.dpDiv );
7762 if ( sel[ 0 ] ) {
7763 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
7764 }
7765
7766 onSelect = $.datepicker._get( inst, "onSelect" );
7767 if ( onSelect ) {
7768 dateStr = $.datepicker._formatDate( inst );
7769
7770 // Trigger custom callback
7771 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
7772 } else {
7773 $.datepicker._hideDatepicker();
7774 }
7775
7776 return false; // don't submit the form
7777 case 27: $.datepicker._hideDatepicker();
7778 break; // hide on escape
7779 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7780 -$.datepicker._get( inst, "stepBigMonths" ) :
7781 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
7782 break; // previous month/year on page up/+ ctrl
7783 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7784 +$.datepicker._get( inst, "stepBigMonths" ) :
7785 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
7786 break; // next month/year on page down/+ ctrl
7787 case 35: if ( event.ctrlKey || event.metaKey ) {
7788 $.datepicker._clearDate( event.target );
7789 }
7790 handled = event.ctrlKey || event.metaKey;
7791 break; // clear on ctrl or command +end
7792 case 36: if ( event.ctrlKey || event.metaKey ) {
7793 $.datepicker._gotoToday( event.target );
7794 }
7795 handled = event.ctrlKey || event.metaKey;
7796 break; // current on ctrl or command +home
7797 case 37: if ( event.ctrlKey || event.metaKey ) {
7798 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
7799 }
7800 handled = event.ctrlKey || event.metaKey;
7801
7802 // -1 day on ctrl or command +left
7803 if ( event.originalEvent.altKey ) {
7804 $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7805 -$.datepicker._get( inst, "stepBigMonths" ) :
7806 -$.datepicker._get( inst, "stepMonths" ) ), "M" );
7807 }
7808
7809 // next month/year on alt +left on Mac
7810 break;
7811 case 38: if ( event.ctrlKey || event.metaKey ) {
7812 $.datepicker._adjustDate( event.target, -7, "D" );
7813 }
7814 handled = event.ctrlKey || event.metaKey;
7815 break; // -1 week on ctrl or command +up
7816 case 39: if ( event.ctrlKey || event.metaKey ) {
7817 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
7818 }
7819 handled = event.ctrlKey || event.metaKey;
7820
7821 // +1 day on ctrl or command +right
7822 if ( event.originalEvent.altKey ) {
7823 $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
7824 +$.datepicker._get( inst, "stepBigMonths" ) :
7825 +$.datepicker._get( inst, "stepMonths" ) ), "M" );
7826 }
7827
7828 // next month/year on alt +right
7829 break;
7830 case 40: if ( event.ctrlKey || event.metaKey ) {
7831 $.datepicker._adjustDate( event.target, +7, "D" );
7832 }
7833 handled = event.ctrlKey || event.metaKey;
7834 break; // +1 week on ctrl or command +down
7835 default: handled = false;
7836 }
7837 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
7838 $.datepicker._showDatepicker( this );
7839 } else {
7840 handled = false;
7841 }
7842
7843 if ( handled ) {
7844 event.preventDefault();
7845 event.stopPropagation();
7846 }
7847 },
7848
7849 /* Filter entered characters - based on date format. */
7850 _doKeyPress: function( event ) {
7851 var chars, chr,
7852 inst = $.datepicker._getInst( event.target );
7853
7854 if ( $.datepicker._get( inst, "constrainInput" ) ) {
7855 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
7856 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
7857 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
7858 }
7859 },
7860
7861 /* Synchronise manual entry and field/alternate field. */
7862 _doKeyUp: function( event ) {
7863 var date,
7864 inst = $.datepicker._getInst( event.target );
7865
7866 if ( inst.input.val() !== inst.lastVal ) {
7867 try {
7868 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
7869 ( inst.input ? inst.input.val() : null ),
7870 $.datepicker._getFormatConfig( inst ) );
7871
7872 if ( date ) { // only if valid
7873 $.datepicker._setDateFromField( inst );
7874 $.datepicker._updateAlternate( inst );
7875 $.datepicker._updateDatepicker( inst );
7876 }
7877 }
7878 catch ( err ) {
7879 }
7880 }
7881 return true;
7882 },
7883
7884 /* Pop-up the date picker for a given input field.
7885 * If false returned from beforeShow event handler do not show.
7886 * @param input element - the input field attached to the date picker or
7887 * event - if triggered by focus
7888 */
7889 _showDatepicker: function( input ) {
7890 input = input.target || input;
7891 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
7892 input = $( "input", input.parentNode )[ 0 ];
7893 }
7894
7895 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
7896 return;
7897 }
7898
7899 var inst, beforeShow, beforeShowSettings, isFixed,
7900 offset, showAnim, duration;
7901
7902 inst = $.datepicker._getInst( input );
7903 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
7904 $.datepicker._curInst.dpDiv.stop( true, true );
7905 if ( inst && $.datepicker._datepickerShowing ) {
7906 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
7907 }
7908 }
7909
7910 beforeShow = $.datepicker._get( inst, "beforeShow" );
7911 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
7912 if ( beforeShowSettings === false ) {
7913 return;
7914 }
7915 datepicker_extendRemove( inst.settings, beforeShowSettings );
7916
7917 inst.lastVal = null;
7918 $.datepicker._lastInput = input;
7919 $.datepicker._setDateFromField( inst );
7920
7921 if ( $.datepicker._inDialog ) { // hide cursor
7922 input.value = "";
7923 }
7924 if ( !$.datepicker._pos ) { // position below input
7925 $.datepicker._pos = $.datepicker._findPos( input );
7926 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
7927 }
7928
7929 isFixed = false;
7930 $( input ).parents().each( function() {
7931 isFixed |= $( this ).css( "position" ) === "fixed";
7932 return !isFixed;
7933 } );
7934
7935 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
7936 $.datepicker._pos = null;
7937
7938 //to avoid flashes on Firefox
7939 inst.dpDiv.empty();
7940
7941 // determine sizing offscreen
7942 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
7943 $.datepicker._updateDatepicker( inst );
7944
7945 // fix width for dynamic number of date pickers
7946 // and adjust position before showing
7947 offset = $.datepicker._checkOffset( inst, offset, isFixed );
7948 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
7949 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
7950 left: offset.left + "px", top: offset.top + "px" } );
7951
7952 if ( !inst.inline ) {
7953 showAnim = $.datepicker._get( inst, "showAnim" );
7954 duration = $.datepicker._get( inst, "duration" );
7955 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
7956 $.datepicker._datepickerShowing = true;
7957
7958 if ( $.effects && $.effects.effect[ showAnim ] ) {
7959 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
7960 } else {
7961 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
7962 }
7963
7964 if ( $.datepicker._shouldFocusInput( inst ) ) {
7965 inst.input.trigger( "focus" );
7966 }
7967
7968 $.datepicker._curInst = inst;
7969 }
7970 },
7971
7972 /* Generate the date picker content. */
7973 _updateDatepicker: function( inst ) {
7974 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
7975 datepicker_instActive = inst; // for delegate hover events
7976 inst.dpDiv.empty().append( this._generateHTML( inst ) );
7977 this._attachHandlers( inst );
7978
7979 var origyearshtml,
7980 numMonths = this._getNumberOfMonths( inst ),
7981 cols = numMonths[ 1 ],
7982 width = 17,
7983 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
7984
7985 if ( activeCell.length > 0 ) {
7986 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
7987 }
7988
7989 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
7990 if ( cols > 1 ) {
7991 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
7992 }
7993 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
7994 "Class" ]( "ui-datepicker-multi" );
7995 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
7996 "Class" ]( "ui-datepicker-rtl" );
7997
7998 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
7999 inst.input.trigger( "focus" );
8000 }
8001
8002 // Deffered render of the years select (to avoid flashes on Firefox)
8003 if ( inst.yearshtml ) {
8004 origyearshtml = inst.yearshtml;
8005 setTimeout( function() {
8006
8007 //assure that inst.yearshtml didn't change.
8008 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
8009 inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
8010 }
8011 origyearshtml = inst.yearshtml = null;
8012 }, 0 );
8013 }
8014 },
8015
8016 // #6694 - don't focus the input if it's already focused
8017 // this breaks the change event in IE
8018 // Support: IE and jQuery <1.9
8019 _shouldFocusInput: function( inst ) {
8020 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
8021 },
8022
8023 /* Check positioning to remain on screen. */
8024 _checkOffset: function( inst, offset, isFixed ) {
8025 var dpWidth = inst.dpDiv.outerWidth(),
8026 dpHeight = inst.dpDiv.outerHeight(),
8027 inputWidth = inst.input ? inst.input.outerWidth() : 0,
8028 inputHeight = inst.input ? inst.input.outerHeight() : 0,
8029 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
8030 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
8031
8032 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
8033 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
8034 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
8035
8036 // Now check if datepicker is showing outside window viewport - move to a better place if so.
8037 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
8038 Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
8039 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
8040 Math.abs( dpHeight + inputHeight ) : 0 );
8041
8042 return offset;
8043 },
8044
8045 /* Find an object's position on the screen. */
8046 _findPos: function( obj ) {
8047 var position,
8048 inst = this._getInst( obj ),
8049 isRTL = this._get( inst, "isRTL" );
8050
8051 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
8052 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
8053 }
8054
8055 position = $( obj ).offset();
8056 return [ position.left, position.top ];
8057 },
8058
8059 /* Hide the date picker from view.
8060 * @param input element - the input field attached to the date picker
8061 */
8062 _hideDatepicker: function( input ) {
8063 var showAnim, duration, postProcess, onClose,
8064 inst = this._curInst;
8065
8066 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
8067 return;
8068 }
8069
8070 if ( this._datepickerShowing ) {
8071 showAnim = this._get( inst, "showAnim" );
8072 duration = this._get( inst, "duration" );
8073 postProcess = function() {
8074 $.datepicker._tidyDialog( inst );
8075 };
8076
8077 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
8078 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
8079 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
8080 } else {
8081 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
8082 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
8083 }
8084
8085 if ( !showAnim ) {
8086 postProcess();
8087 }
8088 this._datepickerShowing = false;
8089
8090 onClose = this._get( inst, "onClose" );
8091 if ( onClose ) {
8092 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
8093 }
8094
8095 this._lastInput = null;
8096 if ( this._inDialog ) {
8097 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
8098 if ( $.blockUI ) {
8099 $.unblockUI();
8100 $( "body" ).append( this.dpDiv );
8101 }
8102 }
8103 this._inDialog = false;
8104 }
8105 },
8106
8107 /* Tidy up after a dialog display. */
8108 _tidyDialog: function( inst ) {
8109 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
8110 },
8111
8112 /* Close date picker if clicked elsewhere. */
8113 _checkExternalClick: function( event ) {
8114 if ( !$.datepicker._curInst ) {
8115 return;
8116 }
8117
8118 var $target = $( event.target ),
8119 inst = $.datepicker._getInst( $target[ 0 ] );
8120
8121 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
8122 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
8123 !$target.hasClass( $.datepicker.markerClassName ) &&
8124 !$target.closest( "." + $.datepicker._triggerClass ).length &&
8125 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
8126 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
8127 $.datepicker._hideDatepicker();
8128 }
8129 },
8130
8131 /* Adjust one of the date sub-fields. */
8132 _adjustDate: function( id, offset, period ) {
8133 var target = $( id ),
8134 inst = this._getInst( target[ 0 ] );
8135
8136 if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
8137 return;
8138 }
8139 this._adjustInstDate( inst, offset +
8140 ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
8141 period );
8142 this._updateDatepicker( inst );
8143 },
8144
8145 /* Action for current link. */
8146 _gotoToday: function( id ) {
8147 var date,
8148 target = $( id ),
8149 inst = this._getInst( target[ 0 ] );
8150
8151 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
8152 inst.selectedDay = inst.currentDay;
8153 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
8154 inst.drawYear = inst.selectedYear = inst.currentYear;
8155 } else {
8156 date = new Date();
8157 inst.selectedDay = date.getDate();
8158 inst.drawMonth = inst.selectedMonth = date.getMonth();
8159 inst.drawYear = inst.selectedYear = date.getFullYear();
8160 }
8161 this._notifyChange( inst );
8162 this._adjustDate( target );
8163 },
8164
8165 /* Action for selecting a new month/year. */
8166 _selectMonthYear: function( id, select, period ) {
8167 var target = $( id ),
8168 inst = this._getInst( target[ 0 ] );
8169
8170 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
8171 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
8172 parseInt( select.options[ select.selectedIndex ].value, 10 );
8173
8174 this._notifyChange( inst );
8175 this._adjustDate( target );
8176 },
8177
8178 /* Action for selecting a day. */
8179 _selectDay: function( id, month, year, td ) {
8180 var inst,
8181 target = $( id );
8182
8183 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
8184 return;
8185 }
8186
8187 inst = this._getInst( target[ 0 ] );
8188 inst.selectedDay = inst.currentDay = $( "a", td ).html();
8189 inst.selectedMonth = inst.currentMonth = month;
8190 inst.selectedYear = inst.currentYear = year;
8191 this._selectDate( id, this._formatDate( inst,
8192 inst.currentDay, inst.currentMonth, inst.currentYear ) );
8193 },
8194
8195 /* Erase the input field and hide the date picker. */
8196 _clearDate: function( id ) {
8197 var target = $( id );
8198 this._selectDate( target, "" );
8199 },
8200
8201 /* Update the input field with the selected date. */
8202 _selectDate: function( id, dateStr ) {
8203 var onSelect,
8204 target = $( id ),
8205 inst = this._getInst( target[ 0 ] );
8206
8207 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
8208 if ( inst.input ) {
8209 inst.input.val( dateStr );
8210 }
8211 this._updateAlternate( inst );
8212
8213 onSelect = this._get( inst, "onSelect" );
8214 if ( onSelect ) {
8215 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
8216 } else if ( inst.input ) {
8217 inst.input.trigger( "change" ); // fire the change event
8218 }
8219
8220 if ( inst.inline ) {
8221 this._updateDatepicker( inst );
8222 } else {
8223 this._hideDatepicker();
8224 this._lastInput = inst.input[ 0 ];
8225 if ( typeof( inst.input[ 0 ] ) !== "object" ) {
8226 inst.input.trigger( "focus" ); // restore focus
8227 }
8228 this._lastInput = null;
8229 }
8230 },
8231
8232 /* Update any alternate field to synchronise with the main field. */
8233 _updateAlternate: function( inst ) {
8234 var altFormat, date, dateStr,
8235 altField = this._get( inst, "altField" );
8236
8237 if ( altField ) { // update alternate field too
8238 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
8239 date = this._getDate( inst );
8240 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
8241 $( altField ).val( dateStr );
8242 }
8243 },
8244
8245 /* Set as beforeShowDay function to prevent selection of weekends.
8246 * @param date Date - the date to customise
8247 * @return [boolean, string] - is this date selectable?, what is its CSS class?
8248 */
8249 noWeekends: function( date ) {
8250 var day = date.getDay();
8251 return [ ( day > 0 && day < 6 ), "" ];
8252 },
8253
8254 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
8255 * @param date Date - the date to get the week for
8256 * @return number - the number of the week within the year that contains this date
8257 */
8258 iso8601Week: function( date ) {
8259 var time,
8260 checkDate = new Date( date.getTime() );
8261
8262 // Find Thursday of this week starting on Monday
8263 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
8264
8265 time = checkDate.getTime();
8266 checkDate.setMonth( 0 ); // Compare with Jan 1
8267 checkDate.setDate( 1 );
8268 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
8269 },
8270
8271 /* Parse a string value into a date object.
8272 * See formatDate below for the possible formats.
8273 *
8274 * @param format string - the expected format of the date
8275 * @param value string - the date in the above format
8276 * @param settings Object - attributes include:
8277 * shortYearCutoff number - the cutoff year for determining the century (optional)
8278 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8279 * dayNames string[7] - names of the days from Sunday (optional)
8280 * monthNamesShort string[12] - abbreviated names of the months (optional)
8281 * monthNames string[12] - names of the months (optional)
8282 * @return Date - the extracted date value or null if value is blank
8283 */
8284 parseDate: function( format, value, settings ) {
8285 if ( format == null || value == null ) {
8286 throw "Invalid arguments";
8287 }
8288
8289 value = ( typeof value === "object" ? value.toString() : value + "" );
8290 if ( value === "" ) {
8291 return null;
8292 }
8293
8294 var iFormat, dim, extra,
8295 iValue = 0,
8296 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
8297 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
8298 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
8299 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
8300 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
8301 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
8302 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
8303 year = -1,
8304 month = -1,
8305 day = -1,
8306 doy = -1,
8307 literal = false,
8308 date,
8309
8310 // Check whether a format character is doubled
8311 lookAhead = function( match ) {
8312 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8313 if ( matches ) {
8314 iFormat++;
8315 }
8316 return matches;
8317 },
8318
8319 // Extract a number from the string value
8320 getNumber = function( match ) {
8321 var isDoubled = lookAhead( match ),
8322 size = ( match === "@" ? 14 : ( match === "!" ? 20 :
8323 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
8324 minSize = ( match === "y" ? size : 1 ),
8325 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
8326 num = value.substring( iValue ).match( digits );
8327 if ( !num ) {
8328 throw "Missing number at position " + iValue;
8329 }
8330 iValue += num[ 0 ].length;
8331 return parseInt( num[ 0 ], 10 );
8332 },
8333
8334 // Extract a name from the string value and convert to an index
8335 getName = function( match, shortNames, longNames ) {
8336 var index = -1,
8337 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
8338 return [ [ k, v ] ];
8339 } ).sort( function( a, b ) {
8340 return -( a[ 1 ].length - b[ 1 ].length );
8341 } );
8342
8343 $.each( names, function( i, pair ) {
8344 var name = pair[ 1 ];
8345 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
8346 index = pair[ 0 ];
8347 iValue += name.length;
8348 return false;
8349 }
8350 } );
8351 if ( index !== -1 ) {
8352 return index + 1;
8353 } else {
8354 throw "Unknown name at position " + iValue;
8355 }
8356 },
8357
8358 // Confirm that a literal character matches the string value
8359 checkLiteral = function() {
8360 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
8361 throw "Unexpected literal at position " + iValue;
8362 }
8363 iValue++;
8364 };
8365
8366 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8367 if ( literal ) {
8368 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8369 literal = false;
8370 } else {
8371 checkLiteral();
8372 }
8373 } else {
8374 switch ( format.charAt( iFormat ) ) {
8375 case "d":
8376 day = getNumber( "d" );
8377 break;
8378 case "D":
8379 getName( "D", dayNamesShort, dayNames );
8380 break;
8381 case "o":
8382 doy = getNumber( "o" );
8383 break;
8384 case "m":
8385 month = getNumber( "m" );
8386 break;
8387 case "M":
8388 month = getName( "M", monthNamesShort, monthNames );
8389 break;
8390 case "y":
8391 year = getNumber( "y" );
8392 break;
8393 case "@":
8394 date = new Date( getNumber( "@" ) );
8395 year = date.getFullYear();
8396 month = date.getMonth() + 1;
8397 day = date.getDate();
8398 break;
8399 case "!":
8400 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
8401 year = date.getFullYear();
8402 month = date.getMonth() + 1;
8403 day = date.getDate();
8404 break;
8405 case "'":
8406 if ( lookAhead( "'" ) ) {
8407 checkLiteral();
8408 } else {
8409 literal = true;
8410 }
8411 break;
8412 default:
8413 checkLiteral();
8414 }
8415 }
8416 }
8417
8418 if ( iValue < value.length ) {
8419 extra = value.substr( iValue );
8420 if ( !/^\s+/.test( extra ) ) {
8421 throw "Extra/unparsed characters found in date: " + extra;
8422 }
8423 }
8424
8425 if ( year === -1 ) {
8426 year = new Date().getFullYear();
8427 } else if ( year < 100 ) {
8428 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
8429 ( year <= shortYearCutoff ? 0 : -100 );
8430 }
8431
8432 if ( doy > -1 ) {
8433 month = 1;
8434 day = doy;
8435 do {
8436 dim = this._getDaysInMonth( year, month - 1 );
8437 if ( day <= dim ) {
8438 break;
8439 }
8440 month++;
8441 day -= dim;
8442 } while ( true );
8443 }
8444
8445 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
8446 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
8447 throw "Invalid date"; // E.g. 31/02/00
8448 }
8449 return date;
8450 },
8451
8452 /* Standard date formats. */
8453 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
8454 COOKIE: "D, dd M yy",
8455 ISO_8601: "yy-mm-dd",
8456 RFC_822: "D, d M y",
8457 RFC_850: "DD, dd-M-y",
8458 RFC_1036: "D, d M y",
8459 RFC_1123: "D, d M yy",
8460 RFC_2822: "D, d M yy",
8461 RSS: "D, d M y", // RFC 822
8462 TICKS: "!",
8463 TIMESTAMP: "@",
8464 W3C: "yy-mm-dd", // ISO 8601
8465
8466 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
8467 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
8468
8469 /* Format a date object into a string value.
8470 * The format can be combinations of the following:
8471 * d - day of month (no leading zero)
8472 * dd - day of month (two digit)
8473 * o - day of year (no leading zeros)
8474 * oo - day of year (three digit)
8475 * D - day name short
8476 * DD - day name long
8477 * m - month of year (no leading zero)
8478 * mm - month of year (two digit)
8479 * M - month name short
8480 * MM - month name long
8481 * y - year (two digit)
8482 * yy - year (four digit)
8483 * @ - Unix timestamp (ms since 01/01/1970)
8484 * ! - Windows ticks (100ns since 01/01/0001)
8485 * "..." - literal text
8486 * '' - single quote
8487 *
8488 * @param format string - the desired format of the date
8489 * @param date Date - the date value to format
8490 * @param settings Object - attributes include:
8491 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
8492 * dayNames string[7] - names of the days from Sunday (optional)
8493 * monthNamesShort string[12] - abbreviated names of the months (optional)
8494 * monthNames string[12] - names of the months (optional)
8495 * @return string - the date in the above format
8496 */
8497 formatDate: function( format, date, settings ) {
8498 if ( !date ) {
8499 return "";
8500 }
8501
8502 var iFormat,
8503 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
8504 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
8505 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
8506 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
8507
8508 // Check whether a format character is doubled
8509 lookAhead = function( match ) {
8510 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8511 if ( matches ) {
8512 iFormat++;
8513 }
8514 return matches;
8515 },
8516
8517 // Format a number, with leading zero if necessary
8518 formatNumber = function( match, value, len ) {
8519 var num = "" + value;
8520 if ( lookAhead( match ) ) {
8521 while ( num.length < len ) {
8522 num = "0" + num;
8523 }
8524 }
8525 return num;
8526 },
8527
8528 // Format a name, short or long as requested
8529 formatName = function( match, value, shortNames, longNames ) {
8530 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
8531 },
8532 output = "",
8533 literal = false;
8534
8535 if ( date ) {
8536 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8537 if ( literal ) {
8538 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8539 literal = false;
8540 } else {
8541 output += format.charAt( iFormat );
8542 }
8543 } else {
8544 switch ( format.charAt( iFormat ) ) {
8545 case "d":
8546 output += formatNumber( "d", date.getDate(), 2 );
8547 break;
8548 case "D":
8549 output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
8550 break;
8551 case "o":
8552 output += formatNumber( "o",
8553 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
8554 break;
8555 case "m":
8556 output += formatNumber( "m", date.getMonth() + 1, 2 );
8557 break;
8558 case "M":
8559 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
8560 break;
8561 case "y":
8562 output += ( lookAhead( "y" ) ? date.getFullYear() :
8563 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
8564 break;
8565 case "@":
8566 output += date.getTime();
8567 break;
8568 case "!":
8569 output += date.getTime() * 10000 + this._ticksTo1970;
8570 break;
8571 case "'":
8572 if ( lookAhead( "'" ) ) {
8573 output += "'";
8574 } else {
8575 literal = true;
8576 }
8577 break;
8578 default:
8579 output += format.charAt( iFormat );
8580 }
8581 }
8582 }
8583 }
8584 return output;
8585 },
8586
8587 /* Extract all possible characters from the date format. */
8588 _possibleChars: function( format ) {
8589 var iFormat,
8590 chars = "",
8591 literal = false,
8592
8593 // Check whether a format character is doubled
8594 lookAhead = function( match ) {
8595 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
8596 if ( matches ) {
8597 iFormat++;
8598 }
8599 return matches;
8600 };
8601
8602 for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
8603 if ( literal ) {
8604 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
8605 literal = false;
8606 } else {
8607 chars += format.charAt( iFormat );
8608 }
8609 } else {
8610 switch ( format.charAt( iFormat ) ) {
8611 case "d": case "m": case "y": case "@":
8612 chars += "0123456789";
8613 break;
8614 case "D": case "M":
8615 return null; // Accept anything
8616 case "'":
8617 if ( lookAhead( "'" ) ) {
8618 chars += "'";
8619 } else {
8620 literal = true;
8621 }
8622 break;
8623 default:
8624 chars += format.charAt( iFormat );
8625 }
8626 }
8627 }
8628 return chars;
8629 },
8630
8631 /* Get a setting value, defaulting if necessary. */
8632 _get: function( inst, name ) {
8633 return inst.settings[ name ] !== undefined ?
8634 inst.settings[ name ] : this._defaults[ name ];
8635 },
8636
8637 /* Parse existing date and initialise date picker. */
8638 _setDateFromField: function( inst, noDefault ) {
8639 if ( inst.input.val() === inst.lastVal ) {
8640 return;
8641 }
8642
8643 var dateFormat = this._get( inst, "dateFormat" ),
8644 dates = inst.lastVal = inst.input ? inst.input.val() : null,
8645 defaultDate = this._getDefaultDate( inst ),
8646 date = defaultDate,
8647 settings = this._getFormatConfig( inst );
8648
8649 try {
8650 date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
8651 } catch ( event ) {
8652 dates = ( noDefault ? "" : dates );
8653 }
8654 inst.selectedDay = date.getDate();
8655 inst.drawMonth = inst.selectedMonth = date.getMonth();
8656 inst.drawYear = inst.selectedYear = date.getFullYear();
8657 inst.currentDay = ( dates ? date.getDate() : 0 );
8658 inst.currentMonth = ( dates ? date.getMonth() : 0 );
8659 inst.currentYear = ( dates ? date.getFullYear() : 0 );
8660 this._adjustInstDate( inst );
8661 },
8662
8663 /* Retrieve the default date shown on opening. */
8664 _getDefaultDate: function( inst ) {
8665 return this._restrictMinMax( inst,
8666 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
8667 },
8668
8669 /* A date may be specified as an exact value or a relative one. */
8670 _determineDate: function( inst, date, defaultDate ) {
8671 var offsetNumeric = function( offset ) {
8672 var date = new Date();
8673 date.setDate( date.getDate() + offset );
8674 return date;
8675 },
8676 offsetString = function( offset ) {
8677 try {
8678 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
8679 offset, $.datepicker._getFormatConfig( inst ) );
8680 }
8681 catch ( e ) {
8682
8683 // Ignore
8684 }
8685
8686 var date = ( offset.toLowerCase().match( /^c/ ) ?
8687 $.datepicker._getDate( inst ) : null ) || new Date(),
8688 year = date.getFullYear(),
8689 month = date.getMonth(),
8690 day = date.getDate(),
8691 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
8692 matches = pattern.exec( offset );
8693
8694 while ( matches ) {
8695 switch ( matches[ 2 ] || "d" ) {
8696 case "d" : case "D" :
8697 day += parseInt( matches[ 1 ], 10 ); break;
8698 case "w" : case "W" :
8699 day += parseInt( matches[ 1 ], 10 ) * 7; break;
8700 case "m" : case "M" :
8701 month += parseInt( matches[ 1 ], 10 );
8702 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
8703 break;
8704 case "y": case "Y" :
8705 year += parseInt( matches[ 1 ], 10 );
8706 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
8707 break;
8708 }
8709 matches = pattern.exec( offset );
8710 }
8711 return new Date( year, month, day );
8712 },
8713 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
8714 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
8715
8716 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
8717 if ( newDate ) {
8718 newDate.setHours( 0 );
8719 newDate.setMinutes( 0 );
8720 newDate.setSeconds( 0 );
8721 newDate.setMilliseconds( 0 );
8722 }
8723 return this._daylightSavingAdjust( newDate );
8724 },
8725
8726 /* Handle switch to/from daylight saving.
8727 * Hours may be non-zero on daylight saving cut-over:
8728 * > 12 when midnight changeover, but then cannot generate
8729 * midnight datetime, so jump to 1AM, otherwise reset.
8730 * @param date (Date) the date to check
8731 * @return (Date) the corrected date
8732 */
8733 _daylightSavingAdjust: function( date ) {
8734 if ( !date ) {
8735 return null;
8736 }
8737 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
8738 return date;
8739 },
8740
8741 /* Set the date(s) directly. */
8742 _setDate: function( inst, date, noChange ) {
8743 var clear = !date,
8744 origMonth = inst.selectedMonth,
8745 origYear = inst.selectedYear,
8746 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
8747
8748 inst.selectedDay = inst.currentDay = newDate.getDate();
8749 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
8750 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
8751 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
8752 this._notifyChange( inst );
8753 }
8754 this._adjustInstDate( inst );
8755 if ( inst.input ) {
8756 inst.input.val( clear ? "" : this._formatDate( inst ) );
8757 }
8758 },
8759
8760 /* Retrieve the date(s) directly. */
8761 _getDate: function( inst ) {
8762 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
8763 this._daylightSavingAdjust( new Date(
8764 inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
8765 return startDate;
8766 },
8767
8768 /* Attach the onxxx handlers. These are declared statically so
8769 * they work with static code transformers like Caja.
8770 */
8771 _attachHandlers: function( inst ) {
8772 var stepMonths = this._get( inst, "stepMonths" ),
8773 id = "#" + inst.id.replace( /\\\\/g, "\\" );
8774 inst.dpDiv.find( "[data-handler]" ).map( function() {
8775 var handler = {
8776 prev: function() {
8777 $.datepicker._adjustDate( id, -stepMonths, "M" );
8778 },
8779 next: function() {
8780 $.datepicker._adjustDate( id, +stepMonths, "M" );
8781 },
8782 hide: function() {
8783 $.datepicker._hideDatepicker();
8784 },
8785 today: function() {
8786 $.datepicker._gotoToday( id );
8787 },
8788 selectDay: function() {
8789 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
8790 return false;
8791 },
8792 selectMonth: function() {
8793 $.datepicker._selectMonthYear( id, this, "M" );
8794 return false;
8795 },
8796 selectYear: function() {
8797 $.datepicker._selectMonthYear( id, this, "Y" );
8798 return false;
8799 }
8800 };
8801 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
8802 } );
8803 },
8804
8805 /* Generate the HTML for the current state of the date picker. */
8806 _generateHTML: function( inst ) {
8807 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
8808 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
8809 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
8810 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
8811 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
8812 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
8813 tempDate = new Date(),
8814 today = this._daylightSavingAdjust(
8815 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
8816 isRTL = this._get( inst, "isRTL" ),
8817 showButtonPanel = this._get( inst, "showButtonPanel" ),
8818 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
8819 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
8820 numMonths = this._getNumberOfMonths( inst ),
8821 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
8822 stepMonths = this._get( inst, "stepMonths" ),
8823 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
8824 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
8825 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
8826 minDate = this._getMinMaxDate( inst, "min" ),
8827 maxDate = this._getMinMaxDate( inst, "max" ),
8828 drawMonth = inst.drawMonth - showCurrentAtPos,
8829 drawYear = inst.drawYear;
8830
8831 if ( drawMonth < 0 ) {
8832 drawMonth += 12;
8833 drawYear--;
8834 }
8835 if ( maxDate ) {
8836 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
8837 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
8838 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
8839 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
8840 drawMonth--;
8841 if ( drawMonth < 0 ) {
8842 drawMonth = 11;
8843 drawYear--;
8844 }
8845 }
8846 }
8847 inst.drawMonth = drawMonth;
8848 inst.drawYear = drawYear;
8849
8850 prevText = this._get( inst, "prevText" );
8851 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
8852 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
8853 this._getFormatConfig( inst ) ) );
8854
8855 prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
8856 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
8857 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
8858 ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) );
8859
8860 nextText = this._get( inst, "nextText" );
8861 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
8862 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
8863 this._getFormatConfig( inst ) ) );
8864
8865 next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
8866 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
8867 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
8868 ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) );
8869
8870 currentText = this._get( inst, "currentText" );
8871 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
8872 currentText = ( !navigationAsDateFormat ? currentText :
8873 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
8874
8875 controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
8876 this._get( inst, "closeText" ) + "</button>" : "" );
8877
8878 buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
8879 ( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
8880 ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
8881
8882 firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
8883 firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
8884
8885 showWeek = this._get( inst, "showWeek" );
8886 dayNames = this._get( inst, "dayNames" );
8887 dayNamesMin = this._get( inst, "dayNamesMin" );
8888 monthNames = this._get( inst, "monthNames" );
8889 monthNamesShort = this._get( inst, "monthNamesShort" );
8890 beforeShowDay = this._get( inst, "beforeShowDay" );
8891 showOtherMonths = this._get( inst, "showOtherMonths" );
8892 selectOtherMonths = this._get( inst, "selectOtherMonths" );
8893 defaultDate = this._getDefaultDate( inst );
8894 html = "";
8895
8896 for ( row = 0; row < numMonths[ 0 ]; row++ ) {
8897 group = "";
8898 this.maxRows = 4;
8899 for ( col = 0; col < numMonths[ 1 ]; col++ ) {
8900 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
8901 cornerClass = " ui-corner-all";
8902 calender = "";
8903 if ( isMultiMonth ) {
8904 calender += "<div class='ui-datepicker-group";
8905 if ( numMonths[ 1 ] > 1 ) {
8906 switch ( col ) {
8907 case 0: calender += " ui-datepicker-group-first";
8908 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
8909 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
8910 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
8911 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
8912 }
8913 }
8914 calender += "'>";
8915 }
8916 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
8917 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
8918 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
8919 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
8920 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
8921 "</div><table class='ui-datepicker-calendar'><thead>" +
8922 "<tr>";
8923 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
8924 for ( dow = 0; dow < 7; dow++ ) { // days of the week
8925 day = ( dow + firstDay ) % 7;
8926 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
8927 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
8928 }
8929 calender += thead + "</tr></thead><tbody>";
8930 daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
8931 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
8932 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
8933 }
8934 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
8935 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
8936 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
8937 this.maxRows = numRows;
8938 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
8939 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
8940 calender += "<tr>";
8941 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
8942 this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
8943 for ( dow = 0; dow < 7; dow++ ) { // create date picker days
8944 daySettings = ( beforeShowDay ?
8945 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
8946 otherMonth = ( printDate.getMonth() !== drawMonth );
8947 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
8948 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
8949 tbody += "<td class='" +
8950 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
8951 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
8952 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
8953 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
8954
8955 // or defaultDate is current printedDate and defaultDate is selectedDate
8956 " " + this._dayOverClass : "" ) + // highlight selected day
8957 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
8958 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
8959 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
8960 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
8961 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
8962 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
8963 ( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
8964 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
8965 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
8966 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
8967 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
8968 "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
8969 printDate.setDate( printDate.getDate() + 1 );
8970 printDate = this._daylightSavingAdjust( printDate );
8971 }
8972 calender += tbody + "</tr>";
8973 }
8974 drawMonth++;
8975 if ( drawMonth > 11 ) {
8976 drawMonth = 0;
8977 drawYear++;
8978 }
8979 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
8980 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
8981 group += calender;
8982 }
8983 html += group;
8984 }
8985 html += buttonPanel;
8986 inst._keyEvent = false;
8987 return html;
8988 },
8989
8990 /* Generate the month and year header. */
8991 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
8992 secondary, monthNames, monthNamesShort ) {
8993
8994 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
8995 changeMonth = this._get( inst, "changeMonth" ),
8996 changeYear = this._get( inst, "changeYear" ),
8997 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
8998 html = "<div class='ui-datepicker-title'>",
8999 monthHtml = "";
9000
9001 // Month selection
9002 if ( secondary || !changeMonth ) {
9003 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
9004 } else {
9005 inMinYear = ( minDate && minDate.getFullYear() === drawYear );
9006 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
9007 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
9008 for ( month = 0; month < 12; month++ ) {
9009 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
9010 monthHtml += "<option value='" + month + "'" +
9011 ( month === drawMonth ? " selected='selected'" : "" ) +
9012 ">" + monthNamesShort[ month ] + "</option>";
9013 }
9014 }
9015 monthHtml += "</select>";
9016 }
9017
9018 if ( !showMonthAfterYear ) {
9019 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
9020 }
9021
9022 // Year selection
9023 if ( !inst.yearshtml ) {
9024 inst.yearshtml = "";
9025 if ( secondary || !changeYear ) {
9026 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
9027 } else {
9028
9029 // determine range of years to display
9030 years = this._get( inst, "yearRange" ).split( ":" );
9031 thisYear = new Date().getFullYear();
9032 determineYear = function( value ) {
9033 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
9034 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
9035 parseInt( value, 10 ) ) );
9036 return ( isNaN( year ) ? thisYear : year );
9037 };
9038 year = determineYear( years[ 0 ] );
9039 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
9040 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
9041 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
9042 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
9043 for ( ; year <= endYear; year++ ) {
9044 inst.yearshtml += "<option value='" + year + "'" +
9045 ( year === drawYear ? " selected='selected'" : "" ) +
9046 ">" + year + "</option>";
9047 }
9048 inst.yearshtml += "</select>";
9049
9050 html += inst.yearshtml;
9051 inst.yearshtml = null;
9052 }
9053 }
9054
9055 html += this._get( inst, "yearSuffix" );
9056 if ( showMonthAfterYear ) {
9057 html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
9058 }
9059 html += "</div>"; // Close datepicker_header
9060 return html;
9061 },
9062
9063 /* Adjust one of the date sub-fields. */
9064 _adjustInstDate: function( inst, offset, period ) {
9065 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
9066 month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
9067 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
9068 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
9069
9070 inst.selectedDay = date.getDate();
9071 inst.drawMonth = inst.selectedMonth = date.getMonth();
9072 inst.drawYear = inst.selectedYear = date.getFullYear();
9073 if ( period === "M" || period === "Y" ) {
9074 this._notifyChange( inst );
9075 }
9076 },
9077
9078 /* Ensure a date is within any min/max bounds. */
9079 _restrictMinMax: function( inst, date ) {
9080 var minDate = this._getMinMaxDate( inst, "min" ),
9081 maxDate = this._getMinMaxDate( inst, "max" ),
9082 newDate = ( minDate && date < minDate ? minDate : date );
9083 return ( maxDate && newDate > maxDate ? maxDate : newDate );
9084 },
9085
9086 /* Notify change of month/year. */
9087 _notifyChange: function( inst ) {
9088 var onChange = this._get( inst, "onChangeMonthYear" );
9089 if ( onChange ) {
9090 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
9091 [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
9092 }
9093 },
9094
9095 /* Determine the number of months to show. */
9096 _getNumberOfMonths: function( inst ) {
9097 var numMonths = this._get( inst, "numberOfMonths" );
9098 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
9099 },
9100
9101 /* Determine the current maximum date - ensure no time components are set. */
9102 _getMinMaxDate: function( inst, minMax ) {
9103 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
9104 },
9105
9106 /* Find the number of days in a given month. */
9107 _getDaysInMonth: function( year, month ) {
9108 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
9109 },
9110
9111 /* Find the day of the week of the first of a month. */
9112 _getFirstDayOfMonth: function( year, month ) {
9113 return new Date( year, month, 1 ).getDay();
9114 },
9115
9116 /* Determines if we should allow a "next/prev" month display change. */
9117 _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
9118 var numMonths = this._getNumberOfMonths( inst ),
9119 date = this._daylightSavingAdjust( new Date( curYear,
9120 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
9121
9122 if ( offset < 0 ) {
9123 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
9124 }
9125 return this._isInRange( inst, date );
9126 },
9127
9128 /* Is the given date in the accepted range? */
9129 _isInRange: function( inst, date ) {
9130 var yearSplit, currentYear,
9131 minDate = this._getMinMaxDate( inst, "min" ),
9132 maxDate = this._getMinMaxDate( inst, "max" ),
9133 minYear = null,
9134 maxYear = null,
9135 years = this._get( inst, "yearRange" );
9136 if ( years ) {
9137 yearSplit = years.split( ":" );
9138 currentYear = new Date().getFullYear();
9139 minYear = parseInt( yearSplit[ 0 ], 10 );
9140 maxYear = parseInt( yearSplit[ 1 ], 10 );
9141 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
9142 minYear += currentYear;
9143 }
9144 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
9145 maxYear += currentYear;
9146 }
9147 }
9148
9149 return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
9150 ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
9151 ( !minYear || date.getFullYear() >= minYear ) &&
9152 ( !maxYear || date.getFullYear() <= maxYear ) );
9153 },
9154
9155 /* Provide the configuration settings for formatting/parsing. */
9156 _getFormatConfig: function( inst ) {
9157 var shortYearCutoff = this._get( inst, "shortYearCutoff" );
9158 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
9159 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
9160 return { shortYearCutoff: shortYearCutoff,
9161 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
9162 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
9163 },
9164
9165 /* Format the given date for display. */
9166 _formatDate: function( inst, day, month, year ) {
9167 if ( !day ) {
9168 inst.currentDay = inst.selectedDay;
9169 inst.currentMonth = inst.selectedMonth;
9170 inst.currentYear = inst.selectedYear;
9171 }
9172 var date = ( day ? ( typeof day === "object" ? day :
9173 this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
9174 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
9175 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
9176 }
9177 } );
9178
9179 /*
9180 * Bind hover events for datepicker elements.
9181 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
9182 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
9183 */
9184 function datepicker_bindHover( dpDiv ) {
9185 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
9186 return dpDiv.on( "mouseout", selector, function() {
9187 $( this ).removeClass( "ui-state-hover" );
9188 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
9189 $( this ).removeClass( "ui-datepicker-prev-hover" );
9190 }
9191 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
9192 $( this ).removeClass( "ui-datepicker-next-hover" );
9193 }
9194 } )
9195 .on( "mouseover", selector, datepicker_handleMouseover );
9196 }
9197
9198 function datepicker_handleMouseover() {
9199 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
9200 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
9201 $( this ).addClass( "ui-state-hover" );
9202 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
9203 $( this ).addClass( "ui-datepicker-prev-hover" );
9204 }
9205 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
9206 $( this ).addClass( "ui-datepicker-next-hover" );
9207 }
9208 }
9209 }
9210
9211 /* jQuery extend now ignores nulls! */
9212 function datepicker_extendRemove( target, props ) {
9213 $.extend( target, props );
9214 for ( var name in props ) {
9215 if ( props[ name ] == null ) {
9216 target[ name ] = props[ name ];
9217 }
9218 }
9219 return target;
9220 }
9221
9222 /* Invoke the datepicker functionality.
9223 @param options string - a command, optionally followed by additional parameters or
9224 Object - settings for attaching new datepicker functionality
9225 @return jQuery object */
9226 $.fn.datepicker = function( options ) {
9227
9228 /* Verify an empty collection wasn't passed - Fixes #6976 */
9229 if ( !this.length ) {
9230 return this;
9231 }
9232
9233 /* Initialise the date picker. */
9234 if ( !$.datepicker.initialized ) {
9235 $( document ).on( "mousedown", $.datepicker._checkExternalClick );
9236 $.datepicker.initialized = true;
9237 }
9238
9239 /* Append datepicker main container to body if not exist. */
9240 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
9241 $( "body" ).append( $.datepicker.dpDiv );
9242 }
9243
9244 var otherArgs = Array.prototype.slice.call( arguments, 1 );
9245 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
9246 return $.datepicker[ "_" + options + "Datepicker" ].
9247 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
9248 }
9249 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
9250 return $.datepicker[ "_" + options + "Datepicker" ].
9251 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
9252 }
9253 return this.each( function() {
9254 typeof options === "string" ?
9255 $.datepicker[ "_" + options + "Datepicker" ].
9256 apply( $.datepicker, [ this ].concat( otherArgs ) ) :
9257 $.datepicker._attachDatepicker( this, options );
9258 } );
9259 };
9260
9261 $.datepicker = new Datepicker(); // singleton instance
9262 $.datepicker.initialized = false;
9263 $.datepicker.uuid = new Date().getTime();
9264 $.datepicker.version = "1.12.1";
9265
9266 var widgetsDatepicker = $.datepicker;
9267
9268
9269
9270
9271 // This file is deprecated
9272 var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
9273
9274 /*!
9275 * jQuery UI Mouse 1.12.1
9276 * http://jqueryui.com
9277 *
9278 * Copyright jQuery Foundation and other contributors
9279 * Released under the MIT license.
9280 * http://jquery.org/license
9281 */
9282
9283 //>>label: Mouse
9284 //>>group: Widgets
9285 //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
9286 //>>docs: http://api.jqueryui.com/mouse/
9287
9288
9289
9290 var mouseHandled = false;
9291 $( document ).on( "mouseup", function() {
9292 mouseHandled = false;
9293 } );
9294
9295 var widgetsMouse = $.widget( "ui.mouse", {
9296 version: "1.12.1",
9297 options: {
9298 cancel: "input, textarea, button, select, option",
9299 distance: 1,
9300 delay: 0
9301 },
9302 _mouseInit: function() {
9303 var that = this;
9304
9305 this.element
9306 .on( "mousedown." + this.widgetName, function( event ) {
9307 return that._mouseDown( event );
9308 } )
9309 .on( "click." + this.widgetName, function( event ) {
9310 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
9311 $.removeData( event.target, that.widgetName + ".preventClickEvent" );
9312 event.stopImmediatePropagation();
9313 return false;
9314 }
9315 } );
9316
9317 this.started = false;
9318 },
9319
9320 // TODO: make sure destroying one instance of mouse doesn't mess with
9321 // other instances of mouse
9322 _mouseDestroy: function() {
9323 this.element.off( "." + this.widgetName );
9324 if ( this._mouseMoveDelegate ) {
9325 this.document
9326 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9327 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
9328 }
9329 },
9330
9331 _mouseDown: function( event ) {
9332
9333 // don't let more than one widget handle mouseStart
9334 if ( mouseHandled ) {
9335 return;
9336 }
9337
9338 this._mouseMoved = false;
9339
9340 // We may have missed mouseup (out of window)
9341 ( this._mouseStarted && this._mouseUp( event ) );
9342
9343 this._mouseDownEvent = event;
9344
9345 var that = this,
9346 btnIsLeft = ( event.which === 1 ),
9347
9348 // event.target.nodeName works around a bug in IE 8 with
9349 // disabled inputs (#7620)
9350 elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
9351 $( event.target ).closest( this.options.cancel ).length : false );
9352 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
9353 return true;
9354 }
9355
9356 this.mouseDelayMet = !this.options.delay;
9357 if ( !this.mouseDelayMet ) {
9358 this._mouseDelayTimer = setTimeout( function() {
9359 that.mouseDelayMet = true;
9360 }, this.options.delay );
9361 }
9362
9363 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
9364 this._mouseStarted = ( this._mouseStart( event ) !== false );
9365 if ( !this._mouseStarted ) {
9366 event.preventDefault();
9367 return true;
9368 }
9369 }
9370
9371 // Click event may never have fired (Gecko & Opera)
9372 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
9373 $.removeData( event.target, this.widgetName + ".preventClickEvent" );
9374 }
9375
9376 // These delegates are required to keep context
9377 this._mouseMoveDelegate = function( event ) {
9378 return that._mouseMove( event );
9379 };
9380 this._mouseUpDelegate = function( event ) {
9381 return that._mouseUp( event );
9382 };
9383
9384 this.document
9385 .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9386 .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
9387
9388 event.preventDefault();
9389
9390 mouseHandled = true;
9391 return true;
9392 },
9393
9394 _mouseMove: function( event ) {
9395
9396 // Only check for mouseups outside the document if you've moved inside the document
9397 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
9398 // fire a mousemove event if content is placed under the cursor. See #7778
9399 // Support: IE <9
9400 if ( this._mouseMoved ) {
9401
9402 // IE mouseup check - mouseup happened when mouse was out of window
9403 if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
9404 !event.button ) {
9405 return this._mouseUp( event );
9406
9407 // Iframe mouseup check - mouseup occurred in another document
9408 } else if ( !event.which ) {
9409
9410 // Support: Safari <=8 - 9
9411 // Safari sets which to 0 if you press any of the following keys
9412 // during a drag (#14461)
9413 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
9414 event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
9415 this.ignoreMissingWhich = true;
9416 } else if ( !this.ignoreMissingWhich ) {
9417 return this._mouseUp( event );
9418 }
9419 }
9420 }
9421
9422 if ( event.which || event.button ) {
9423 this._mouseMoved = true;
9424 }
9425
9426 if ( this._mouseStarted ) {
9427 this._mouseDrag( event );
9428 return event.preventDefault();
9429 }
9430
9431 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
9432 this._mouseStarted =
9433 ( this._mouseStart( this._mouseDownEvent, event ) !== false );
9434 ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
9435 }
9436
9437 return !this._mouseStarted;
9438 },
9439
9440 _mouseUp: function( event ) {
9441 this.document
9442 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
9443 .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
9444
9445 if ( this._mouseStarted ) {
9446 this._mouseStarted = false;
9447
9448 if ( event.target === this._mouseDownEvent.target ) {
9449 $.data( event.target, this.widgetName + ".preventClickEvent", true );
9450 }
9451
9452 this._mouseStop( event );
9453 }
9454
9455 if ( this._mouseDelayTimer ) {
9456 clearTimeout( this._mouseDelayTimer );
9457 delete this._mouseDelayTimer;
9458 }
9459
9460 this.ignoreMissingWhich = false;
9461 mouseHandled = false;
9462 event.preventDefault();
9463 },
9464
9465 _mouseDistanceMet: function( event ) {
9466 return ( Math.max(
9467 Math.abs( this._mouseDownEvent.pageX - event.pageX ),
9468 Math.abs( this._mouseDownEvent.pageY - event.pageY )
9469 ) >= this.options.distance
9470 );
9471 },
9472
9473 _mouseDelayMet: function( /* event */ ) {
9474 return this.mouseDelayMet;
9475 },
9476
9477 // These are placeholder methods, to be overriden by extending plugin
9478 _mouseStart: function( /* event */ ) {},
9479 _mouseDrag: function( /* event */ ) {},
9480 _mouseStop: function( /* event */ ) {},
9481 _mouseCapture: function( /* event */ ) { return true; }
9482 } );
9483
9484
9485
9486
9487 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
9488 var plugin = $.ui.plugin = {
9489 add: function( module, option, set ) {
9490 var i,
9491 proto = $.ui[ module ].prototype;
9492 for ( i in set ) {
9493 proto.plugins[ i ] = proto.plugins[ i ] || [];
9494 proto.plugins[ i ].push( [ option, set[ i ] ] );
9495 }
9496 },
9497 call: function( instance, name, args, allowDisconnected ) {
9498 var i,
9499 set = instance.plugins[ name ];
9500
9501 if ( !set ) {
9502 return;
9503 }
9504
9505 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
9506 instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
9507 return;
9508 }
9509
9510 for ( i = 0; i < set.length; i++ ) {
9511 if ( instance.options[ set[ i ][ 0 ] ] ) {
9512 set[ i ][ 1 ].apply( instance.element, args );
9513 }
9514 }
9515 }
9516 };
9517
9518
9519
9520 var safeBlur = $.ui.safeBlur = function( element ) {
9521
9522 // Support: IE9 - 10 only
9523 // If the <body> is blurred, IE will switch windows, see #9420
9524 if ( element && element.nodeName.toLowerCase() !== "body" ) {
9525 $( element ).trigger( "blur" );
9526 }
9527 };
9528
9529
9530 /*!
9531 * jQuery UI Draggable 1.12.1
9532 * http://jqueryui.com
9533 *
9534 * Copyright jQuery Foundation and other contributors
9535 * Released under the MIT license.
9536 * http://jquery.org/license
9537 */
9538
9539 //>>label: Draggable
9540 //>>group: Interactions
9541 //>>description: Enables dragging functionality for any element.
9542 //>>docs: http://api.jqueryui.com/draggable/
9543 //>>demos: http://jqueryui.com/draggable/
9544 //>>css.structure: ../../themes/base/draggable.css
9545
9546
9547
9548 $.widget( "ui.draggable", $.ui.mouse, {
9549 version: "1.12.1",
9550 widgetEventPrefix: "drag",
9551 options: {
9552 addClasses: true,
9553 appendTo: "parent",
9554 axis: false,
9555 connectToSortable: false,
9556 containment: false,
9557 cursor: "auto",
9558 cursorAt: false,
9559 grid: false,
9560 handle: false,
9561 helper: "original",
9562 iframeFix: false,
9563 opacity: false,
9564 refreshPositions: false,
9565 revert: false,
9566 revertDuration: 500,
9567 scope: "default",
9568 scroll: true,
9569 scrollSensitivity: 20,
9570 scrollSpeed: 20,
9571 snap: false,
9572 snapMode: "both",
9573 snapTolerance: 20,
9574 stack: false,
9575 zIndex: false,
9576
9577 // Callbacks
9578 drag: null,
9579 start: null,
9580 stop: null
9581 },
9582 _create: function() {
9583
9584 if ( this.options.helper === "original" ) {
9585 this._setPositionRelative();
9586 }
9587 if ( this.options.addClasses ) {
9588 this._addClass( "ui-draggable" );
9589 }
9590 this._setHandleClassName();
9591
9592 this._mouseInit();
9593 },
9594
9595 _setOption: function( key, value ) {
9596 this._super( key, value );
9597 if ( key === "handle" ) {
9598 this._removeHandleClassName();
9599 this._setHandleClassName();
9600 }
9601 },
9602
9603 _destroy: function() {
9604 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
9605 this.destroyOnClear = true;
9606 return;
9607 }
9608 this._removeHandleClassName();
9609 this._mouseDestroy();
9610 },
9611
9612 _mouseCapture: function( event ) {
9613 var o = this.options;
9614
9615 // Among others, prevent a drag on a resizable-handle
9616 if ( this.helper || o.disabled ||
9617 $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
9618 return false;
9619 }
9620
9621 //Quit if we're not on a valid handle
9622 this.handle = this._getHandle( event );
9623 if ( !this.handle ) {
9624 return false;
9625 }
9626
9627 this._blurActiveElement( event );
9628
9629 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
9630
9631 return true;
9632
9633 },
9634
9635 _blockFrames: function( selector ) {
9636 this.iframeBlocks = this.document.find( selector ).map( function() {
9637 var iframe = $( this );
9638
9639 return $( "<div>" )
9640 .css( "position", "absolute" )
9641 .appendTo( iframe.parent() )
9642 .outerWidth( iframe.outerWidth() )
9643 .outerHeight( iframe.outerHeight() )
9644 .offset( iframe.offset() )[ 0 ];
9645 } );
9646 },
9647
9648 _unblockFrames: function() {
9649 if ( this.iframeBlocks ) {
9650 this.iframeBlocks.remove();
9651 delete this.iframeBlocks;
9652 }
9653 },
9654
9655 _blurActiveElement: function( event ) {
9656 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
9657 target = $( event.target );
9658
9659 // Don't blur if the event occurred on an element that is within
9660 // the currently focused element
9661 // See #10527, #12472
9662 if ( target.closest( activeElement ).length ) {
9663 return;
9664 }
9665
9666 // Blur any element that currently has focus, see #4261
9667 $.ui.safeBlur( activeElement );
9668 },
9669
9670 _mouseStart: function( event ) {
9671
9672 var o = this.options;
9673
9674 //Create and append the visible helper
9675 this.helper = this._createHelper( event );
9676
9677 this._addClass( this.helper, "ui-draggable-dragging" );
9678
9679 //Cache the helper size
9680 this._cacheHelperProportions();
9681
9682 //If ddmanager is used for droppables, set the global draggable
9683 if ( $.ui.ddmanager ) {
9684 $.ui.ddmanager.current = this;
9685 }
9686
9687 /*
9688 * - Position generation -
9689 * This block generates everything position related - it's the core of draggables.
9690 */
9691
9692 //Cache the margins of the original element
9693 this._cacheMargins();
9694
9695 //Store the helper's css position
9696 this.cssPosition = this.helper.css( "position" );
9697 this.scrollParent = this.helper.scrollParent( true );
9698 this.offsetParent = this.helper.offsetParent();
9699 this.hasFixedAncestor = this.helper.parents().filter( function() {
9700 return $( this ).css( "position" ) === "fixed";
9701 } ).length > 0;
9702
9703 //The element's absolute position on the page minus margins
9704 this.positionAbs = this.element.offset();
9705 this._refreshOffsets( event );
9706
9707 //Generate the original position
9708 this.originalPosition = this.position = this._generatePosition( event, false );
9709 this.originalPageX = event.pageX;
9710 this.originalPageY = event.pageY;
9711
9712 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
9713 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
9714
9715 //Set a containment if given in the options
9716 this._setContainment();
9717
9718 //Trigger event + callbacks
9719 if ( this._trigger( "start", event ) === false ) {
9720 this._clear();
9721 return false;
9722 }
9723
9724 //Recache the helper size
9725 this._cacheHelperProportions();
9726
9727 //Prepare the droppable offsets
9728 if ( $.ui.ddmanager && !o.dropBehaviour ) {
9729 $.ui.ddmanager.prepareOffsets( this, event );
9730 }
9731
9732 // Execute the drag once - this causes the helper not to be visible before getting its
9733 // correct position
9734 this._mouseDrag( event, true );
9735
9736 // If the ddmanager is used for droppables, inform the manager that dragging has started
9737 // (see #5003)
9738 if ( $.ui.ddmanager ) {
9739 $.ui.ddmanager.dragStart( this, event );
9740 }
9741
9742 return true;
9743 },
9744
9745 _refreshOffsets: function( event ) {
9746 this.offset = {
9747 top: this.positionAbs.top - this.margins.top,
9748 left: this.positionAbs.left - this.margins.left,
9749 scroll: false,
9750 parent: this._getParentOffset(),
9751 relative: this._getRelativeOffset()
9752 };
9753
9754 this.offset.click = {
9755 left: event.pageX - this.offset.left,
9756 top: event.pageY - this.offset.top
9757 };
9758 },
9759
9760 _mouseDrag: function( event, noPropagation ) {
9761
9762 // reset any necessary cached properties (see #5009)
9763 if ( this.hasFixedAncestor ) {
9764 this.offset.parent = this._getParentOffset();
9765 }
9766
9767 //Compute the helpers position
9768 this.position = this._generatePosition( event, true );
9769 this.positionAbs = this._convertPositionTo( "absolute" );
9770
9771 //Call plugins and callbacks and use the resulting position if something is returned
9772 if ( !noPropagation ) {
9773 var ui = this._uiHash();
9774 if ( this._trigger( "drag", event, ui ) === false ) {
9775 this._mouseUp( new $.Event( "mouseup", event ) );
9776 return false;
9777 }
9778 this.position = ui.position;
9779 }
9780
9781 this.helper[ 0 ].style.left = this.position.left + "px";
9782 this.helper[ 0 ].style.top = this.position.top + "px";
9783
9784 if ( $.ui.ddmanager ) {
9785 $.ui.ddmanager.drag( this, event );
9786 }
9787
9788 return false;
9789 },
9790
9791 _mouseStop: function( event ) {
9792
9793 //If we are using droppables, inform the manager about the drop
9794 var that = this,
9795 dropped = false;
9796 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
9797 dropped = $.ui.ddmanager.drop( this, event );
9798 }
9799
9800 //if a drop comes from outside (a sortable)
9801 if ( this.dropped ) {
9802 dropped = this.dropped;
9803 this.dropped = false;
9804 }
9805
9806 if ( ( this.options.revert === "invalid" && !dropped ) ||
9807 ( this.options.revert === "valid" && dropped ) ||
9808 this.options.revert === true || ( $.isFunction( this.options.revert ) &&
9809 this.options.revert.call( this.element, dropped ) )
9810 ) {
9811 $( this.helper ).animate(
9812 this.originalPosition,
9813 parseInt( this.options.revertDuration, 10 ),
9814 function() {
9815 if ( that._trigger( "stop", event ) !== false ) {
9816 that._clear();
9817 }
9818 }
9819 );
9820 } else {
9821 if ( this._trigger( "stop", event ) !== false ) {
9822 this._clear();
9823 }
9824 }
9825
9826 return false;
9827 },
9828
9829 _mouseUp: function( event ) {
9830 this._unblockFrames();
9831
9832 // If the ddmanager is used for droppables, inform the manager that dragging has stopped
9833 // (see #5003)
9834 if ( $.ui.ddmanager ) {
9835 $.ui.ddmanager.dragStop( this, event );
9836 }
9837
9838 // Only need to focus if the event occurred on the draggable itself, see #10527
9839 if ( this.handleElement.is( event.target ) ) {
9840
9841 // The interaction is over; whether or not the click resulted in a drag,
9842 // focus the element
9843 this.element.trigger( "focus" );
9844 }
9845
9846 return $.ui.mouse.prototype._mouseUp.call( this, event );
9847 },
9848
9849 cancel: function() {
9850
9851 if ( this.helper.is( ".ui-draggable-dragging" ) ) {
9852 this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
9853 } else {
9854 this._clear();
9855 }
9856
9857 return this;
9858
9859 },
9860
9861 _getHandle: function( event ) {
9862 return this.options.handle ?
9863 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
9864 true;
9865 },
9866
9867 _setHandleClassName: function() {
9868 this.handleElement = this.options.handle ?
9869 this.element.find( this.options.handle ) : this.element;
9870 this._addClass( this.handleElement, "ui-draggable-handle" );
9871 },
9872
9873 _removeHandleClassName: function() {
9874 this._removeClass( this.handleElement, "ui-draggable-handle" );
9875 },
9876
9877 _createHelper: function( event ) {
9878
9879 var o = this.options,
9880 helperIsFunction = $.isFunction( o.helper ),
9881 helper = helperIsFunction ?
9882 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
9883 ( o.helper === "clone" ?
9884 this.element.clone().removeAttr( "id" ) :
9885 this.element );
9886
9887 if ( !helper.parents( "body" ).length ) {
9888 helper.appendTo( ( o.appendTo === "parent" ?
9889 this.element[ 0 ].parentNode :
9890 o.appendTo ) );
9891 }
9892
9893 // Http://bugs.jqueryui.com/ticket/9446
9894 // a helper function can return the original element
9895 // which wouldn't have been set to relative in _create
9896 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
9897 this._setPositionRelative();
9898 }
9899
9900 if ( helper[ 0 ] !== this.element[ 0 ] &&
9901 !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
9902 helper.css( "position", "absolute" );
9903 }
9904
9905 return helper;
9906
9907 },
9908
9909 _setPositionRelative: function() {
9910 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
9911 this.element[ 0 ].style.position = "relative";
9912 }
9913 },
9914
9915 _adjustOffsetFromHelper: function( obj ) {
9916 if ( typeof obj === "string" ) {
9917 obj = obj.split( " " );
9918 }
9919 if ( $.isArray( obj ) ) {
9920 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
9921 }
9922 if ( "left" in obj ) {
9923 this.offset.click.left = obj.left + this.margins.left;
9924 }
9925 if ( "right" in obj ) {
9926 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
9927 }
9928 if ( "top" in obj ) {
9929 this.offset.click.top = obj.top + this.margins.top;
9930 }
9931 if ( "bottom" in obj ) {
9932 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
9933 }
9934 },
9935
9936 _isRootNode: function( element ) {
9937 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
9938 },
9939
9940 _getParentOffset: function() {
9941
9942 //Get the offsetParent and cache its position
9943 var po = this.offsetParent.offset(),
9944 document = this.document[ 0 ];
9945
9946 // This is a special case where we need to modify a offset calculated on start, since the
9947 // following happened:
9948 // 1. The position of the helper is absolute, so it's position is calculated based on the
9949 // next positioned parent
9950 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
9951 // the document, which means that the scroll is included in the initial calculation of the
9952 // offset of the parent, and never recalculated upon drag
9953 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
9954 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
9955 po.left += this.scrollParent.scrollLeft();
9956 po.top += this.scrollParent.scrollTop();
9957 }
9958
9959 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
9960 po = { top: 0, left: 0 };
9961 }
9962
9963 return {
9964 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
9965 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
9966 };
9967
9968 },
9969
9970 _getRelativeOffset: function() {
9971 if ( this.cssPosition !== "relative" ) {
9972 return { top: 0, left: 0 };
9973 }
9974
9975 var p = this.element.position(),
9976 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
9977
9978 return {
9979 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
9980 ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
9981 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
9982 ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
9983 };
9984
9985 },
9986
9987 _cacheMargins: function() {
9988 this.margins = {
9989 left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
9990 top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
9991 right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
9992 bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
9993 };
9994 },
9995
9996 _cacheHelperProportions: function() {
9997 this.helperProportions = {
9998 width: this.helper.outerWidth(),
9999 height: this.helper.outerHeight()
10000 };
10001 },
10002
10003 _setContainment: function() {
10004
10005 var isUserScrollable, c, ce,
10006 o = this.options,
10007 document = this.document[ 0 ];
10008
10009 this.relativeContainer = null;
10010
10011 if ( !o.containment ) {
10012 this.containment = null;
10013 return;
10014 }
10015
10016 if ( o.containment === "window" ) {
10017 this.containment = [
10018 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
10019 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
10020 $( window ).scrollLeft() + $( window ).width() -
10021 this.helperProportions.width - this.margins.left,
10022 $( window ).scrollTop() +
10023 ( $( window ).height() || document.body.parentNode.scrollHeight ) -
10024 this.helperProportions.height - this.margins.top
10025 ];
10026 return;
10027 }
10028
10029 if ( o.containment === "document" ) {
10030 this.containment = [
10031 0,
10032 0,
10033 $( document ).width() - this.helperProportions.width - this.margins.left,
10034 ( $( document ).height() || document.body.parentNode.scrollHeight ) -
10035 this.helperProportions.height - this.margins.top
10036 ];
10037 return;
10038 }
10039
10040 if ( o.containment.constructor === Array ) {
10041 this.containment = o.containment;
10042 return;
10043 }
10044
10045 if ( o.containment === "parent" ) {
10046 o.containment = this.helper[ 0 ].parentNode;
10047 }
10048
10049 c = $( o.containment );
10050 ce = c[ 0 ];
10051
10052 if ( !ce ) {
10053 return;
10054 }
10055
10056 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
10057
10058 this.containment = [
10059 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
10060 ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
10061 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
10062 ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
10063 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
10064 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
10065 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
10066 this.helperProportions.width -
10067 this.margins.left -
10068 this.margins.right,
10069 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
10070 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
10071 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
10072 this.helperProportions.height -
10073 this.margins.top -
10074 this.margins.bottom
10075 ];
10076 this.relativeContainer = c;
10077 },
10078
10079 _convertPositionTo: function( d, pos ) {
10080
10081 if ( !pos ) {
10082 pos = this.position;
10083 }
10084
10085 var mod = d === "absolute" ? 1 : -1,
10086 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
10087
10088 return {
10089 top: (
10090
10091 // The absolute mouse position
10092 pos.top +
10093
10094 // Only for relative positioned nodes: Relative offset from element to offset parent
10095 this.offset.relative.top * mod +
10096
10097 // The offsetParent's offset without borders (offset + border)
10098 this.offset.parent.top * mod -
10099 ( ( this.cssPosition === "fixed" ?
10100 -this.offset.scroll.top :
10101 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
10102 ),
10103 left: (
10104
10105 // The absolute mouse position
10106 pos.left +
10107
10108 // Only for relative positioned nodes: Relative offset from element to offset parent
10109 this.offset.relative.left * mod +
10110
10111 // The offsetParent's offset without borders (offset + border)
10112 this.offset.parent.left * mod -
10113 ( ( this.cssPosition === "fixed" ?
10114 -this.offset.scroll.left :
10115 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
10116 )
10117 };
10118
10119 },
10120
10121 _generatePosition: function( event, constrainPosition ) {
10122
10123 var containment, co, top, left,
10124 o = this.options,
10125 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
10126 pageX = event.pageX,
10127 pageY = event.pageY;
10128
10129 // Cache the scroll
10130 if ( !scrollIsRootNode || !this.offset.scroll ) {
10131 this.offset.scroll = {
10132 top: this.scrollParent.scrollTop(),
10133 left: this.scrollParent.scrollLeft()
10134 };
10135 }
10136
10137 /*
10138 * - Position constraining -
10139 * Constrain the position to a mix of grid, containment.
10140 */
10141
10142 // If we are not dragging yet, we won't check for options
10143 if ( constrainPosition ) {
10144 if ( this.containment ) {
10145 if ( this.relativeContainer ) {
10146 co = this.relativeContainer.offset();
10147 containment = [
10148 this.containment[ 0 ] + co.left,
10149 this.containment[ 1 ] + co.top,
10150 this.containment[ 2 ] + co.left,
10151 this.containment[ 3 ] + co.top
10152 ];
10153 } else {
10154 containment = this.containment;
10155 }
10156
10157 if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
10158 pageX = containment[ 0 ] + this.offset.click.left;
10159 }
10160 if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
10161 pageY = containment[ 1 ] + this.offset.click.top;
10162 }
10163 if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
10164 pageX = containment[ 2 ] + this.offset.click.left;
10165 }
10166 if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
10167 pageY = containment[ 3 ] + this.offset.click.top;
10168 }
10169 }
10170
10171 if ( o.grid ) {
10172
10173 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid
10174 // argument errors in IE (see ticket #6950)
10175 top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
10176 this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
10177 pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
10178 top - this.offset.click.top > containment[ 3 ] ) ?
10179 top :
10180 ( ( top - this.offset.click.top >= containment[ 1 ] ) ?
10181 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
10182
10183 left = o.grid[ 0 ] ? this.originalPageX +
10184 Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
10185 this.originalPageX;
10186 pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
10187 left - this.offset.click.left > containment[ 2 ] ) ?
10188 left :
10189 ( ( left - this.offset.click.left >= containment[ 0 ] ) ?
10190 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
10191 }
10192
10193 if ( o.axis === "y" ) {
10194 pageX = this.originalPageX;
10195 }
10196
10197 if ( o.axis === "x" ) {
10198 pageY = this.originalPageY;
10199 }
10200 }
10201
10202 return {
10203 top: (
10204
10205 // The absolute mouse position
10206 pageY -
10207
10208 // Click offset (relative to the element)
10209 this.offset.click.top -
10210
10211 // Only for relative positioned nodes: Relative offset from element to offset parent
10212 this.offset.relative.top -
10213
10214 // The offsetParent's offset without borders (offset + border)
10215 this.offset.parent.top +
10216 ( this.cssPosition === "fixed" ?
10217 -this.offset.scroll.top :
10218 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
10219 ),
10220 left: (
10221
10222 // The absolute mouse position
10223 pageX -
10224
10225 // Click offset (relative to the element)
10226 this.offset.click.left -
10227
10228 // Only for relative positioned nodes: Relative offset from element to offset parent
10229 this.offset.relative.left -
10230
10231 // The offsetParent's offset without borders (offset + border)
10232 this.offset.parent.left +
10233 ( this.cssPosition === "fixed" ?
10234 -this.offset.scroll.left :
10235 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
10236 )
10237 };
10238
10239 },
10240
10241 _clear: function() {
10242 this._removeClass( this.helper, "ui-draggable-dragging" );
10243 if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
10244 this.helper.remove();
10245 }
10246 this.helper = null;
10247 this.cancelHelperRemoval = false;
10248 if ( this.destroyOnClear ) {
10249 this.destroy();
10250 }
10251 },
10252
10253 // From now on bulk stuff - mainly helpers
10254
10255 _trigger: function( type, event, ui ) {
10256 ui = ui || this._uiHash();
10257 $.ui.plugin.call( this, type, [ event, ui, this ], true );
10258
10259 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
10260 if ( /^(drag|start|stop)/.test( type ) ) {
10261 this.positionAbs = this._convertPositionTo( "absolute" );
10262 ui.offset = this.positionAbs;
10263 }
10264 return $.Widget.prototype._trigger.call( this, type, event, ui );
10265 },
10266
10267 plugins: {},
10268
10269 _uiHash: function() {
10270 return {
10271 helper: this.helper,
10272 position: this.position,
10273 originalPosition: this.originalPosition,
10274 offset: this.positionAbs
10275 };
10276 }
10277
10278 } );
10279
10280 $.ui.plugin.add( "draggable", "connectToSortable", {
10281 start: function( event, ui, draggable ) {
10282 var uiSortable = $.extend( {}, ui, {
10283 item: draggable.element
10284 } );
10285
10286 draggable.sortables = [];
10287 $( draggable.options.connectToSortable ).each( function() {
10288 var sortable = $( this ).sortable( "instance" );
10289
10290 if ( sortable && !sortable.options.disabled ) {
10291 draggable.sortables.push( sortable );
10292
10293 // RefreshPositions is called at drag start to refresh the containerCache
10294 // which is used in drag. This ensures it's initialized and synchronized
10295 // with any changes that might have happened on the page since initialization.
10296 sortable.refreshPositions();
10297 sortable._trigger( "activate", event, uiSortable );
10298 }
10299 } );
10300 },
10301 stop: function( event, ui, draggable ) {
10302 var uiSortable = $.extend( {}, ui, {
10303 item: draggable.element
10304 } );
10305
10306 draggable.cancelHelperRemoval = false;
10307
10308 $.each( draggable.sortables, function() {
10309 var sortable = this;
10310
10311 if ( sortable.isOver ) {
10312 sortable.isOver = 0;
10313
10314 // Allow this sortable to handle removing the helper
10315 draggable.cancelHelperRemoval = true;
10316 sortable.cancelHelperRemoval = false;
10317
10318 // Use _storedCSS To restore properties in the sortable,
10319 // as this also handles revert (#9675) since the draggable
10320 // may have modified them in unexpected ways (#8809)
10321 sortable._storedCSS = {
10322 position: sortable.placeholder.css( "position" ),
10323 top: sortable.placeholder.css( "top" ),
10324 left: sortable.placeholder.css( "left" )
10325 };
10326
10327 sortable._mouseStop( event );
10328
10329 // Once drag has ended, the sortable should return to using
10330 // its original helper, not the shared helper from draggable
10331 sortable.options.helper = sortable.options._helper;
10332 } else {
10333
10334 // Prevent this Sortable from removing the helper.
10335 // However, don't set the draggable to remove the helper
10336 // either as another connected Sortable may yet handle the removal.
10337 sortable.cancelHelperRemoval = true;
10338
10339 sortable._trigger( "deactivate", event, uiSortable );
10340 }
10341 } );
10342 },
10343 drag: function( event, ui, draggable ) {
10344 $.each( draggable.sortables, function() {
10345 var innermostIntersecting = false,
10346 sortable = this;
10347
10348 // Copy over variables that sortable's _intersectsWith uses
10349 sortable.positionAbs = draggable.positionAbs;
10350 sortable.helperProportions = draggable.helperProportions;
10351 sortable.offset.click = draggable.offset.click;
10352
10353 if ( sortable._intersectsWith( sortable.containerCache ) ) {
10354 innermostIntersecting = true;
10355
10356 $.each( draggable.sortables, function() {
10357
10358 // Copy over variables that sortable's _intersectsWith uses
10359 this.positionAbs = draggable.positionAbs;
10360 this.helperProportions = draggable.helperProportions;
10361 this.offset.click = draggable.offset.click;
10362
10363 if ( this !== sortable &&
10364 this._intersectsWith( this.containerCache ) &&
10365 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
10366 innermostIntersecting = false;
10367 }
10368
10369 return innermostIntersecting;
10370 } );
10371 }
10372
10373 if ( innermostIntersecting ) {
10374
10375 // If it intersects, we use a little isOver variable and set it once,
10376 // so that the move-in stuff gets fired only once.
10377 if ( !sortable.isOver ) {
10378 sortable.isOver = 1;
10379
10380 // Store draggable's parent in case we need to reappend to it later.
10381 draggable._parent = ui.helper.parent();
10382
10383 sortable.currentItem = ui.helper
10384 .appendTo( sortable.element )
10385 .data( "ui-sortable-item", true );
10386
10387 // Store helper option to later restore it
10388 sortable.options._helper = sortable.options.helper;
10389
10390 sortable.options.helper = function() {
10391 return ui.helper[ 0 ];
10392 };
10393
10394 // Fire the start events of the sortable with our passed browser event,
10395 // and our own helper (so it doesn't create a new one)
10396 event.target = sortable.currentItem[ 0 ];
10397 sortable._mouseCapture( event, true );
10398 sortable._mouseStart( event, true, true );
10399
10400 // Because the browser event is way off the new appended portlet,
10401 // modify necessary variables to reflect the changes
10402 sortable.offset.click.top = draggable.offset.click.top;
10403 sortable.offset.click.left = draggable.offset.click.left;
10404 sortable.offset.parent.left -= draggable.offset.parent.left -
10405 sortable.offset.parent.left;
10406 sortable.offset.parent.top -= draggable.offset.parent.top -
10407 sortable.offset.parent.top;
10408
10409 draggable._trigger( "toSortable", event );
10410
10411 // Inform draggable that the helper is in a valid drop zone,
10412 // used solely in the revert option to handle "valid/invalid".
10413 draggable.dropped = sortable.element;
10414
10415 // Need to refreshPositions of all sortables in the case that
10416 // adding to one sortable changes the location of the other sortables (#9675)
10417 $.each( draggable.sortables, function() {
10418 this.refreshPositions();
10419 } );
10420
10421 // Hack so receive/update callbacks work (mostly)
10422 draggable.currentItem = draggable.element;
10423 sortable.fromOutside = draggable;
10424 }
10425
10426 if ( sortable.currentItem ) {
10427 sortable._mouseDrag( event );
10428
10429 // Copy the sortable's position because the draggable's can potentially reflect
10430 // a relative position, while sortable is always absolute, which the dragged
10431 // element has now become. (#8809)
10432 ui.position = sortable.position;
10433 }
10434 } else {
10435
10436 // If it doesn't intersect with the sortable, and it intersected before,
10437 // we fake the drag stop of the sortable, but make sure it doesn't remove
10438 // the helper by using cancelHelperRemoval.
10439 if ( sortable.isOver ) {
10440
10441 sortable.isOver = 0;
10442 sortable.cancelHelperRemoval = true;
10443
10444 // Calling sortable's mouseStop would trigger a revert,
10445 // so revert must be temporarily false until after mouseStop is called.
10446 sortable.options._revert = sortable.options.revert;
10447 sortable.options.revert = false;
10448
10449 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
10450 sortable._mouseStop( event, true );
10451
10452 // Restore sortable behaviors that were modfied
10453 // when the draggable entered the sortable area (#9481)
10454 sortable.options.revert = sortable.options._revert;
10455 sortable.options.helper = sortable.options._helper;
10456
10457 if ( sortable.placeholder ) {
10458 sortable.placeholder.remove();
10459 }
10460
10461 // Restore and recalculate the draggable's offset considering the sortable
10462 // may have modified them in unexpected ways. (#8809, #10669)
10463 ui.helper.appendTo( draggable._parent );
10464 draggable._refreshOffsets( event );
10465 ui.position = draggable._generatePosition( event, true );
10466
10467 draggable._trigger( "fromSortable", event );
10468
10469 // Inform draggable that the helper is no longer in a valid drop zone
10470 draggable.dropped = false;
10471
10472 // Need to refreshPositions of all sortables just in case removing
10473 // from one sortable changes the location of other sortables (#9675)
10474 $.each( draggable.sortables, function() {
10475 this.refreshPositions();
10476 } );
10477 }
10478 }
10479 } );
10480 }
10481 } );
10482
10483 $.ui.plugin.add( "draggable", "cursor", {
10484 start: function( event, ui, instance ) {
10485 var t = $( "body" ),
10486 o = instance.options;
10487
10488 if ( t.css( "cursor" ) ) {
10489 o._cursor = t.css( "cursor" );
10490 }
10491 t.css( "cursor", o.cursor );
10492 },
10493 stop: function( event, ui, instance ) {
10494 var o = instance.options;
10495 if ( o._cursor ) {
10496 $( "body" ).css( "cursor", o._cursor );
10497 }
10498 }
10499 } );
10500
10501 $.ui.plugin.add( "draggable", "opacity", {
10502 start: function( event, ui, instance ) {
10503 var t = $( ui.helper ),
10504 o = instance.options;
10505 if ( t.css( "opacity" ) ) {
10506 o._opacity = t.css( "opacity" );
10507 }
10508 t.css( "opacity", o.opacity );
10509 },
10510 stop: function( event, ui, instance ) {
10511 var o = instance.options;
10512 if ( o._opacity ) {
10513 $( ui.helper ).css( "opacity", o._opacity );
10514 }
10515 }
10516 } );
10517
10518 $.ui.plugin.add( "draggable", "scroll", {
10519 start: function( event, ui, i ) {
10520 if ( !i.scrollParentNotHidden ) {
10521 i.scrollParentNotHidden = i.helper.scrollParent( false );
10522 }
10523
10524 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
10525 i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
10526 i.overflowOffset = i.scrollParentNotHidden.offset();
10527 }
10528 },
10529 drag: function( event, ui, i ) {
10530
10531 var o = i.options,
10532 scrolled = false,
10533 scrollParent = i.scrollParentNotHidden[ 0 ],
10534 document = i.document[ 0 ];
10535
10536 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
10537 if ( !o.axis || o.axis !== "x" ) {
10538 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
10539 o.scrollSensitivity ) {
10540 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
10541 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
10542 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
10543 }
10544 }
10545
10546 if ( !o.axis || o.axis !== "y" ) {
10547 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
10548 o.scrollSensitivity ) {
10549 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
10550 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
10551 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
10552 }
10553 }
10554
10555 } else {
10556
10557 if ( !o.axis || o.axis !== "x" ) {
10558 if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
10559 scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
10560 } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
10561 o.scrollSensitivity ) {
10562 scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
10563 }
10564 }
10565
10566 if ( !o.axis || o.axis !== "y" ) {
10567 if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
10568 scrolled = $( document ).scrollLeft(
10569 $( document ).scrollLeft() - o.scrollSpeed
10570 );
10571 } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
10572 o.scrollSensitivity ) {
10573 scrolled = $( document ).scrollLeft(
10574 $( document ).scrollLeft() + o.scrollSpeed
10575 );
10576 }
10577 }
10578
10579 }
10580
10581 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
10582 $.ui.ddmanager.prepareOffsets( i, event );
10583 }
10584
10585 }
10586 } );
10587
10588 $.ui.plugin.add( "draggable", "snap", {
10589 start: function( event, ui, i ) {
10590
10591 var o = i.options;
10592
10593 i.snapElements = [];
10594
10595 $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
10596 .each( function() {
10597 var $t = $( this ),
10598 $o = $t.offset();
10599 if ( this !== i.element[ 0 ] ) {
10600 i.snapElements.push( {
10601 item: this,
10602 width: $t.outerWidth(), height: $t.outerHeight(),
10603 top: $o.top, left: $o.left
10604 } );
10605 }
10606 } );
10607
10608 },
10609 drag: function( event, ui, inst ) {
10610
10611 var ts, bs, ls, rs, l, r, t, b, i, first,
10612 o = inst.options,
10613 d = o.snapTolerance,
10614 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
10615 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
10616
10617 for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
10618
10619 l = inst.snapElements[ i ].left - inst.margins.left;
10620 r = l + inst.snapElements[ i ].width;
10621 t = inst.snapElements[ i ].top - inst.margins.top;
10622 b = t + inst.snapElements[ i ].height;
10623
10624 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
10625 !$.contains( inst.snapElements[ i ].item.ownerDocument,
10626 inst.snapElements[ i ].item ) ) {
10627 if ( inst.snapElements[ i ].snapping ) {
10628 ( inst.options.snap.release &&
10629 inst.options.snap.release.call(
10630 inst.element,
10631 event,
10632 $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
10633 ) );
10634 }
10635 inst.snapElements[ i ].snapping = false;
10636 continue;
10637 }
10638
10639 if ( o.snapMode !== "inner" ) {
10640 ts = Math.abs( t - y2 ) <= d;
10641 bs = Math.abs( b - y1 ) <= d;
10642 ls = Math.abs( l - x2 ) <= d;
10643 rs = Math.abs( r - x1 ) <= d;
10644 if ( ts ) {
10645 ui.position.top = inst._convertPositionTo( "relative", {
10646 top: t - inst.helperProportions.height,
10647 left: 0
10648 } ).top;
10649 }
10650 if ( bs ) {
10651 ui.position.top = inst._convertPositionTo( "relative", {
10652 top: b,
10653 left: 0
10654 } ).top;
10655 }
10656 if ( ls ) {
10657 ui.position.left = inst._convertPositionTo( "relative", {
10658 top: 0,
10659 left: l - inst.helperProportions.width
10660 } ).left;
10661 }
10662 if ( rs ) {
10663 ui.position.left = inst._convertPositionTo( "relative", {
10664 top: 0,
10665 left: r
10666 } ).left;
10667 }
10668 }
10669
10670 first = ( ts || bs || ls || rs );
10671
10672 if ( o.snapMode !== "outer" ) {
10673 ts = Math.abs( t - y1 ) <= d;
10674 bs = Math.abs( b - y2 ) <= d;
10675 ls = Math.abs( l - x1 ) <= d;
10676 rs = Math.abs( r - x2 ) <= d;
10677 if ( ts ) {
10678 ui.position.top = inst._convertPositionTo( "relative", {
10679 top: t,
10680 left: 0
10681 } ).top;
10682 }
10683 if ( bs ) {
10684 ui.position.top = inst._convertPositionTo( "relative", {
10685 top: b - inst.helperProportions.height,
10686 left: 0
10687 } ).top;
10688 }
10689 if ( ls ) {
10690 ui.position.left = inst._convertPositionTo( "relative", {
10691 top: 0,
10692 left: l
10693 } ).left;
10694 }
10695 if ( rs ) {
10696 ui.position.left = inst._convertPositionTo( "relative", {
10697 top: 0,
10698 left: r - inst.helperProportions.width
10699 } ).left;
10700 }
10701 }
10702
10703 if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
10704 ( inst.options.snap.snap &&
10705 inst.options.snap.snap.call(
10706 inst.element,
10707 event,
10708 $.extend( inst._uiHash(), {
10709 snapItem: inst.snapElements[ i ].item
10710 } ) ) );
10711 }
10712 inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
10713
10714 }
10715
10716 }
10717 } );
10718
10719 $.ui.plugin.add( "draggable", "stack", {
10720 start: function( event, ui, instance ) {
10721 var min,
10722 o = instance.options,
10723 group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
10724 return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
10725 ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
10726 } );
10727
10728 if ( !group.length ) { return; }
10729
10730 min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
10731 $( group ).each( function( i ) {
10732 $( this ).css( "zIndex", min + i );
10733 } );
10734 this.css( "zIndex", ( min + group.length ) );
10735 }
10736 } );
10737
10738 $.ui.plugin.add( "draggable", "zIndex", {
10739 start: function( event, ui, instance ) {
10740 var t = $( ui.helper ),
10741 o = instance.options;
10742
10743 if ( t.css( "zIndex" ) ) {
10744 o._zIndex = t.css( "zIndex" );
10745 }
10746 t.css( "zIndex", o.zIndex );
10747 },
10748 stop: function( event, ui, instance ) {
10749 var o = instance.options;
10750
10751 if ( o._zIndex ) {
10752 $( ui.helper ).css( "zIndex", o._zIndex );
10753 }
10754 }
10755 } );
10756
10757 var widgetsDraggable = $.ui.draggable;
10758
10759
10760 /*!
10761 * jQuery UI Resizable 1.12.1
10762 * http://jqueryui.com
10763 *
10764 * Copyright jQuery Foundation and other contributors
10765 * Released under the MIT license.
10766 * http://jquery.org/license
10767 */
10768
10769 //>>label: Resizable
10770 //>>group: Interactions
10771 //>>description: Enables resize functionality for any element.
10772 //>>docs: http://api.jqueryui.com/resizable/
10773 //>>demos: http://jqueryui.com/resizable/
10774 //>>css.structure: ../../themes/base/core.css
10775 //>>css.structure: ../../themes/base/resizable.css
10776 //>>css.theme: ../../themes/base/theme.css
10777
10778
10779
10780 $.widget( "ui.resizable", $.ui.mouse, {
10781 version: "1.12.1",
10782 widgetEventPrefix: "resize",
10783 options: {
10784 alsoResize: false,
10785 animate: false,
10786 animateDuration: "slow",
10787 animateEasing: "swing",
10788 aspectRatio: false,
10789 autoHide: false,
10790 classes: {
10791 "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
10792 },
10793 containment: false,
10794 ghost: false,
10795 grid: false,
10796 handles: "e,s,se",
10797 helper: false,
10798 maxHeight: null,
10799 maxWidth: null,
10800 minHeight: 10,
10801 minWidth: 10,
10802
10803 // See #7960
10804 zIndex: 90,
10805
10806 // Callbacks
10807 resize: null,
10808 start: null,
10809 stop: null
10810 },
10811
10812 _num: function( value ) {
10813 return parseFloat( value ) || 0;
10814 },
10815
10816 _isNumber: function( value ) {
10817 return !isNaN( parseFloat( value ) );
10818 },
10819
10820 _hasScroll: function( el, a ) {
10821
10822 if ( $( el ).css( "overflow" ) === "hidden" ) {
10823 return false;
10824 }
10825
10826 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
10827 has = false;
10828
10829 if ( el[ scroll ] > 0 ) {
10830 return true;
10831 }
10832
10833 // TODO: determine which cases actually cause this to happen
10834 // if the element doesn't have the scroll set, see if it's possible to
10835 // set the scroll
10836 el[ scroll ] = 1;
10837 has = ( el[ scroll ] > 0 );
10838 el[ scroll ] = 0;
10839 return has;
10840 },
10841
10842 _create: function() {
10843
10844 var margins,
10845 o = this.options,
10846 that = this;
10847 this._addClass( "ui-resizable" );
10848
10849 $.extend( this, {
10850 _aspectRatio: !!( o.aspectRatio ),
10851 aspectRatio: o.aspectRatio,
10852 originalElement: this.element,
10853 _proportionallyResizeElements: [],
10854 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
10855 } );
10856
10857 // Wrap the element if it cannot hold child nodes
10858 if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
10859
10860 this.element.wrap(
10861 $( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
10862 position: this.element.css( "position" ),
10863 width: this.element.outerWidth(),
10864 height: this.element.outerHeight(),
10865 top: this.element.css( "top" ),
10866 left: this.element.css( "left" )
10867 } )
10868 );
10869
10870 this.element = this.element.parent().data(
10871 "ui-resizable", this.element.resizable( "instance" )
10872 );
10873
10874 this.elementIsWrapper = true;
10875
10876 margins = {
10877 marginTop: this.originalElement.css( "marginTop" ),
10878 marginRight: this.originalElement.css( "marginRight" ),
10879 marginBottom: this.originalElement.css( "marginBottom" ),
10880 marginLeft: this.originalElement.css( "marginLeft" )
10881 };
10882
10883 this.element.css( margins );
10884 this.originalElement.css( "margin", 0 );
10885
10886 // support: Safari
10887 // Prevent Safari textarea resize
10888 this.originalResizeStyle = this.originalElement.css( "resize" );
10889 this.originalElement.css( "resize", "none" );
10890
10891 this._proportionallyResizeElements.push( this.originalElement.css( {
10892 position: "static",
10893 zoom: 1,
10894 display: "block"
10895 } ) );
10896
10897 // Support: IE9
10898 // avoid IE jump (hard set the margin)
10899 this.originalElement.css( margins );
10900
10901 this._proportionallyResize();
10902 }
10903
10904 this._setupHandles();
10905
10906 if ( o.autoHide ) {
10907 $( this.element )
10908 .on( "mouseenter", function() {
10909 if ( o.disabled ) {
10910 return;
10911 }
10912 that._removeClass( "ui-resizable-autohide" );
10913 that._handles.show();
10914 } )
10915 .on( "mouseleave", function() {
10916 if ( o.disabled ) {
10917 return;
10918 }
10919 if ( !that.resizing ) {
10920 that._addClass( "ui-resizable-autohide" );
10921 that._handles.hide();
10922 }
10923 } );
10924 }
10925
10926 this._mouseInit();
10927 },
10928
10929 _destroy: function() {
10930
10931 this._mouseDestroy();
10932
10933 var wrapper,
10934 _destroy = function( exp ) {
10935 $( exp )
10936 .removeData( "resizable" )
10937 .removeData( "ui-resizable" )
10938 .off( ".resizable" )
10939 .find( ".ui-resizable-handle" )
10940 .remove();
10941 };
10942
10943 // TODO: Unwrap at same DOM position
10944 if ( this.elementIsWrapper ) {
10945 _destroy( this.element );
10946 wrapper = this.element;
10947 this.originalElement.css( {
10948 position: wrapper.css( "position" ),
10949 width: wrapper.outerWidth(),
10950 height: wrapper.outerHeight(),
10951 top: wrapper.css( "top" ),
10952 left: wrapper.css( "left" )
10953 } ).insertAfter( wrapper );
10954 wrapper.remove();
10955 }
10956
10957 this.originalElement.css( "resize", this.originalResizeStyle );
10958 _destroy( this.originalElement );
10959
10960 return this;
10961 },
10962
10963 _setOption: function( key, value ) {
10964 this._super( key, value );
10965
10966 switch ( key ) {
10967 case "handles":
10968 this._removeHandles();
10969 this._setupHandles();
10970 break;
10971 default:
10972 break;
10973 }
10974 },
10975
10976 _setupHandles: function() {
10977 var o = this.options, handle, i, n, hname, axis, that = this;
10978 this.handles = o.handles ||
10979 ( !$( ".ui-resizable-handle", this.element ).length ?
10980 "e,s,se" : {
10981 n: ".ui-resizable-n",
10982 e: ".ui-resizable-e",
10983 s: ".ui-resizable-s",
10984 w: ".ui-resizable-w",
10985 se: ".ui-resizable-se",
10986 sw: ".ui-resizable-sw",
10987 ne: ".ui-resizable-ne",
10988 nw: ".ui-resizable-nw"
10989 } );
10990
10991 this._handles = $();
10992 if ( this.handles.constructor === String ) {
10993
10994 if ( this.handles === "all" ) {
10995 this.handles = "n,e,s,w,se,sw,ne,nw";
10996 }
10997
10998 n = this.handles.split( "," );
10999 this.handles = {};
11000
11001 for ( i = 0; i < n.length; i++ ) {
11002
11003 handle = $.trim( n[ i ] );
11004 hname = "ui-resizable-" + handle;
11005 axis = $( "<div>" );
11006 this._addClass( axis, "ui-resizable-handle " + hname );
11007
11008 axis.css( { zIndex: o.zIndex } );
11009
11010 this.handles[ handle ] = ".ui-resizable-" + handle;
11011 this.element.append( axis );
11012 }
11013
11014 }
11015
11016 this._renderAxis = function( target ) {
11017
11018 var i, axis, padPos, padWrapper;
11019
11020 target = target || this.element;
11021
11022 for ( i in this.handles ) {
11023
11024 if ( this.handles[ i ].constructor === String ) {
11025 this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
11026 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
11027 this.handles[ i ] = $( this.handles[ i ] );
11028 this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
11029 }
11030
11031 if ( this.elementIsWrapper &&
11032 this.originalElement[ 0 ]
11033 .nodeName
11034 .match( /^(textarea|input|select|button)$/i ) ) {
11035 axis = $( this.handles[ i ], this.element );
11036
11037 padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
11038 axis.outerHeight() :
11039 axis.outerWidth();
11040
11041 padPos = [ "padding",
11042 /ne|nw|n/.test( i ) ? "Top" :
11043 /se|sw|s/.test( i ) ? "Bottom" :
11044 /^e$/.test( i ) ? "Right" : "Left" ].join( "" );
11045
11046 target.css( padPos, padWrapper );
11047
11048 this._proportionallyResize();
11049 }
11050
11051 this._handles = this._handles.add( this.handles[ i ] );
11052 }
11053 };
11054
11055 // TODO: make renderAxis a prototype function
11056 this._renderAxis( this.element );
11057
11058 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
11059 this._handles.disableSelection();
11060
11061 this._handles.on( "mouseover", function() {
11062 if ( !that.resizing ) {
11063 if ( this.className ) {
11064 axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
11065 }
11066 that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
11067 }
11068 } );
11069
11070 if ( o.autoHide ) {
11071 this._handles.hide();
11072 this._addClass( "ui-resizable-autohide" );
11073 }
11074 },
11075
11076 _removeHandles: function() {
11077 this._handles.remove();
11078 },
11079
11080 _mouseCapture: function( event ) {
11081 var i, handle,
11082 capture = false;
11083
11084 for ( i in this.handles ) {
11085 handle = $( this.handles[ i ] )[ 0 ];
11086 if ( handle === event.target || $.contains( handle, event.target ) ) {
11087 capture = true;
11088 }
11089 }
11090
11091 return !this.options.disabled && capture;
11092 },
11093
11094 _mouseStart: function( event ) {
11095
11096 var curleft, curtop, cursor,
11097 o = this.options,
11098 el = this.element;
11099
11100 this.resizing = true;
11101
11102 this._renderProxy();
11103
11104 curleft = this._num( this.helper.css( "left" ) );
11105 curtop = this._num( this.helper.css( "top" ) );
11106
11107 if ( o.containment ) {
11108 curleft += $( o.containment ).scrollLeft() || 0;
11109 curtop += $( o.containment ).scrollTop() || 0;
11110 }
11111
11112 this.offset = this.helper.offset();
11113 this.position = { left: curleft, top: curtop };
11114
11115 this.size = this._helper ? {
11116 width: this.helper.width(),
11117 height: this.helper.height()
11118 } : {
11119 width: el.width(),
11120 height: el.height()
11121 };
11122
11123 this.originalSize = this._helper ? {
11124 width: el.outerWidth(),
11125 height: el.outerHeight()
11126 } : {
11127 width: el.width(),
11128 height: el.height()
11129 };
11130
11131 this.sizeDiff = {
11132 width: el.outerWidth() - el.width(),
11133 height: el.outerHeight() - el.height()
11134 };
11135
11136 this.originalPosition = { left: curleft, top: curtop };
11137 this.originalMousePosition = { left: event.pageX, top: event.pageY };
11138
11139 this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
11140 o.aspectRatio :
11141 ( ( this.originalSize.width / this.originalSize.height ) || 1 );
11142
11143 cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
11144 $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
11145
11146 this._addClass( "ui-resizable-resizing" );
11147 this._propagate( "start", event );
11148 return true;
11149 },
11150
11151 _mouseDrag: function( event ) {
11152
11153 var data, props,
11154 smp = this.originalMousePosition,
11155 a = this.axis,
11156 dx = ( event.pageX - smp.left ) || 0,
11157 dy = ( event.pageY - smp.top ) || 0,
11158 trigger = this._change[ a ];
11159
11160 this._updatePrevProperties();
11161
11162 if ( !trigger ) {
11163 return false;
11164 }
11165
11166 data = trigger.apply( this, [ event, dx, dy ] );
11167
11168 this._updateVirtualBoundaries( event.shiftKey );
11169 if ( this._aspectRatio || event.shiftKey ) {
11170 data = this._updateRatio( data, event );
11171 }
11172
11173 data = this._respectSize( data, event );
11174
11175 this._updateCache( data );
11176
11177 this._propagate( "resize", event );
11178
11179 props = this._applyChanges();
11180
11181 if ( !this._helper && this._proportionallyResizeElements.length ) {
11182 this._proportionallyResize();
11183 }
11184
11185 if ( !$.isEmptyObject( props ) ) {
11186 this._updatePrevProperties();
11187 this._trigger( "resize", event, this.ui() );
11188 this._applyChanges();
11189 }
11190
11191 return false;
11192 },
11193
11194 _mouseStop: function( event ) {
11195
11196 this.resizing = false;
11197 var pr, ista, soffseth, soffsetw, s, left, top,
11198 o = this.options, that = this;
11199
11200 if ( this._helper ) {
11201
11202 pr = this._proportionallyResizeElements;
11203 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
11204 soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
11205 soffsetw = ista ? 0 : that.sizeDiff.width;
11206
11207 s = {
11208 width: ( that.helper.width() - soffsetw ),
11209 height: ( that.helper.height() - soffseth )
11210 };
11211 left = ( parseFloat( that.element.css( "left" ) ) +
11212 ( that.position.left - that.originalPosition.left ) ) || null;
11213 top = ( parseFloat( that.element.css( "top" ) ) +
11214 ( that.position.top - that.originalPosition.top ) ) || null;
11215
11216 if ( !o.animate ) {
11217 this.element.css( $.extend( s, { top: top, left: left } ) );
11218 }
11219
11220 that.helper.height( that.size.height );
11221 that.helper.width( that.size.width );
11222
11223 if ( this._helper && !o.animate ) {
11224 this._proportionallyResize();
11225 }
11226 }
11227
11228 $( "body" ).css( "cursor", "auto" );
11229
11230 this._removeClass( "ui-resizable-resizing" );
11231
11232 this._propagate( "stop", event );
11233
11234 if ( this._helper ) {
11235 this.helper.remove();
11236 }
11237
11238 return false;
11239
11240 },
11241
11242 _updatePrevProperties: function() {
11243 this.prevPosition = {
11244 top: this.position.top,
11245 left: this.position.left
11246 };
11247 this.prevSize = {
11248 width: this.size.width,
11249 height: this.size.height
11250 };
11251 },
11252
11253 _applyChanges: function() {
11254 var props = {};
11255
11256 if ( this.position.top !== this.prevPosition.top ) {
11257 props.top = this.position.top + "px";
11258 }
11259 if ( this.position.left !== this.prevPosition.left ) {
11260 props.left = this.position.left + "px";
11261 }
11262 if ( this.size.width !== this.prevSize.width ) {
11263 props.width = this.size.width + "px";
11264 }
11265 if ( this.size.height !== this.prevSize.height ) {
11266 props.height = this.size.height + "px";
11267 }
11268
11269 this.helper.css( props );
11270
11271 return props;
11272 },
11273
11274 _updateVirtualBoundaries: function( forceAspectRatio ) {
11275 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
11276 o = this.options;
11277
11278 b = {
11279 minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
11280 maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
11281 minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
11282 maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
11283 };
11284
11285 if ( this._aspectRatio || forceAspectRatio ) {
11286 pMinWidth = b.minHeight * this.aspectRatio;
11287 pMinHeight = b.minWidth / this.aspectRatio;
11288 pMaxWidth = b.maxHeight * this.aspectRatio;
11289 pMaxHeight = b.maxWidth / this.aspectRatio;
11290
11291 if ( pMinWidth > b.minWidth ) {
11292 b.minWidth = pMinWidth;
11293 }
11294 if ( pMinHeight > b.minHeight ) {
11295 b.minHeight = pMinHeight;
11296 }
11297 if ( pMaxWidth < b.maxWidth ) {
11298 b.maxWidth = pMaxWidth;
11299 }
11300 if ( pMaxHeight < b.maxHeight ) {
11301 b.maxHeight = pMaxHeight;
11302 }
11303 }
11304 this._vBoundaries = b;
11305 },
11306
11307 _updateCache: function( data ) {
11308 this.offset = this.helper.offset();
11309 if ( this._isNumber( data.left ) ) {
11310 this.position.left = data.left;
11311 }
11312 if ( this._isNumber( data.top ) ) {
11313 this.position.top = data.top;
11314 }
11315 if ( this._isNumber( data.height ) ) {
11316 this.size.height = data.height;
11317 }
11318 if ( this._isNumber( data.width ) ) {
11319 this.size.width = data.width;
11320 }
11321 },
11322
11323 _updateRatio: function( data ) {
11324
11325 var cpos = this.position,
11326 csize = this.size,
11327 a = this.axis;
11328
11329 if ( this._isNumber( data.height ) ) {
11330 data.width = ( data.height * this.aspectRatio );
11331 } else if ( this._isNumber( data.width ) ) {
11332 data.height = ( data.width / this.aspectRatio );
11333 }
11334
11335 if ( a === "sw" ) {
11336 data.left = cpos.left + ( csize.width - data.width );
11337 data.top = null;
11338 }
11339 if ( a === "nw" ) {
11340 data.top = cpos.top + ( csize.height - data.height );
11341 data.left = cpos.left + ( csize.width - data.width );
11342 }
11343
11344 return data;
11345 },
11346
11347 _respectSize: function( data ) {
11348
11349 var o = this._vBoundaries,
11350 a = this.axis,
11351 ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
11352 ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
11353 isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
11354 isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
11355 dw = this.originalPosition.left + this.originalSize.width,
11356 dh = this.originalPosition.top + this.originalSize.height,
11357 cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
11358 if ( isminw ) {
11359 data.width = o.minWidth;
11360 }
11361 if ( isminh ) {
11362 data.height = o.minHeight;
11363 }
11364 if ( ismaxw ) {
11365 data.width = o.maxWidth;
11366 }
11367 if ( ismaxh ) {
11368 data.height = o.maxHeight;
11369 }
11370
11371 if ( isminw && cw ) {
11372 data.left = dw - o.minWidth;
11373 }
11374 if ( ismaxw && cw ) {
11375 data.left = dw - o.maxWidth;
11376 }
11377 if ( isminh && ch ) {
11378 data.top = dh - o.minHeight;
11379 }
11380 if ( ismaxh && ch ) {
11381 data.top = dh - o.maxHeight;
11382 }
11383
11384 // Fixing jump error on top/left - bug #2330
11385 if ( !data.width && !data.height && !data.left && data.top ) {
11386 data.top = null;
11387 } else if ( !data.width && !data.height && !data.top && data.left ) {
11388 data.left = null;
11389 }
11390
11391 return data;
11392 },
11393
11394 _getPaddingPlusBorderDimensions: function( element ) {
11395 var i = 0,
11396 widths = [],
11397 borders = [
11398 element.css( "borderTopWidth" ),
11399 element.css( "borderRightWidth" ),
11400 element.css( "borderBottomWidth" ),
11401 element.css( "borderLeftWidth" )
11402 ],
11403 paddings = [
11404 element.css( "paddingTop" ),
11405 element.css( "paddingRight" ),
11406 element.css( "paddingBottom" ),
11407 element.css( "paddingLeft" )
11408 ];
11409
11410 for ( ; i < 4; i++ ) {
11411 widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
11412 widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
11413 }
11414
11415 return {
11416 height: widths[ 0 ] + widths[ 2 ],
11417 width: widths[ 1 ] + widths[ 3 ]
11418 };
11419 },
11420
11421 _proportionallyResize: function() {
11422
11423 if ( !this._proportionallyResizeElements.length ) {
11424 return;
11425 }
11426
11427 var prel,
11428 i = 0,
11429 element = this.helper || this.element;
11430
11431 for ( ; i < this._proportionallyResizeElements.length; i++ ) {
11432
11433 prel = this._proportionallyResizeElements[ i ];
11434
11435 // TODO: Seems like a bug to cache this.outerDimensions
11436 // considering that we are in a loop.
11437 if ( !this.outerDimensions ) {
11438 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
11439 }
11440
11441 prel.css( {
11442 height: ( element.height() - this.outerDimensions.height ) || 0,
11443 width: ( element.width() - this.outerDimensions.width ) || 0
11444 } );
11445
11446 }
11447
11448 },
11449
11450 _renderProxy: function() {
11451
11452 var el = this.element, o = this.options;
11453 this.elementOffset = el.offset();
11454
11455 if ( this._helper ) {
11456
11457 this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );
11458
11459 this._addClass( this.helper, this._helper );
11460 this.helper.css( {
11461 width: this.element.outerWidth(),
11462 height: this.element.outerHeight(),
11463 position: "absolute",
11464 left: this.elementOffset.left + "px",
11465 top: this.elementOffset.top + "px",
11466 zIndex: ++o.zIndex //TODO: Don't modify option
11467 } );
11468
11469 this.helper
11470 .appendTo( "body" )
11471 .disableSelection();
11472
11473 } else {
11474 this.helper = this.element;
11475 }
11476
11477 },
11478
11479 _change: {
11480 e: function( event, dx ) {
11481 return { width: this.originalSize.width + dx };
11482 },
11483 w: function( event, dx ) {
11484 var cs = this.originalSize, sp = this.originalPosition;
11485 return { left: sp.left + dx, width: cs.width - dx };
11486 },
11487 n: function( event, dx, dy ) {
11488 var cs = this.originalSize, sp = this.originalPosition;
11489 return { top: sp.top + dy, height: cs.height - dy };
11490 },
11491 s: function( event, dx, dy ) {
11492 return { height: this.originalSize.height + dy };
11493 },
11494 se: function( event, dx, dy ) {
11495 return $.extend( this._change.s.apply( this, arguments ),
11496 this._change.e.apply( this, [ event, dx, dy ] ) );
11497 },
11498 sw: function( event, dx, dy ) {
11499 return $.extend( this._change.s.apply( this, arguments ),
11500 this._change.w.apply( this, [ event, dx, dy ] ) );
11501 },
11502 ne: function( event, dx, dy ) {
11503 return $.extend( this._change.n.apply( this, arguments ),
11504 this._change.e.apply( this, [ event, dx, dy ] ) );
11505 },
11506 nw: function( event, dx, dy ) {
11507 return $.extend( this._change.n.apply( this, arguments ),
11508 this._change.w.apply( this, [ event, dx, dy ] ) );
11509 }
11510 },
11511
11512 _propagate: function( n, event ) {
11513 $.ui.plugin.call( this, n, [ event, this.ui() ] );
11514 ( n !== "resize" && this._trigger( n, event, this.ui() ) );
11515 },
11516
11517 plugins: {},
11518
11519 ui: function() {
11520 return {
11521 originalElement: this.originalElement,
11522 element: this.element,
11523 helper: this.helper,
11524 position: this.position,
11525 size: this.size,
11526 originalSize: this.originalSize,
11527 originalPosition: this.originalPosition
11528 };
11529 }
11530
11531 } );
11532
11533 /*
11534 * Resizable Extensions
11535 */
11536
11537 $.ui.plugin.add( "resizable", "animate", {
11538
11539 stop: function( event ) {
11540 var that = $( this ).resizable( "instance" ),
11541 o = that.options,
11542 pr = that._proportionallyResizeElements,
11543 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
11544 soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
11545 soffsetw = ista ? 0 : that.sizeDiff.width,
11546 style = {
11547 width: ( that.size.width - soffsetw ),
11548 height: ( that.size.height - soffseth )
11549 },
11550 left = ( parseFloat( that.element.css( "left" ) ) +
11551 ( that.position.left - that.originalPosition.left ) ) || null,
11552 top = ( parseFloat( that.element.css( "top" ) ) +
11553 ( that.position.top - that.originalPosition.top ) ) || null;
11554
11555 that.element.animate(
11556 $.extend( style, top && left ? { top: top, left: left } : {} ), {
11557 duration: o.animateDuration,
11558 easing: o.animateEasing,
11559 step: function() {
11560
11561 var data = {
11562 width: parseFloat( that.element.css( "width" ) ),
11563 height: parseFloat( that.element.css( "height" ) ),
11564 top: parseFloat( that.element.css( "top" ) ),
11565 left: parseFloat( that.element.css( "left" ) )
11566 };
11567
11568 if ( pr && pr.length ) {
11569 $( pr[ 0 ] ).css( { width: data.width, height: data.height } );
11570 }
11571
11572 // Propagating resize, and updating values for each animation step
11573 that._updateCache( data );
11574 that._propagate( "resize", event );
11575
11576 }
11577 }
11578 );
11579 }
11580
11581 } );
11582
11583 $.ui.plugin.add( "resizable", "containment", {
11584
11585 start: function() {
11586 var element, p, co, ch, cw, width, height,
11587 that = $( this ).resizable( "instance" ),
11588 o = that.options,
11589 el = that.element,
11590 oc = o.containment,
11591 ce = ( oc instanceof $ ) ?
11592 oc.get( 0 ) :
11593 ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
11594
11595 if ( !ce ) {
11596 return;
11597 }
11598
11599 that.containerElement = $( ce );
11600
11601 if ( /document/.test( oc ) || oc === document ) {
11602 that.containerOffset = {
11603 left: 0,
11604 top: 0
11605 };
11606 that.containerPosition = {
11607 left: 0,
11608 top: 0
11609 };
11610
11611 that.parentData = {
11612 element: $( document ),
11613 left: 0,
11614 top: 0,
11615 width: $( document ).width(),
11616 height: $( document ).height() || document.body.parentNode.scrollHeight
11617 };
11618 } else {
11619 element = $( ce );
11620 p = [];
11621 $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
11622 p[ i ] = that._num( element.css( "padding" + name ) );
11623 } );
11624
11625 that.containerOffset = element.offset();
11626 that.containerPosition = element.position();
11627 that.containerSize = {
11628 height: ( element.innerHeight() - p[ 3 ] ),
11629 width: ( element.innerWidth() - p[ 1 ] )
11630 };
11631
11632 co = that.containerOffset;
11633 ch = that.containerSize.height;
11634 cw = that.containerSize.width;
11635 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
11636 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
11637
11638 that.parentData = {
11639 element: ce,
11640 left: co.left,
11641 top: co.top,
11642 width: width,
11643 height: height
11644 };
11645 }
11646 },
11647
11648 resize: function( event ) {
11649 var woset, hoset, isParent, isOffsetRelative,
11650 that = $( this ).resizable( "instance" ),
11651 o = that.options,
11652 co = that.containerOffset,
11653 cp = that.position,
11654 pRatio = that._aspectRatio || event.shiftKey,
11655 cop = {
11656 top: 0,
11657 left: 0
11658 },
11659 ce = that.containerElement,
11660 continueResize = true;
11661
11662 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
11663 cop = co;
11664 }
11665
11666 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
11667 that.size.width = that.size.width +
11668 ( that._helper ?
11669 ( that.position.left - co.left ) :
11670 ( that.position.left - cop.left ) );
11671
11672 if ( pRatio ) {
11673 that.size.height = that.size.width / that.aspectRatio;
11674 continueResize = false;
11675 }
11676 that.position.left = o.helper ? co.left : 0;
11677 }
11678
11679 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
11680 that.size.height = that.size.height +
11681 ( that._helper ?
11682 ( that.position.top - co.top ) :
11683 that.position.top );
11684
11685 if ( pRatio ) {
11686 that.size.width = that.size.height * that.aspectRatio;
11687 continueResize = false;
11688 }
11689 that.position.top = that._helper ? co.top : 0;
11690 }
11691
11692 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
11693 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
11694
11695 if ( isParent && isOffsetRelative ) {
11696 that.offset.left = that.parentData.left + that.position.left;
11697 that.offset.top = that.parentData.top + that.position.top;
11698 } else {
11699 that.offset.left = that.element.offset().left;
11700 that.offset.top = that.element.offset().top;
11701 }
11702
11703 woset = Math.abs( that.sizeDiff.width +
11704 ( that._helper ?
11705 that.offset.left - cop.left :
11706 ( that.offset.left - co.left ) ) );
11707
11708 hoset = Math.abs( that.sizeDiff.height +
11709 ( that._helper ?
11710 that.offset.top - cop.top :
11711 ( that.offset.top - co.top ) ) );
11712
11713 if ( woset + that.size.width >= that.parentData.width ) {
11714 that.size.width = that.parentData.width - woset;
11715 if ( pRatio ) {
11716 that.size.height = that.size.width / that.aspectRatio;
11717 continueResize = false;
11718 }
11719 }
11720
11721 if ( hoset + that.size.height >= that.parentData.height ) {
11722 that.size.height = that.parentData.height - hoset;
11723 if ( pRatio ) {
11724 that.size.width = that.size.height * that.aspectRatio;
11725 continueResize = false;
11726 }
11727 }
11728
11729 if ( !continueResize ) {
11730 that.position.left = that.prevPosition.left;
11731 that.position.top = that.prevPosition.top;
11732 that.size.width = that.prevSize.width;
11733 that.size.height = that.prevSize.height;
11734 }
11735 },
11736
11737 stop: function() {
11738 var that = $( this ).resizable( "instance" ),
11739 o = that.options,
11740 co = that.containerOffset,
11741 cop = that.containerPosition,
11742 ce = that.containerElement,
11743 helper = $( that.helper ),
11744 ho = helper.offset(),
11745 w = helper.outerWidth() - that.sizeDiff.width,
11746 h = helper.outerHeight() - that.sizeDiff.height;
11747
11748 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
11749 $( this ).css( {
11750 left: ho.left - cop.left - co.left,
11751 width: w,
11752 height: h
11753 } );
11754 }
11755
11756 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
11757 $( this ).css( {
11758 left: ho.left - cop.left - co.left,
11759 width: w,
11760 height: h
11761 } );
11762 }
11763 }
11764 } );
11765
11766 $.ui.plugin.add( "resizable", "alsoResize", {
11767
11768 start: function() {
11769 var that = $( this ).resizable( "instance" ),
11770 o = that.options;
11771
11772 $( o.alsoResize ).each( function() {
11773 var el = $( this );
11774 el.data( "ui-resizable-alsoresize", {
11775 width: parseFloat( el.width() ), height: parseFloat( el.height() ),
11776 left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
11777 } );
11778 } );
11779 },
11780
11781 resize: function( event, ui ) {
11782 var that = $( this ).resizable( "instance" ),
11783 o = that.options,
11784 os = that.originalSize,
11785 op = that.originalPosition,
11786 delta = {
11787 height: ( that.size.height - os.height ) || 0,
11788 width: ( that.size.width - os.width ) || 0,
11789 top: ( that.position.top - op.top ) || 0,
11790 left: ( that.position.left - op.left ) || 0
11791 };
11792
11793 $( o.alsoResize ).each( function() {
11794 var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
11795 css = el.parents( ui.originalElement[ 0 ] ).length ?
11796 [ "width", "height" ] :
11797 [ "width", "height", "top", "left" ];
11798
11799 $.each( css, function( i, prop ) {
11800 var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
11801 if ( sum && sum >= 0 ) {
11802 style[ prop ] = sum || null;
11803 }
11804 } );
11805
11806 el.css( style );
11807 } );
11808 },
11809
11810 stop: function() {
11811 $( this ).removeData( "ui-resizable-alsoresize" );
11812 }
11813 } );
11814
11815 $.ui.plugin.add( "resizable", "ghost", {
11816
11817 start: function() {
11818
11819 var that = $( this ).resizable( "instance" ), cs = that.size;
11820
11821 that.ghost = that.originalElement.clone();
11822 that.ghost.css( {
11823 opacity: 0.25,
11824 display: "block",
11825 position: "relative",
11826 height: cs.height,
11827 width: cs.width,
11828 margin: 0,
11829 left: 0,
11830 top: 0
11831 } );
11832
11833 that._addClass( that.ghost, "ui-resizable-ghost" );
11834
11835 // DEPRECATED
11836 // TODO: remove after 1.12
11837 if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
11838
11839 // Ghost option
11840 that.ghost.addClass( this.options.ghost );
11841 }
11842
11843 that.ghost.appendTo( that.helper );
11844
11845 },
11846
11847 resize: function() {
11848 var that = $( this ).resizable( "instance" );
11849 if ( that.ghost ) {
11850 that.ghost.css( {
11851 position: "relative",
11852 height: that.size.height,
11853 width: that.size.width
11854 } );
11855 }
11856 },
11857
11858 stop: function() {
11859 var that = $( this ).resizable( "instance" );
11860 if ( that.ghost && that.helper ) {
11861 that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
11862 }
11863 }
11864
11865 } );
11866
11867 $.ui.plugin.add( "resizable", "grid", {
11868
11869 resize: function() {
11870 var outerDimensions,
11871 that = $( this ).resizable( "instance" ),
11872 o = that.options,
11873 cs = that.size,
11874 os = that.originalSize,
11875 op = that.originalPosition,
11876 a = that.axis,
11877 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
11878 gridX = ( grid[ 0 ] || 1 ),
11879 gridY = ( grid[ 1 ] || 1 ),
11880 ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
11881 oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
11882 newWidth = os.width + ox,
11883 newHeight = os.height + oy,
11884 isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
11885 isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
11886 isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
11887 isMinHeight = o.minHeight && ( o.minHeight > newHeight );
11888
11889 o.grid = grid;
11890
11891 if ( isMinWidth ) {
11892 newWidth += gridX;
11893 }
11894 if ( isMinHeight ) {
11895 newHeight += gridY;
11896 }
11897 if ( isMaxWidth ) {
11898 newWidth -= gridX;
11899 }
11900 if ( isMaxHeight ) {
11901 newHeight -= gridY;
11902 }
11903
11904 if ( /^(se|s|e)$/.test( a ) ) {
11905 that.size.width = newWidth;
11906 that.size.height = newHeight;
11907 } else if ( /^(ne)$/.test( a ) ) {
11908 that.size.width = newWidth;
11909 that.size.height = newHeight;
11910 that.position.top = op.top - oy;
11911 } else if ( /^(sw)$/.test( a ) ) {
11912 that.size.width = newWidth;
11913 that.size.height = newHeight;
11914 that.position.left = op.left - ox;
11915 } else {
11916 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
11917 outerDimensions = that._getPaddingPlusBorderDimensions( this );
11918 }
11919
11920 if ( newHeight - gridY > 0 ) {
11921 that.size.height = newHeight;
11922 that.position.top = op.top - oy;
11923 } else {
11924 newHeight = gridY - outerDimensions.height;
11925 that.size.height = newHeight;
11926 that.position.top = op.top + os.height - newHeight;
11927 }
11928 if ( newWidth - gridX > 0 ) {
11929 that.size.width = newWidth;
11930 that.position.left = op.left - ox;
11931 } else {
11932 newWidth = gridX - outerDimensions.width;
11933 that.size.width = newWidth;
11934 that.position.left = op.left + os.width - newWidth;
11935 }
11936 }
11937 }
11938
11939 } );
11940
11941 var widgetsResizable = $.ui.resizable;
11942
11943
11944 /*!
11945 * jQuery UI Dialog 1.12.1
11946 * http://jqueryui.com
11947 *
11948 * Copyright jQuery Foundation and other contributors
11949 * Released under the MIT license.
11950 * http://jquery.org/license
11951 */
11952
11953 //>>label: Dialog
11954 //>>group: Widgets
11955 //>>description: Displays customizable dialog windows.
11956 //>>docs: http://api.jqueryui.com/dialog/
11957 //>>demos: http://jqueryui.com/dialog/
11958 //>>css.structure: ../../themes/base/core.css
11959 //>>css.structure: ../../themes/base/dialog.css
11960 //>>css.theme: ../../themes/base/theme.css
11961
11962
11963
11964 $.widget( "ui.dialog", {
11965 version: "1.12.1",
11966 options: {
11967 appendTo: "body",
11968 autoOpen: true,
11969 buttons: [],
11970 classes: {
11971 "ui-dialog": "ui-corner-all",
11972 "ui-dialog-titlebar": "ui-corner-all"
11973 },
11974 closeOnEscape: true,
11975 closeText: "Close",
11976 draggable: true,
11977 hide: null,
11978 height: "auto",
11979 maxHeight: null,
11980 maxWidth: null,
11981 minHeight: 150,
11982 minWidth: 150,
11983 modal: false,
11984 position: {
11985 my: "center",
11986 at: "center",
11987 of: window,
11988 collision: "fit",
11989
11990 // Ensure the titlebar is always visible
11991 using: function( pos ) {
11992 var topOffset = $( this ).css( pos ).offset().top;
11993 if ( topOffset < 0 ) {
11994 $( this ).css( "top", pos.top - topOffset );
11995 }
11996 }
11997 },
11998 resizable: true,
11999 show: null,
12000 title: null,
12001 width: 300,
12002
12003 // Callbacks
12004 beforeClose: null,
12005 close: null,
12006 drag: null,
12007 dragStart: null,
12008 dragStop: null,
12009 focus: null,
12010 open: null,
12011 resize: null,
12012 resizeStart: null,
12013 resizeStop: null
12014 },
12015
12016 sizeRelatedOptions: {
12017 buttons: true,
12018 height: true,
12019 maxHeight: true,
12020 maxWidth: true,
12021 minHeight: true,
12022 minWidth: true,
12023 width: true
12024 },
12025
12026 resizableRelatedOptions: {
12027 maxHeight: true,
12028 maxWidth: true,
12029 minHeight: true,
12030 minWidth: true
12031 },
12032
12033 _create: function() {
12034 this.originalCss = {
12035 display: this.element[ 0 ].style.display,
12036 width: this.element[ 0 ].style.width,
12037 minHeight: this.element[ 0 ].style.minHeight,
12038 maxHeight: this.element[ 0 ].style.maxHeight,
12039 height: this.element[ 0 ].style.height
12040 };
12041 this.originalPosition = {
12042 parent: this.element.parent(),
12043 index: this.element.parent().children().index( this.element )
12044 };
12045 this.originalTitle = this.element.attr( "title" );
12046 if ( this.options.title == null && this.originalTitle != null ) {
12047 this.options.title = this.originalTitle;
12048 }
12049
12050 // Dialogs can't be disabled
12051 if ( this.options.disabled ) {
12052 this.options.disabled = false;
12053 }
12054
12055 this._createWrapper();
12056
12057 this.element
12058 .show()
12059 .removeAttr( "title" )
12060 .appendTo( this.uiDialog );
12061
12062 this._addClass( "ui-dialog-content", "ui-widget-content" );
12063
12064 this._createTitlebar();
12065 this._createButtonPane();
12066
12067 if ( this.options.draggable && $.fn.draggable ) {
12068 this._makeDraggable();
12069 }
12070 if ( this.options.resizable && $.fn.resizable ) {
12071 this._makeResizable();
12072 }
12073
12074 this._isOpen = false;
12075
12076 this._trackFocus();
12077 },
12078
12079 _init: function() {
12080 if ( this.options.autoOpen ) {
12081 this.open();
12082 }
12083 },
12084
12085 _appendTo: function() {
12086 var element = this.options.appendTo;
12087 if ( element && ( element.jquery || element.nodeType ) ) {
12088 return $( element );
12089 }
12090 return this.document.find( element || "body" ).eq( 0 );
12091 },
12092
12093 _destroy: function() {
12094 var next,
12095 originalPosition = this.originalPosition;
12096
12097 this._untrackInstance();
12098 this._destroyOverlay();
12099
12100 this.element
12101 .removeUniqueId()
12102 .css( this.originalCss )
12103
12104 // Without detaching first, the following becomes really slow
12105 .detach();
12106
12107 this.uiDialog.remove();
12108
12109 if ( this.originalTitle ) {
12110 this.element.attr( "title", this.originalTitle );
12111 }
12112
12113 next = originalPosition.parent.children().eq( originalPosition.index );
12114
12115 // Don't try to place the dialog next to itself (#8613)
12116 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
12117 next.before( this.element );
12118 } else {
12119 originalPosition.parent.append( this.element );
12120 }
12121 },
12122
12123 widget: function() {
12124 return this.uiDialog;
12125 },
12126
12127 disable: $.noop,
12128 enable: $.noop,
12129
12130 close: function( event ) {
12131 var that = this;
12132
12133 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
12134 return;
12135 }
12136
12137 this._isOpen = false;
12138 this._focusedElement = null;
12139 this._destroyOverlay();
12140 this._untrackInstance();
12141
12142 if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
12143
12144 // Hiding a focused element doesn't trigger blur in WebKit
12145 // so in case we have nothing to focus on, explicitly blur the active element
12146 // https://bugs.webkit.org/show_bug.cgi?id=47182
12147 $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
12148 }
12149
12150 this._hide( this.uiDialog, this.options.hide, function() {
12151 that._trigger( "close", event );
12152 } );
12153 },
12154
12155 isOpen: function() {
12156 return this._isOpen;
12157 },
12158
12159 moveToTop: function() {
12160 this._moveToTop();
12161 },
12162
12163 _moveToTop: function( event, silent ) {
12164 var moved = false,
12165 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
12166 return +$( this ).css( "z-index" );
12167 } ).get(),
12168 zIndexMax = Math.max.apply( null, zIndices );
12169
12170 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
12171 this.uiDialog.css( "z-index", zIndexMax + 1 );
12172 moved = true;
12173 }
12174
12175 if ( moved && !silent ) {
12176 this._trigger( "focus", event );
12177 }
12178 return moved;
12179 },
12180
12181 open: function() {
12182 var that = this;
12183 if ( this._isOpen ) {
12184 if ( this._moveToTop() ) {
12185 this._focusTabbable();
12186 }
12187 return;
12188 }
12189
12190 this._isOpen = true;
12191 this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
12192
12193 this._size();
12194 this._position();
12195 this._createOverlay();
12196 this._moveToTop( null, true );
12197
12198 // Ensure the overlay is moved to the top with the dialog, but only when
12199 // opening. The overlay shouldn't move after the dialog is open so that
12200 // modeless dialogs opened after the modal dialog stack properly.
12201 if ( this.overlay ) {
12202 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
12203 }
12204
12205 this._show( this.uiDialog, this.options.show, function() {
12206 that._focusTabbable();
12207 that._trigger( "focus" );
12208 } );
12209
12210 // Track the dialog immediately upon openening in case a focus event
12211 // somehow occurs outside of the dialog before an element inside the
12212 // dialog is focused (#10152)
12213 this._makeFocusTarget();
12214
12215 this._trigger( "open" );
12216 },
12217
12218 _focusTabbable: function() {
12219
12220 // Set focus to the first match:
12221 // 1. An element that was focused previously
12222 // 2. First element inside the dialog matching [autofocus]
12223 // 3. Tabbable element inside the content element
12224 // 4. Tabbable element inside the buttonpane
12225 // 5. The close button
12226 // 6. The dialog itself
12227 var hasFocus = this._focusedElement;
12228 if ( !hasFocus ) {
12229 hasFocus = this.element.find( "[autofocus]" );
12230 }
12231 if ( !hasFocus.length ) {
12232 hasFocus = this.element.find( ":tabbable" );
12233 }
12234 if ( !hasFocus.length ) {
12235 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
12236 }
12237 if ( !hasFocus.length ) {
12238 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
12239 }
12240 if ( !hasFocus.length ) {
12241 hasFocus = this.uiDialog;
12242 }
12243 hasFocus.eq( 0 ).trigger( "focus" );
12244 },
12245
12246 _keepFocus: function( event ) {
12247 function checkFocus() {
12248 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
12249 isActive = this.uiDialog[ 0 ] === activeElement ||
12250 $.contains( this.uiDialog[ 0 ], activeElement );
12251 if ( !isActive ) {
12252 this._focusTabbable();
12253 }
12254 }
12255 event.preventDefault();
12256 checkFocus.call( this );
12257
12258 // support: IE
12259 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
12260 // so we check again later
12261 this._delay( checkFocus );
12262 },
12263
12264 _createWrapper: function() {
12265 this.uiDialog = $( "<div>" )
12266 .hide()
12267 .attr( {
12268
12269 // Setting tabIndex makes the div focusable
12270 tabIndex: -1,
12271 role: "dialog"
12272 } )
12273 .appendTo( this._appendTo() );
12274
12275 this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
12276 this._on( this.uiDialog, {
12277 keydown: function( event ) {
12278 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
12279 event.keyCode === $.ui.keyCode.ESCAPE ) {
12280 event.preventDefault();
12281 this.close( event );
12282 return;
12283 }
12284
12285 // Prevent tabbing out of dialogs
12286 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
12287 return;
12288 }
12289 var tabbables = this.uiDialog.find( ":tabbable" ),
12290 first = tabbables.filter( ":first" ),
12291 last = tabbables.filter( ":last" );
12292
12293 if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
12294 !event.shiftKey ) {
12295 this._delay( function() {
12296 first.trigger( "focus" );
12297 } );
12298 event.preventDefault();
12299 } else if ( ( event.target === first[ 0 ] ||
12300 event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
12301 this._delay( function() {
12302 last.trigger( "focus" );
12303 } );
12304 event.preventDefault();
12305 }
12306 },
12307 mousedown: function( event ) {
12308 if ( this._moveToTop( event ) ) {
12309 this._focusTabbable();
12310 }
12311 }
12312 } );
12313
12314 // We assume that any existing aria-describedby attribute means
12315 // that the dialog content is marked up properly
12316 // otherwise we brute force the content as the description
12317 if ( !this.element.find( "[aria-describedby]" ).length ) {
12318 this.uiDialog.attr( {
12319 "aria-describedby": this.element.uniqueId().attr( "id" )
12320 } );
12321 }
12322 },
12323
12324 _createTitlebar: function() {
12325 var uiDialogTitle;
12326
12327 this.uiDialogTitlebar = $( "<div>" );
12328 this._addClass( this.uiDialogTitlebar,
12329 "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
12330 this._on( this.uiDialogTitlebar, {
12331 mousedown: function( event ) {
12332
12333 // Don't prevent click on close button (#8838)
12334 // Focusing a dialog that is partially scrolled out of view
12335 // causes the browser to scroll it into view, preventing the click event
12336 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
12337
12338 // Dialog isn't getting focus when dragging (#8063)
12339 this.uiDialog.trigger( "focus" );
12340 }
12341 }
12342 } );
12343
12344 // Support: IE
12345 // Use type="button" to prevent enter keypresses in textboxes from closing the
12346 // dialog in IE (#9312)
12347 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
12348 .button( {
12349 label: $( "<a>" ).text( this.options.closeText ).html(),
12350 icon: "ui-icon-closethick",
12351 showLabel: false
12352 } )
12353 .appendTo( this.uiDialogTitlebar );
12354
12355 this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
12356 this._on( this.uiDialogTitlebarClose, {
12357 click: function( event ) {
12358 event.preventDefault();
12359 this.close( event );
12360 }
12361 } );
12362
12363 uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
12364 this._addClass( uiDialogTitle, "ui-dialog-title" );
12365 this._title( uiDialogTitle );
12366
12367 this.uiDialogTitlebar.prependTo( this.uiDialog );
12368
12369 this.uiDialog.attr( {
12370 "aria-labelledby": uiDialogTitle.attr( "id" )
12371 } );
12372 },
12373
12374 _title: function( title ) {
12375 if ( this.options.title ) {
12376 title.text( this.options.title );
12377 } else {
12378 title.html( "&#160;" );
12379 }
12380 },
12381
12382 _createButtonPane: function() {
12383 this.uiDialogButtonPane = $( "<div>" );
12384 this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
12385 "ui-widget-content ui-helper-clearfix" );
12386
12387 this.uiButtonSet = $( "<div>" )
12388 .appendTo( this.uiDialogButtonPane );
12389 this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
12390
12391 this._createButtons();
12392 },
12393
12394 _createButtons: function() {
12395 var that = this,
12396 buttons = this.options.buttons;
12397
12398 // If we already have a button pane, remove it
12399 this.uiDialogButtonPane.remove();
12400 this.uiButtonSet.empty();
12401
12402 if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
12403 this._removeClass( this.uiDialog, "ui-dialog-buttons" );
12404 return;
12405 }
12406
12407 $.each( buttons, function( name, props ) {
12408 var click, buttonOptions;
12409 props = $.isFunction( props ) ?
12410 { click: props, text: name } :
12411 props;
12412
12413 // Default to a non-submitting button
12414 props = $.extend( { type: "button" }, props );
12415
12416 // Change the context for the click callback to be the main element
12417 click = props.click;
12418 buttonOptions = {
12419 icon: props.icon,
12420 iconPosition: props.iconPosition,
12421 showLabel: props.showLabel,
12422
12423 // Deprecated options
12424 icons: props.icons,
12425 text: props.text
12426 };
12427
12428 delete props.click;
12429 delete props.icon;
12430 delete props.iconPosition;
12431 delete props.showLabel;
12432
12433 // Deprecated options
12434 delete props.icons;
12435 if ( typeof props.text === "boolean" ) {
12436 delete props.text;
12437 }
12438
12439 $( "<button></button>", props )
12440 .button( buttonOptions )
12441 .appendTo( that.uiButtonSet )
12442 .on( "click", function() {
12443 click.apply( that.element[ 0 ], arguments );
12444 } );
12445 } );
12446 this._addClass( this.uiDialog, "ui-dialog-buttons" );
12447 this.uiDialogButtonPane.appendTo( this.uiDialog );
12448 },
12449
12450 _makeDraggable: function() {
12451 var that = this,
12452 options = this.options;
12453
12454 function filteredUi( ui ) {
12455 return {
12456 position: ui.position,
12457 offset: ui.offset
12458 };
12459 }
12460
12461 this.uiDialog.draggable( {
12462 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
12463 handle: ".ui-dialog-titlebar",
12464 containment: "document",
12465 start: function( event, ui ) {
12466 that._addClass( $( this ), "ui-dialog-dragging" );
12467 that._blockFrames();
12468 that._trigger( "dragStart", event, filteredUi( ui ) );
12469 },
12470 drag: function( event, ui ) {
12471 that._trigger( "drag", event, filteredUi( ui ) );
12472 },
12473 stop: function( event, ui ) {
12474 var left = ui.offset.left - that.document.scrollLeft(),
12475 top = ui.offset.top - that.document.scrollTop();
12476
12477 options.position = {
12478 my: "left top",
12479 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12480 "top" + ( top >= 0 ? "+" : "" ) + top,
12481 of: that.window
12482 };
12483 that._removeClass( $( this ), "ui-dialog-dragging" );
12484 that._unblockFrames();
12485 that._trigger( "dragStop", event, filteredUi( ui ) );
12486 }
12487 } );
12488 },
12489
12490 _makeResizable: function() {
12491 var that = this,
12492 options = this.options,
12493 handles = options.resizable,
12494
12495 // .ui-resizable has position: relative defined in the stylesheet
12496 // but dialogs have to use absolute or fixed positioning
12497 position = this.uiDialog.css( "position" ),
12498 resizeHandles = typeof handles === "string" ?
12499 handles :
12500 "n,e,s,w,se,sw,ne,nw";
12501
12502 function filteredUi( ui ) {
12503 return {
12504 originalPosition: ui.originalPosition,
12505 originalSize: ui.originalSize,
12506 position: ui.position,
12507 size: ui.size
12508 };
12509 }
12510
12511 this.uiDialog.resizable( {
12512 cancel: ".ui-dialog-content",
12513 containment: "document",
12514 alsoResize: this.element,
12515 maxWidth: options.maxWidth,
12516 maxHeight: options.maxHeight,
12517 minWidth: options.minWidth,
12518 minHeight: this._minHeight(),
12519 handles: resizeHandles,
12520 start: function( event, ui ) {
12521 that._addClass( $( this ), "ui-dialog-resizing" );
12522 that._blockFrames();
12523 that._trigger( "resizeStart", event, filteredUi( ui ) );
12524 },
12525 resize: function( event, ui ) {
12526 that._trigger( "resize", event, filteredUi( ui ) );
12527 },
12528 stop: function( event, ui ) {
12529 var offset = that.uiDialog.offset(),
12530 left = offset.left - that.document.scrollLeft(),
12531 top = offset.top - that.document.scrollTop();
12532
12533 options.height = that.uiDialog.height();
12534 options.width = that.uiDialog.width();
12535 options.position = {
12536 my: "left top",
12537 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
12538 "top" + ( top >= 0 ? "+" : "" ) + top,
12539 of: that.window
12540 };
12541 that._removeClass( $( this ), "ui-dialog-resizing" );
12542 that._unblockFrames();
12543 that._trigger( "resizeStop", event, filteredUi( ui ) );
12544 }
12545 } )
12546 .css( "position", position );
12547 },
12548
12549 _trackFocus: function() {
12550 this._on( this.widget(), {
12551 focusin: function( event ) {
12552 this._makeFocusTarget();
12553 this._focusedElement = $( event.target );
12554 }
12555 } );
12556 },
12557
12558 _makeFocusTarget: function() {
12559 this._untrackInstance();
12560 this._trackingInstances().unshift( this );
12561 },
12562
12563 _untrackInstance: function() {
12564 var instances = this._trackingInstances(),
12565 exists = $.inArray( this, instances );
12566 if ( exists !== -1 ) {
12567 instances.splice( exists, 1 );
12568 }
12569 },
12570
12571 _trackingInstances: function() {
12572 var instances = this.document.data( "ui-dialog-instances" );
12573 if ( !instances ) {
12574 instances = [];
12575 this.document.data( "ui-dialog-instances", instances );
12576 }
12577 return instances;
12578 },
12579
12580 _minHeight: function() {
12581 var options = this.options;
12582
12583 return options.height === "auto" ?
12584 options.minHeight :
12585 Math.min( options.minHeight, options.height );
12586 },
12587
12588 _position: function() {
12589
12590 // Need to show the dialog to get the actual offset in the position plugin
12591 var isVisible = this.uiDialog.is( ":visible" );
12592 if ( !isVisible ) {
12593 this.uiDialog.show();
12594 }
12595 this.uiDialog.position( this.options.position );
12596 if ( !isVisible ) {
12597 this.uiDialog.hide();
12598 }
12599 },
12600
12601 _setOptions: function( options ) {
12602 var that = this,
12603 resize = false,
12604 resizableOptions = {};
12605
12606 $.each( options, function( key, value ) {
12607 that._setOption( key, value );
12608
12609 if ( key in that.sizeRelatedOptions ) {
12610 resize = true;
12611 }
12612 if ( key in that.resizableRelatedOptions ) {
12613 resizableOptions[ key ] = value;
12614 }
12615 } );
12616
12617 if ( resize ) {
12618 this._size();
12619 this._position();
12620 }
12621 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12622 this.uiDialog.resizable( "option", resizableOptions );
12623 }
12624 },
12625
12626 _setOption: function( key, value ) {
12627 var isDraggable, isResizable,
12628 uiDialog = this.uiDialog;
12629
12630 if ( key === "disabled" ) {
12631 return;
12632 }
12633
12634 this._super( key, value );
12635
12636 if ( key === "appendTo" ) {
12637 this.uiDialog.appendTo( this._appendTo() );
12638 }
12639
12640 if ( key === "buttons" ) {
12641 this._createButtons();
12642 }
12643
12644 if ( key === "closeText" ) {
12645 this.uiDialogTitlebarClose.button( {
12646
12647 // Ensure that we always pass a string
12648 label: $( "<a>" ).text( "" + this.options.closeText ).html()
12649 } );
12650 }
12651
12652 if ( key === "draggable" ) {
12653 isDraggable = uiDialog.is( ":data(ui-draggable)" );
12654 if ( isDraggable && !value ) {
12655 uiDialog.draggable( "destroy" );
12656 }
12657
12658 if ( !isDraggable && value ) {
12659 this._makeDraggable();
12660 }
12661 }
12662
12663 if ( key === "position" ) {
12664 this._position();
12665 }
12666
12667 if ( key === "resizable" ) {
12668
12669 // currently resizable, becoming non-resizable
12670 isResizable = uiDialog.is( ":data(ui-resizable)" );
12671 if ( isResizable && !value ) {
12672 uiDialog.resizable( "destroy" );
12673 }
12674
12675 // Currently resizable, changing handles
12676 if ( isResizable && typeof value === "string" ) {
12677 uiDialog.resizable( "option", "handles", value );
12678 }
12679
12680 // Currently non-resizable, becoming resizable
12681 if ( !isResizable && value !== false ) {
12682 this._makeResizable();
12683 }
12684 }
12685
12686 if ( key === "title" ) {
12687 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
12688 }
12689 },
12690
12691 _size: function() {
12692
12693 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
12694 // divs will both have width and height set, so we need to reset them
12695 var nonContentHeight, minContentHeight, maxContentHeight,
12696 options = this.options;
12697
12698 // Reset content sizing
12699 this.element.show().css( {
12700 width: "auto",
12701 minHeight: 0,
12702 maxHeight: "none",
12703 height: 0
12704 } );
12705
12706 if ( options.minWidth > options.width ) {
12707 options.width = options.minWidth;
12708 }
12709
12710 // Reset wrapper sizing
12711 // determine the height of all the non-content elements
12712 nonContentHeight = this.uiDialog.css( {
12713 height: "auto",
12714 width: options.width
12715 } )
12716 .outerHeight();
12717 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
12718 maxContentHeight = typeof options.maxHeight === "number" ?
12719 Math.max( 0, options.maxHeight - nonContentHeight ) :
12720 "none";
12721
12722 if ( options.height === "auto" ) {
12723 this.element.css( {
12724 minHeight: minContentHeight,
12725 maxHeight: maxContentHeight,
12726 height: "auto"
12727 } );
12728 } else {
12729 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
12730 }
12731
12732 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
12733 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
12734 }
12735 },
12736
12737 _blockFrames: function() {
12738 this.iframeBlocks = this.document.find( "iframe" ).map( function() {
12739 var iframe = $( this );
12740
12741 return $( "<div>" )
12742 .css( {
12743 position: "absolute",
12744 width: iframe.outerWidth(),
12745 height: iframe.outerHeight()
12746 } )
12747 .appendTo( iframe.parent() )
12748 .offset( iframe.offset() )[ 0 ];
12749 } );
12750 },
12751
12752 _unblockFrames: function() {
12753 if ( this.iframeBlocks ) {
12754 this.iframeBlocks.remove();
12755 delete this.iframeBlocks;
12756 }
12757 },
12758
12759 _allowInteraction: function( event ) {
12760 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
12761 return true;
12762 }
12763
12764 // TODO: Remove hack when datepicker implements
12765 // the .ui-front logic (#8989)
12766 return !!$( event.target ).closest( ".ui-datepicker" ).length;
12767 },
12768
12769 _createOverlay: function() {
12770 if ( !this.options.modal ) {
12771 return;
12772 }
12773
12774 // We use a delay in case the overlay is created from an
12775 // event that we're going to be cancelling (#2804)
12776 var isOpening = true;
12777 this._delay( function() {
12778 isOpening = false;
12779 } );
12780
12781 if ( !this.document.data( "ui-dialog-overlays" ) ) {
12782
12783 // Prevent use of anchors and inputs
12784 // Using _on() for an event handler shared across many instances is
12785 // safe because the dialogs stack and must be closed in reverse order
12786 this._on( this.document, {
12787 focusin: function( event ) {
12788 if ( isOpening ) {
12789 return;
12790 }
12791
12792 if ( !this._allowInteraction( event ) ) {
12793 event.preventDefault();
12794 this._trackingInstances()[ 0 ]._focusTabbable();
12795 }
12796 }
12797 } );
12798 }
12799
12800 this.overlay = $( "<div>" )
12801 .appendTo( this._appendTo() );
12802
12803 this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
12804 this._on( this.overlay, {
12805 mousedown: "_keepFocus"
12806 } );
12807 this.document.data( "ui-dialog-overlays",
12808 ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
12809 },
12810
12811 _destroyOverlay: function() {
12812 if ( !this.options.modal ) {
12813 return;
12814 }
12815
12816 if ( this.overlay ) {
12817 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
12818
12819 if ( !overlays ) {
12820 this._off( this.document, "focusin" );
12821 this.document.removeData( "ui-dialog-overlays" );
12822 } else {
12823 this.document.data( "ui-dialog-overlays", overlays );
12824 }
12825
12826 this.overlay.remove();
12827 this.overlay = null;
12828 }
12829 }
12830 } );
12831
12832 // DEPRECATED
12833 // TODO: switch return back to widget declaration at top of file when this is removed
12834 if ( $.uiBackCompat !== false ) {
12835
12836 // Backcompat for dialogClass option
12837 $.widget( "ui.dialog", $.ui.dialog, {
12838 options: {
12839 dialogClass: ""
12840 },
12841 _createWrapper: function() {
12842 this._super();
12843 this.uiDialog.addClass( this.options.dialogClass );
12844 },
12845 _setOption: function( key, value ) {
12846 if ( key === "dialogClass" ) {
12847 this.uiDialog
12848 .removeClass( this.options.dialogClass )
12849 .addClass( value );
12850 }
12851 this._superApply( arguments );
12852 }
12853 } );
12854 }
12855
12856 var widgetsDialog = $.ui.dialog;
12857
12858
12859 /*!
12860 * jQuery UI Droppable 1.12.1
12861 * http://jqueryui.com
12862 *
12863 * Copyright jQuery Foundation and other contributors
12864 * Released under the MIT license.
12865 * http://jquery.org/license
12866 */
12867
12868 //>>label: Droppable
12869 //>>group: Interactions
12870 //>>description: Enables drop targets for draggable elements.
12871 //>>docs: http://api.jqueryui.com/droppable/
12872 //>>demos: http://jqueryui.com/droppable/
12873
12874
12875
12876 $.widget( "ui.droppable", {
12877 version: "1.12.1",
12878 widgetEventPrefix: "drop",
12879 options: {
12880 accept: "*",
12881 addClasses: true,
12882 greedy: false,
12883 scope: "default",
12884 tolerance: "intersect",
12885
12886 // Callbacks
12887 activate: null,
12888 deactivate: null,
12889 drop: null,
12890 out: null,
12891 over: null
12892 },
12893 _create: function() {
12894
12895 var proportions,
12896 o = this.options,
12897 accept = o.accept;
12898
12899 this.isover = false;
12900 this.isout = true;
12901
12902 this.accept = $.isFunction( accept ) ? accept : function( d ) {
12903 return d.is( accept );
12904 };
12905
12906 this.proportions = function( /* valueToWrite */ ) {
12907 if ( arguments.length ) {
12908
12909 // Store the droppable's proportions
12910 proportions = arguments[ 0 ];
12911 } else {
12912
12913 // Retrieve or derive the droppable's proportions
12914 return proportions ?
12915 proportions :
12916 proportions = {
12917 width: this.element[ 0 ].offsetWidth,
12918 height: this.element[ 0 ].offsetHeight
12919 };
12920 }
12921 };
12922
12923 this._addToManager( o.scope );
12924
12925 o.addClasses && this._addClass( "ui-droppable" );
12926
12927 },
12928
12929 _addToManager: function( scope ) {
12930
12931 // Add the reference and positions to the manager
12932 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
12933 $.ui.ddmanager.droppables[ scope ].push( this );
12934 },
12935
12936 _splice: function( drop ) {
12937 var i = 0;
12938 for ( ; i < drop.length; i++ ) {
12939 if ( drop[ i ] === this ) {
12940 drop.splice( i, 1 );
12941 }
12942 }
12943 },
12944
12945 _destroy: function() {
12946 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
12947
12948 this._splice( drop );
12949 },
12950
12951 _setOption: function( key, value ) {
12952
12953 if ( key === "accept" ) {
12954 this.accept = $.isFunction( value ) ? value : function( d ) {
12955 return d.is( value );
12956 };
12957 } else if ( key === "scope" ) {
12958 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
12959
12960 this._splice( drop );
12961 this._addToManager( value );
12962 }
12963
12964 this._super( key, value );
12965 },
12966
12967 _activate: function( event ) {
12968 var draggable = $.ui.ddmanager.current;
12969
12970 this._addActiveClass();
12971 if ( draggable ) {
12972 this._trigger( "activate", event, this.ui( draggable ) );
12973 }
12974 },
12975
12976 _deactivate: function( event ) {
12977 var draggable = $.ui.ddmanager.current;
12978
12979 this._removeActiveClass();
12980 if ( draggable ) {
12981 this._trigger( "deactivate", event, this.ui( draggable ) );
12982 }
12983 },
12984
12985 _over: function( event ) {
12986
12987 var draggable = $.ui.ddmanager.current;
12988
12989 // Bail if draggable and droppable are same element
12990 if ( !draggable || ( draggable.currentItem ||
12991 draggable.element )[ 0 ] === this.element[ 0 ] ) {
12992 return;
12993 }
12994
12995 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
12996 draggable.element ) ) ) {
12997 this._addHoverClass();
12998 this._trigger( "over", event, this.ui( draggable ) );
12999 }
13000
13001 },
13002
13003 _out: function( event ) {
13004
13005 var draggable = $.ui.ddmanager.current;
13006
13007 // Bail if draggable and droppable are same element
13008 if ( !draggable || ( draggable.currentItem ||
13009 draggable.element )[ 0 ] === this.element[ 0 ] ) {
13010 return;
13011 }
13012
13013 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
13014 draggable.element ) ) ) {
13015 this._removeHoverClass();
13016 this._trigger( "out", event, this.ui( draggable ) );
13017 }
13018
13019 },
13020
13021 _drop: function( event, custom ) {
13022
13023 var draggable = custom || $.ui.ddmanager.current,
13024 childrenIntersection = false;
13025
13026 // Bail if draggable and droppable are same element
13027 if ( !draggable || ( draggable.currentItem ||
13028 draggable.element )[ 0 ] === this.element[ 0 ] ) {
13029 return false;
13030 }
13031
13032 this.element
13033 .find( ":data(ui-droppable)" )
13034 .not( ".ui-draggable-dragging" )
13035 .each( function() {
13036 var inst = $( this ).droppable( "instance" );
13037 if (
13038 inst.options.greedy &&
13039 !inst.options.disabled &&
13040 inst.options.scope === draggable.options.scope &&
13041 inst.accept.call(
13042 inst.element[ 0 ], ( draggable.currentItem || draggable.element )
13043 ) &&
13044 intersect(
13045 draggable,
13046 $.extend( inst, { offset: inst.element.offset() } ),
13047 inst.options.tolerance, event
13048 )
13049 ) {
13050 childrenIntersection = true;
13051 return false; }
13052 } );
13053 if ( childrenIntersection ) {
13054 return false;
13055 }
13056
13057 if ( this.accept.call( this.element[ 0 ],
13058 ( draggable.currentItem || draggable.element ) ) ) {
13059 this._removeActiveClass();
13060 this._removeHoverClass();
13061
13062 this._trigger( "drop", event, this.ui( draggable ) );
13063 return this.element;
13064 }
13065
13066 return false;
13067
13068 },
13069
13070 ui: function( c ) {
13071 return {
13072 draggable: ( c.currentItem || c.element ),
13073 helper: c.helper,
13074 position: c.position,
13075 offset: c.positionAbs
13076 };
13077 },
13078
13079 // Extension points just to make backcompat sane and avoid duplicating logic
13080 // TODO: Remove in 1.13 along with call to it below
13081 _addHoverClass: function() {
13082 this._addClass( "ui-droppable-hover" );
13083 },
13084
13085 _removeHoverClass: function() {
13086 this._removeClass( "ui-droppable-hover" );
13087 },
13088
13089 _addActiveClass: function() {
13090 this._addClass( "ui-droppable-active" );
13091 },
13092
13093 _removeActiveClass: function() {
13094 this._removeClass( "ui-droppable-active" );
13095 }
13096 } );
13097
13098 var intersect = $.ui.intersect = ( function() {
13099 function isOverAxis( x, reference, size ) {
13100 return ( x >= reference ) && ( x < ( reference + size ) );
13101 }
13102
13103 return function( draggable, droppable, toleranceMode, event ) {
13104
13105 if ( !droppable.offset ) {
13106 return false;
13107 }
13108
13109 var x1 = ( draggable.positionAbs ||
13110 draggable.position.absolute ).left + draggable.margins.left,
13111 y1 = ( draggable.positionAbs ||
13112 draggable.position.absolute ).top + draggable.margins.top,
13113 x2 = x1 + draggable.helperProportions.width,
13114 y2 = y1 + draggable.helperProportions.height,
13115 l = droppable.offset.left,
13116 t = droppable.offset.top,
13117 r = l + droppable.proportions().width,
13118 b = t + droppable.proportions().height;
13119
13120 switch ( toleranceMode ) {
13121 case "fit":
13122 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
13123 case "intersect":
13124 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
13125 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
13126 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
13127 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
13128 case "pointer":
13129 return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
13130 isOverAxis( event.pageX, l, droppable.proportions().width );
13131 case "touch":
13132 return (
13133 ( y1 >= t && y1 <= b ) || // Top edge touching
13134 ( y2 >= t && y2 <= b ) || // Bottom edge touching
13135 ( y1 < t && y2 > b ) // Surrounded vertically
13136 ) && (
13137 ( x1 >= l && x1 <= r ) || // Left edge touching
13138 ( x2 >= l && x2 <= r ) || // Right edge touching
13139 ( x1 < l && x2 > r ) // Surrounded horizontally
13140 );
13141 default:
13142 return false;
13143 }
13144 };
13145 } )();
13146
13147 /*
13148 This manager tracks offsets of draggables and droppables
13149 */
13150 $.ui.ddmanager = {
13151 current: null,
13152 droppables: { "default": [] },
13153 prepareOffsets: function( t, event ) {
13154
13155 var i, j,
13156 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
13157 type = event ? event.type : null, // workaround for #2317
13158 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
13159
13160 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
13161
13162 // No disabled and non-accepted
13163 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
13164 ( t.currentItem || t.element ) ) ) ) {
13165 continue;
13166 }
13167
13168 // Filter out elements in the current dragged item
13169 for ( j = 0; j < list.length; j++ ) {
13170 if ( list[ j ] === m[ i ].element[ 0 ] ) {
13171 m[ i ].proportions().height = 0;
13172 continue droppablesLoop;
13173 }
13174 }
13175
13176 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
13177 if ( !m[ i ].visible ) {
13178 continue;
13179 }
13180
13181 // Activate the droppable if used directly from draggables
13182 if ( type === "mousedown" ) {
13183 m[ i ]._activate.call( m[ i ], event );
13184 }
13185
13186 m[ i ].offset = m[ i ].element.offset();
13187 m[ i ].proportions( {
13188 width: m[ i ].element[ 0 ].offsetWidth,
13189 height: m[ i ].element[ 0 ].offsetHeight
13190 } );
13191
13192 }
13193
13194 },
13195 drop: function( draggable, event ) {
13196
13197 var dropped = false;
13198
13199 // Create a copy of the droppables in case the list changes during the drop (#9116)
13200 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
13201
13202 if ( !this.options ) {
13203 return;
13204 }
13205 if ( !this.options.disabled && this.visible &&
13206 intersect( draggable, this, this.options.tolerance, event ) ) {
13207 dropped = this._drop.call( this, event ) || dropped;
13208 }
13209
13210 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
13211 ( draggable.currentItem || draggable.element ) ) ) {
13212 this.isout = true;
13213 this.isover = false;
13214 this._deactivate.call( this, event );
13215 }
13216
13217 } );
13218 return dropped;
13219
13220 },
13221 dragStart: function( draggable, event ) {
13222
13223 // Listen for scrolling so that if the dragging causes scrolling the position of the
13224 // droppables can be recalculated (see #5003)
13225 draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
13226 if ( !draggable.options.refreshPositions ) {
13227 $.ui.ddmanager.prepareOffsets( draggable, event );
13228 }
13229 } );
13230 },
13231 drag: function( draggable, event ) {
13232
13233 // If you have a highly dynamic page, you might try this option. It renders positions
13234 // every time you move the mouse.
13235 if ( draggable.options.refreshPositions ) {
13236 $.ui.ddmanager.prepareOffsets( draggable, event );
13237 }
13238
13239 // Run through all droppables and check their positions based on specific tolerance options
13240 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
13241
13242 if ( this.options.disabled || this.greedyChild || !this.visible ) {
13243 return;
13244 }
13245
13246 var parentInstance, scope, parent,
13247 intersects = intersect( draggable, this, this.options.tolerance, event ),
13248 c = !intersects && this.isover ?
13249 "isout" :
13250 ( intersects && !this.isover ? "isover" : null );
13251 if ( !c ) {
13252 return;
13253 }
13254
13255 if ( this.options.greedy ) {
13256
13257 // find droppable parents with same scope
13258 scope = this.options.scope;
13259 parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
13260 return $( this ).droppable( "instance" ).options.scope === scope;
13261 } );
13262
13263 if ( parent.length ) {
13264 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
13265 parentInstance.greedyChild = ( c === "isover" );
13266 }
13267 }
13268
13269 // We just moved into a greedy child
13270 if ( parentInstance && c === "isover" ) {
13271 parentInstance.isover = false;
13272 parentInstance.isout = true;
13273 parentInstance._out.call( parentInstance, event );
13274 }
13275
13276 this[ c ] = true;
13277 this[ c === "isout" ? "isover" : "isout" ] = false;
13278 this[ c === "isover" ? "_over" : "_out" ].call( this, event );
13279
13280 // We just moved out of a greedy child
13281 if ( parentInstance && c === "isout" ) {
13282 parentInstance.isout = false;
13283 parentInstance.isover = true;
13284 parentInstance._over.call( parentInstance, event );
13285 }
13286 } );
13287
13288 },
13289 dragStop: function( draggable, event ) {
13290 draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
13291
13292 // Call prepareOffsets one final time since IE does not fire return scroll events when
13293 // overflow was caused by drag (see #5003)
13294 if ( !draggable.options.refreshPositions ) {
13295 $.ui.ddmanager.prepareOffsets( draggable, event );
13296 }
13297 }
13298 };
13299
13300 // DEPRECATED
13301 // TODO: switch return back to widget declaration at top of file when this is removed
13302 if ( $.uiBackCompat !== false ) {
13303
13304 // Backcompat for activeClass and hoverClass options
13305 $.widget( "ui.droppable", $.ui.droppable, {
13306 options: {
13307 hoverClass: false,
13308 activeClass: false
13309 },
13310 _addActiveClass: function() {
13311 this._super();
13312 if ( this.options.activeClass ) {
13313 this.element.addClass( this.options.activeClass );
13314 }
13315 },
13316 _removeActiveClass: function() {
13317 this._super();
13318 if ( this.options.activeClass ) {
13319 this.element.removeClass( this.options.activeClass );
13320 }
13321 },
13322 _addHoverClass: function() {
13323 this._super();
13324 if ( this.options.hoverClass ) {
13325 this.element.addClass( this.options.hoverClass );
13326 }
13327 },
13328 _removeHoverClass: function() {
13329 this._super();
13330 if ( this.options.hoverClass ) {
13331 this.element.removeClass( this.options.hoverClass );
13332 }
13333 }
13334 } );
13335 }
13336
13337 var widgetsDroppable = $.ui.droppable;
13338
13339
13340 /*!
13341 * jQuery UI Progressbar 1.12.1
13342 * http://jqueryui.com
13343 *
13344 * Copyright jQuery Foundation and other contributors
13345 * Released under the MIT license.
13346 * http://jquery.org/license
13347 */
13348
13349 //>>label: Progressbar
13350 //>>group: Widgets
13351 // jscs:disable maximumLineLength
13352 //>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
13353 // jscs:enable maximumLineLength
13354 //>>docs: http://api.jqueryui.com/progressbar/
13355 //>>demos: http://jqueryui.com/progressbar/
13356 //>>css.structure: ../../themes/base/core.css
13357 //>>css.structure: ../../themes/base/progressbar.css
13358 //>>css.theme: ../../themes/base/theme.css
13359
13360
13361
13362 var widgetsProgressbar = $.widget( "ui.progressbar", {
13363 version: "1.12.1",
13364 options: {
13365 classes: {
13366 "ui-progressbar": "ui-corner-all",
13367 "ui-progressbar-value": "ui-corner-left",
13368 "ui-progressbar-complete": "ui-corner-right"
13369 },
13370 max: 100,
13371 value: 0,
13372
13373 change: null,
13374 complete: null
13375 },
13376
13377 min: 0,
13378
13379 _create: function() {
13380
13381 // Constrain initial value
13382 this.oldValue = this.options.value = this._constrainedValue();
13383
13384 this.element.attr( {
13385
13386 // Only set static values; aria-valuenow and aria-valuemax are
13387 // set inside _refreshValue()
13388 role: "progressbar",
13389 "aria-valuemin": this.min
13390 } );
13391 this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
13392
13393 this.valueDiv = $( "<div>" ).appendTo( this.element );
13394 this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
13395 this._refreshValue();
13396 },
13397
13398 _destroy: function() {
13399 this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
13400
13401 this.valueDiv.remove();
13402 },
13403
13404 value: function( newValue ) {
13405 if ( newValue === undefined ) {
13406 return this.options.value;
13407 }
13408
13409 this.options.value = this._constrainedValue( newValue );
13410 this._refreshValue();
13411 },
13412
13413 _constrainedValue: function( newValue ) {
13414 if ( newValue === undefined ) {
13415 newValue = this.options.value;
13416 }
13417
13418 this.indeterminate = newValue === false;
13419
13420 // Sanitize value
13421 if ( typeof newValue !== "number" ) {
13422 newValue = 0;
13423 }
13424
13425 return this.indeterminate ? false :
13426 Math.min( this.options.max, Math.max( this.min, newValue ) );
13427 },
13428
13429 _setOptions: function( options ) {
13430
13431 // Ensure "value" option is set after other values (like max)
13432 var value = options.value;
13433 delete options.value;
13434
13435 this._super( options );
13436
13437 this.options.value = this._constrainedValue( value );
13438 this._refreshValue();
13439 },
13440
13441 _setOption: function( key, value ) {
13442 if ( key === "max" ) {
13443
13444 // Don't allow a max less than min
13445 value = Math.max( this.min, value );
13446 }
13447 this._super( key, value );
13448 },
13449
13450 _setOptionDisabled: function( value ) {
13451 this._super( value );
13452
13453 this.element.attr( "aria-disabled", value );
13454 this._toggleClass( null, "ui-state-disabled", !!value );
13455 },
13456
13457 _percentage: function() {
13458 return this.indeterminate ?
13459 100 :
13460 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
13461 },
13462
13463 _refreshValue: function() {
13464 var value = this.options.value,
13465 percentage = this._percentage();
13466
13467 this.valueDiv
13468 .toggle( this.indeterminate || value > this.min )
13469 .width( percentage.toFixed( 0 ) + "%" );
13470
13471 this
13472 ._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
13473 value === this.options.max )
13474 ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
13475
13476 if ( this.indeterminate ) {
13477 this.element.removeAttr( "aria-valuenow" );
13478 if ( !this.overlayDiv ) {
13479 this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
13480 this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
13481 }
13482 } else {
13483 this.element.attr( {
13484 "aria-valuemax": this.options.max,
13485 "aria-valuenow": value
13486 } );
13487 if ( this.overlayDiv ) {
13488 this.overlayDiv.remove();
13489 this.overlayDiv = null;
13490 }
13491 }
13492
13493 if ( this.oldValue !== value ) {
13494 this.oldValue = value;
13495 this._trigger( "change" );
13496 }
13497 if ( value === this.options.max ) {
13498 this._trigger( "complete" );
13499 }
13500 }
13501 } );
13502
13503
13504 /*!
13505 * jQuery UI Selectable 1.12.1
13506 * http://jqueryui.com
13507 *
13508 * Copyright jQuery Foundation and other contributors
13509 * Released under the MIT license.
13510 * http://jquery.org/license
13511 */
13512
13513 //>>label: Selectable
13514 //>>group: Interactions
13515 //>>description: Allows groups of elements to be selected with the mouse.
13516 //>>docs: http://api.jqueryui.com/selectable/
13517 //>>demos: http://jqueryui.com/selectable/
13518 //>>css.structure: ../../themes/base/selectable.css
13519
13520
13521
13522 var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
13523 version: "1.12.1",
13524 options: {
13525 appendTo: "body",
13526 autoRefresh: true,
13527 distance: 0,
13528 filter: "*",
13529 tolerance: "touch",
13530
13531 // Callbacks
13532 selected: null,
13533 selecting: null,
13534 start: null,
13535 stop: null,
13536 unselected: null,
13537 unselecting: null
13538 },
13539 _create: function() {
13540 var that = this;
13541
13542 this._addClass( "ui-selectable" );
13543
13544 this.dragged = false;
13545
13546 // Cache selectee children based on filter
13547 this.refresh = function() {
13548 that.elementPos = $( that.element[ 0 ] ).offset();
13549 that.selectees = $( that.options.filter, that.element[ 0 ] );
13550 that._addClass( that.selectees, "ui-selectee" );
13551 that.selectees.each( function() {
13552 var $this = $( this ),
13553 selecteeOffset = $this.offset(),
13554 pos = {
13555 left: selecteeOffset.left - that.elementPos.left,
13556 top: selecteeOffset.top - that.elementPos.top
13557 };
13558 $.data( this, "selectable-item", {
13559 element: this,
13560 $element: $this,
13561 left: pos.left,
13562 top: pos.top,
13563 right: pos.left + $this.outerWidth(),
13564 bottom: pos.top + $this.outerHeight(),
13565 startselected: false,
13566 selected: $this.hasClass( "ui-selected" ),
13567 selecting: $this.hasClass( "ui-selecting" ),
13568 unselecting: $this.hasClass( "ui-unselecting" )
13569 } );
13570 } );
13571 };
13572 this.refresh();
13573
13574 this._mouseInit();
13575
13576 this.helper = $( "<div>" );
13577 this._addClass( this.helper, "ui-selectable-helper" );
13578 },
13579
13580 _destroy: function() {
13581 this.selectees.removeData( "selectable-item" );
13582 this._mouseDestroy();
13583 },
13584
13585 _mouseStart: function( event ) {
13586 var that = this,
13587 options = this.options;
13588
13589 this.opos = [ event.pageX, event.pageY ];
13590 this.elementPos = $( this.element[ 0 ] ).offset();
13591
13592 if ( this.options.disabled ) {
13593 return;
13594 }
13595
13596 this.selectees = $( options.filter, this.element[ 0 ] );
13597
13598 this._trigger( "start", event );
13599
13600 $( options.appendTo ).append( this.helper );
13601
13602 // position helper (lasso)
13603 this.helper.css( {
13604 "left": event.pageX,
13605 "top": event.pageY,
13606 "width": 0,
13607 "height": 0
13608 } );
13609
13610 if ( options.autoRefresh ) {
13611 this.refresh();
13612 }
13613
13614 this.selectees.filter( ".ui-selected" ).each( function() {
13615 var selectee = $.data( this, "selectable-item" );
13616 selectee.startselected = true;
13617 if ( !event.metaKey && !event.ctrlKey ) {
13618 that._removeClass( selectee.$element, "ui-selected" );
13619 selectee.selected = false;
13620 that._addClass( selectee.$element, "ui-unselecting" );
13621 selectee.unselecting = true;
13622
13623 // selectable UNSELECTING callback
13624 that._trigger( "unselecting", event, {
13625 unselecting: selectee.element
13626 } );
13627 }
13628 } );
13629
13630 $( event.target ).parents().addBack().each( function() {
13631 var doSelect,
13632 selectee = $.data( this, "selectable-item" );
13633 if ( selectee ) {
13634 doSelect = ( !event.metaKey && !event.ctrlKey ) ||
13635 !selectee.$element.hasClass( "ui-selected" );
13636 that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
13637 ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
13638 selectee.unselecting = !doSelect;
13639 selectee.selecting = doSelect;
13640 selectee.selected = doSelect;
13641
13642 // selectable (UN)SELECTING callback
13643 if ( doSelect ) {
13644 that._trigger( "selecting", event, {
13645 selecting: selectee.element
13646 } );
13647 } else {
13648 that._trigger( "unselecting", event, {
13649 unselecting: selectee.element
13650 } );
13651 }
13652 return false;
13653 }
13654 } );
13655
13656 },
13657
13658 _mouseDrag: function( event ) {
13659
13660 this.dragged = true;
13661
13662 if ( this.options.disabled ) {
13663 return;
13664 }
13665
13666 var tmp,
13667 that = this,
13668 options = this.options,
13669 x1 = this.opos[ 0 ],
13670 y1 = this.opos[ 1 ],
13671 x2 = event.pageX,
13672 y2 = event.pageY;
13673
13674 if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; }
13675 if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; }
13676 this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
13677
13678 this.selectees.each( function() {
13679 var selectee = $.data( this, "selectable-item" ),
13680 hit = false,
13681 offset = {};
13682
13683 //prevent helper from being selected if appendTo: selectable
13684 if ( !selectee || selectee.element === that.element[ 0 ] ) {
13685 return;
13686 }
13687
13688 offset.left = selectee.left + that.elementPos.left;
13689 offset.right = selectee.right + that.elementPos.left;
13690 offset.top = selectee.top + that.elementPos.top;
13691 offset.bottom = selectee.bottom + that.elementPos.top;
13692
13693 if ( options.tolerance === "touch" ) {
13694 hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
13695 offset.bottom < y1 ) );
13696 } else if ( options.tolerance === "fit" ) {
13697 hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
13698 offset.bottom < y2 );
13699 }
13700
13701 if ( hit ) {
13702
13703 // SELECT
13704 if ( selectee.selected ) {
13705 that._removeClass( selectee.$element, "ui-selected" );
13706 selectee.selected = false;
13707 }
13708 if ( selectee.unselecting ) {
13709 that._removeClass( selectee.$element, "ui-unselecting" );
13710 selectee.unselecting = false;
13711 }
13712 if ( !selectee.selecting ) {
13713 that._addClass( selectee.$element, "ui-selecting" );
13714 selectee.selecting = true;
13715
13716 // selectable SELECTING callback
13717 that._trigger( "selecting", event, {
13718 selecting: selectee.element
13719 } );
13720 }
13721 } else {
13722
13723 // UNSELECT
13724 if ( selectee.selecting ) {
13725 if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
13726 that._removeClass( selectee.$element, "ui-selecting" );
13727 selectee.selecting = false;
13728 that._addClass( selectee.$element, "ui-selected" );
13729 selectee.selected = true;
13730 } else {
13731 that._removeClass( selectee.$element, "ui-selecting" );
13732 selectee.selecting = false;
13733 if ( selectee.startselected ) {
13734 that._addClass( selectee.$element, "ui-unselecting" );
13735 selectee.unselecting = true;
13736 }
13737
13738 // selectable UNSELECTING callback
13739 that._trigger( "unselecting", event, {
13740 unselecting: selectee.element
13741 } );
13742 }
13743 }
13744 if ( selectee.selected ) {
13745 if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
13746 that._removeClass( selectee.$element, "ui-selected" );
13747 selectee.selected = false;
13748
13749 that._addClass( selectee.$element, "ui-unselecting" );
13750 selectee.unselecting = true;
13751
13752 // selectable UNSELECTING callback
13753 that._trigger( "unselecting", event, {
13754 unselecting: selectee.element
13755 } );
13756 }
13757 }
13758 }
13759 } );
13760
13761 return false;
13762 },
13763
13764 _mouseStop: function( event ) {
13765 var that = this;
13766
13767 this.dragged = false;
13768
13769 $( ".ui-unselecting", this.element[ 0 ] ).each( function() {
13770 var selectee = $.data( this, "selectable-item" );
13771 that._removeClass( selectee.$element, "ui-unselecting" );
13772 selectee.unselecting = false;
13773 selectee.startselected = false;
13774 that._trigger( "unselected", event, {
13775 unselected: selectee.element
13776 } );
13777 } );
13778 $( ".ui-selecting", this.element[ 0 ] ).each( function() {
13779 var selectee = $.data( this, "selectable-item" );
13780 that._removeClass( selectee.$element, "ui-selecting" )
13781 ._addClass( selectee.$element, "ui-selected" );
13782 selectee.selecting = false;
13783 selectee.selected = true;
13784 selectee.startselected = true;
13785 that._trigger( "selected", event, {
13786 selected: selectee.element
13787 } );
13788 } );
13789 this._trigger( "stop", event );
13790
13791 this.helper.remove();
13792
13793 return false;
13794 }
13795
13796 } );
13797
13798
13799 /*!
13800 * jQuery UI Selectmenu 1.12.1
13801 * http://jqueryui.com
13802 *
13803 * Copyright jQuery Foundation and other contributors
13804 * Released under the MIT license.
13805 * http://jquery.org/license
13806 */
13807
13808 //>>label: Selectmenu
13809 //>>group: Widgets
13810 // jscs:disable maximumLineLength
13811 //>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
13812 // jscs:enable maximumLineLength
13813 //>>docs: http://api.jqueryui.com/selectmenu/
13814 //>>demos: http://jqueryui.com/selectmenu/
13815 //>>css.structure: ../../themes/base/core.css
13816 //>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
13817 //>>css.theme: ../../themes/base/theme.css
13818
13819
13820
13821 var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
13822 version: "1.12.1",
13823 defaultElement: "<select>",
13824 options: {
13825 appendTo: null,
13826 classes: {
13827 "ui-selectmenu-button-open": "ui-corner-top",
13828 "ui-selectmenu-button-closed": "ui-corner-all"
13829 },
13830 disabled: null,
13831 icons: {
13832 button: "ui-icon-triangle-1-s"
13833 },
13834 position: {
13835 my: "left top",
13836 at: "left bottom",
13837 collision: "none"
13838 },
13839 width: false,
13840
13841 // Callbacks
13842 change: null,
13843 close: null,
13844 focus: null,
13845 open: null,
13846 select: null
13847 },
13848
13849 _create: function() {
13850 var selectmenuId = this.element.uniqueId().attr( "id" );
13851 this.ids = {
13852 element: selectmenuId,
13853 button: selectmenuId + "-button",
13854 menu: selectmenuId + "-menu"
13855 };
13856
13857 this._drawButton();
13858 this._drawMenu();
13859 this._bindFormResetHandler();
13860
13861 this._rendered = false;
13862 this.menuItems = $();
13863 },
13864
13865 _drawButton: function() {
13866 var icon,
13867 that = this,
13868 item = this._parseOption(
13869 this.element.find( "option:selected" ),
13870 this.element[ 0 ].selectedIndex
13871 );
13872
13873 // Associate existing label with the new button
13874 this.labels = this.element.labels().attr( "for", this.ids.button );
13875 this._on( this.labels, {
13876 click: function( event ) {
13877 this.button.focus();
13878 event.preventDefault();
13879 }
13880 } );
13881
13882 // Hide original select element
13883 this.element.hide();
13884
13885 // Create button
13886 this.button = $( "<span>", {
13887 tabindex: this.options.disabled ? -1 : 0,
13888 id: this.ids.button,
13889 role: "combobox",
13890 "aria-expanded": "false",
13891 "aria-autocomplete": "list",
13892 "aria-owns": this.ids.menu,
13893 "aria-haspopup": "true",
13894 title: this.element.attr( "title" )
13895 } )
13896 .insertAfter( this.element );
13897
13898 this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
13899 "ui-button ui-widget" );
13900
13901 icon = $( "<span>" ).appendTo( this.button );
13902 this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
13903 this.buttonItem = this._renderButtonItem( item )
13904 .appendTo( this.button );
13905
13906 if ( this.options.width !== false ) {
13907 this._resizeButton();
13908 }
13909
13910 this._on( this.button, this._buttonEvents );
13911 this.button.one( "focusin", function() {
13912
13913 // Delay rendering the menu items until the button receives focus.
13914 // The menu may have already been rendered via a programmatic open.
13915 if ( !that._rendered ) {
13916 that._refreshMenu();
13917 }
13918 } );
13919 },
13920
13921 _drawMenu: function() {
13922 var that = this;
13923
13924 // Create menu
13925 this.menu = $( "<ul>", {
13926 "aria-hidden": "true",
13927 "aria-labelledby": this.ids.button,
13928 id: this.ids.menu
13929 } );
13930
13931 // Wrap menu
13932 this.menuWrap = $( "<div>" ).append( this.menu );
13933 this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
13934 this.menuWrap.appendTo( this._appendTo() );
13935
13936 // Initialize menu widget
13937 this.menuInstance = this.menu
13938 .menu( {
13939 classes: {
13940 "ui-menu": "ui-corner-bottom"
13941 },
13942 role: "listbox",
13943 select: function( event, ui ) {
13944 event.preventDefault();
13945
13946 // Support: IE8
13947 // If the item was selected via a click, the text selection
13948 // will be destroyed in IE
13949 that._setSelection();
13950
13951 that._select( ui.item.data( "ui-selectmenu-item" ), event );
13952 },
13953 focus: function( event, ui ) {
13954 var item = ui.item.data( "ui-selectmenu-item" );
13955
13956 // Prevent inital focus from firing and check if its a newly focused item
13957 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
13958 that._trigger( "focus", event, { item: item } );
13959 if ( !that.isOpen ) {
13960 that._select( item, event );
13961 }
13962 }
13963 that.focusIndex = item.index;
13964
13965 that.button.attr( "aria-activedescendant",
13966 that.menuItems.eq( item.index ).attr( "id" ) );
13967 }
13968 } )
13969 .menu( "instance" );
13970
13971 // Don't close the menu on mouseleave
13972 this.menuInstance._off( this.menu, "mouseleave" );
13973
13974 // Cancel the menu's collapseAll on document click
13975 this.menuInstance._closeOnDocumentClick = function() {
13976 return false;
13977 };
13978
13979 // Selects often contain empty items, but never contain dividers
13980 this.menuInstance._isDivider = function() {
13981 return false;
13982 };
13983 },
13984
13985 refresh: function() {
13986 this._refreshMenu();
13987 this.buttonItem.replaceWith(
13988 this.buttonItem = this._renderButtonItem(
13989
13990 // Fall back to an empty object in case there are no options
13991 this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
13992 )
13993 );
13994 if ( this.options.width === null ) {
13995 this._resizeButton();
13996 }
13997 },
13998
13999 _refreshMenu: function() {
14000 var item,
14001 options = this.element.find( "option" );
14002
14003 this.menu.empty();
14004
14005 this._parseOptions( options );
14006 this._renderMenu( this.menu, this.items );
14007
14008 this.menuInstance.refresh();
14009 this.menuItems = this.menu.find( "li" )
14010 .not( ".ui-selectmenu-optgroup" )
14011 .find( ".ui-menu-item-wrapper" );
14012
14013 this._rendered = true;
14014
14015 if ( !options.length ) {
14016 return;
14017 }
14018
14019 item = this._getSelectedItem();
14020
14021 // Update the menu to have the correct item focused
14022 this.menuInstance.focus( null, item );
14023 this._setAria( item.data( "ui-selectmenu-item" ) );
14024
14025 // Set disabled state
14026 this._setOption( "disabled", this.element.prop( "disabled" ) );
14027 },
14028
14029 open: function( event ) {
14030 if ( this.options.disabled ) {
14031 return;
14032 }
14033
14034 // If this is the first time the menu is being opened, render the items
14035 if ( !this._rendered ) {
14036 this._refreshMenu();
14037 } else {
14038
14039 // Menu clears focus on close, reset focus to selected item
14040 this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
14041 this.menuInstance.focus( null, this._getSelectedItem() );
14042 }
14043
14044 // If there are no options, don't open the menu
14045 if ( !this.menuItems.length ) {
14046 return;
14047 }
14048
14049 this.isOpen = true;
14050 this._toggleAttr();
14051 this._resizeMenu();
14052 this._position();
14053
14054 this._on( this.document, this._documentClick );
14055
14056 this._trigger( "open", event );
14057 },
14058
14059 _position: function() {
14060 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
14061 },
14062
14063 close: function( event ) {
14064 if ( !this.isOpen ) {
14065 return;
14066 }
14067
14068 this.isOpen = false;
14069 this._toggleAttr();
14070
14071 this.range = null;
14072 this._off( this.document );
14073
14074 this._trigger( "close", event );
14075 },
14076
14077 widget: function() {
14078 return this.button;
14079 },
14080
14081 menuWidget: function() {
14082 return this.menu;
14083 },
14084
14085 _renderButtonItem: function( item ) {
14086 var buttonItem = $( "<span>" );
14087
14088 this._setText( buttonItem, item.label );
14089 this._addClass( buttonItem, "ui-selectmenu-text" );
14090
14091 return buttonItem;
14092 },
14093
14094 _renderMenu: function( ul, items ) {
14095 var that = this,
14096 currentOptgroup = "";
14097
14098 $.each( items, function( index, item ) {
14099 var li;
14100
14101 if ( item.optgroup !== currentOptgroup ) {
14102 li = $( "<li>", {
14103 text: item.optgroup
14104 } );
14105 that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
14106 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
14107 " ui-state-disabled" :
14108 "" ) );
14109
14110 li.appendTo( ul );
14111
14112 currentOptgroup = item.optgroup;
14113 }
14114
14115 that._renderItemData( ul, item );
14116 } );
14117 },
14118
14119 _renderItemData: function( ul, item ) {
14120 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
14121 },
14122
14123 _renderItem: function( ul, item ) {
14124 var li = $( "<li>" ),
14125 wrapper = $( "<div>", {
14126 title: item.element.attr( "title" )
14127 } );
14128
14129 if ( item.disabled ) {
14130 this._addClass( li, null, "ui-state-disabled" );
14131 }
14132 this._setText( wrapper, item.label );
14133
14134 return li.append( wrapper ).appendTo( ul );
14135 },
14136
14137 _setText: function( element, value ) {
14138 if ( value ) {
14139 element.text( value );
14140 } else {
14141 element.html( "&#160;" );
14142 }
14143 },
14144
14145 _move: function( direction, event ) {
14146 var item, next,
14147 filter = ".ui-menu-item";
14148
14149 if ( this.isOpen ) {
14150 item = this.menuItems.eq( this.focusIndex ).parent( "li" );
14151 } else {
14152 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
14153 filter += ":not(.ui-state-disabled)";
14154 }
14155
14156 if ( direction === "first" || direction === "last" ) {
14157 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
14158 } else {
14159 next = item[ direction + "All" ]( filter ).eq( 0 );
14160 }
14161
14162 if ( next.length ) {
14163 this.menuInstance.focus( event, next );
14164 }
14165 },
14166
14167 _getSelectedItem: function() {
14168 return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
14169 },
14170
14171 _toggle: function( event ) {
14172 this[ this.isOpen ? "close" : "open" ]( event );
14173 },
14174
14175 _setSelection: function() {
14176 var selection;
14177
14178 if ( !this.range ) {
14179 return;
14180 }
14181
14182 if ( window.getSelection ) {
14183 selection = window.getSelection();
14184 selection.removeAllRanges();
14185 selection.addRange( this.range );
14186
14187 // Support: IE8
14188 } else {
14189 this.range.select();
14190 }
14191
14192 // Support: IE
14193 // Setting the text selection kills the button focus in IE, but
14194 // restoring the focus doesn't kill the selection.
14195 this.button.focus();
14196 },
14197
14198 _documentClick: {
14199 mousedown: function( event ) {
14200 if ( !this.isOpen ) {
14201 return;
14202 }
14203
14204 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
14205 $.ui.escapeSelector( this.ids.button ) ).length ) {
14206 this.close( event );
14207 }
14208 }
14209 },
14210
14211 _buttonEvents: {
14212
14213 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
14214 mousedown: function() {
14215 var selection;
14216
14217 if ( window.getSelection ) {
14218 selection = window.getSelection();
14219 if ( selection.rangeCount ) {
14220 this.range = selection.getRangeAt( 0 );
14221 }
14222
14223 // Support: IE8
14224 } else {
14225 this.range = document.selection.createRange();
14226 }
14227 },
14228
14229 click: function( event ) {
14230 this._setSelection();
14231 this._toggle( event );
14232 },
14233
14234 keydown: function( event ) {
14235 var preventDefault = true;
14236 switch ( event.keyCode ) {
14237 case $.ui.keyCode.TAB:
14238 case $.ui.keyCode.ESCAPE:
14239 this.close( event );
14240 preventDefault = false;
14241 break;
14242 case $.ui.keyCode.ENTER:
14243 if ( this.isOpen ) {
14244 this._selectFocusedItem( event );
14245 }
14246 break;
14247 case $.ui.keyCode.UP:
14248 if ( event.altKey ) {
14249 this._toggle( event );
14250 } else {
14251 this._move( "prev", event );
14252 }
14253 break;
14254 case $.ui.keyCode.DOWN:
14255 if ( event.altKey ) {
14256 this._toggle( event );
14257 } else {
14258 this._move( "next", event );
14259 }
14260 break;
14261 case $.ui.keyCode.SPACE:
14262 if ( this.isOpen ) {
14263 this._selectFocusedItem( event );
14264 } else {
14265 this._toggle( event );
14266 }
14267 break;
14268 case $.ui.keyCode.LEFT:
14269 this._move( "prev", event );
14270 break;
14271 case $.ui.keyCode.RIGHT:
14272 this._move( "next", event );
14273 break;
14274 case $.ui.keyCode.HOME:
14275 case $.ui.keyCode.PAGE_UP:
14276 this._move( "first", event );
14277 break;
14278 case $.ui.keyCode.END:
14279 case $.ui.keyCode.PAGE_DOWN:
14280 this._move( "last", event );
14281 break;
14282 default:
14283 this.menu.trigger( event );
14284 preventDefault = false;
14285 }
14286
14287 if ( preventDefault ) {
14288 event.preventDefault();
14289 }
14290 }
14291 },
14292
14293 _selectFocusedItem: function( event ) {
14294 var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
14295 if ( !item.hasClass( "ui-state-disabled" ) ) {
14296 this._select( item.data( "ui-selectmenu-item" ), event );
14297 }
14298 },
14299
14300 _select: function( item, event ) {
14301 var oldIndex = this.element[ 0 ].selectedIndex;
14302
14303 // Change native select element
14304 this.element[ 0 ].selectedIndex = item.index;
14305 this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
14306 this._setAria( item );
14307 this._trigger( "select", event, { item: item } );
14308
14309 if ( item.index !== oldIndex ) {
14310 this._trigger( "change", event, { item: item } );
14311 }
14312
14313 this.close( event );
14314 },
14315
14316 _setAria: function( item ) {
14317 var id = this.menuItems.eq( item.index ).attr( "id" );
14318
14319 this.button.attr( {
14320 "aria-labelledby": id,
14321 "aria-activedescendant": id
14322 } );
14323 this.menu.attr( "aria-activedescendant", id );
14324 },
14325
14326 _setOption: function( key, value ) {
14327 if ( key === "icons" ) {
14328 var icon = this.button.find( "span.ui-icon" );
14329 this._removeClass( icon, null, this.options.icons.button )
14330 ._addClass( icon, null, value.button );
14331 }
14332
14333 this._super( key, value );
14334
14335 if ( key === "appendTo" ) {
14336 this.menuWrap.appendTo( this._appendTo() );
14337 }
14338
14339 if ( key === "width" ) {
14340 this._resizeButton();
14341 }
14342 },
14343
14344 _setOptionDisabled: function( value ) {
14345 this._super( value );
14346
14347 this.menuInstance.option( "disabled", value );
14348 this.button.attr( "aria-disabled", value );
14349 this._toggleClass( this.button, null, "ui-state-disabled", value );
14350
14351 this.element.prop( "disabled", value );
14352 if ( value ) {
14353 this.button.attr( "tabindex", -1 );
14354 this.close();
14355 } else {
14356 this.button.attr( "tabindex", 0 );
14357 }
14358 },
14359
14360 _appendTo: function() {
14361 var element = this.options.appendTo;
14362
14363 if ( element ) {
14364 element = element.jquery || element.nodeType ?
14365 $( element ) :
14366 this.document.find( element ).eq( 0 );
14367 }
14368
14369 if ( !element || !element[ 0 ] ) {
14370 element = this.element.closest( ".ui-front, dialog" );
14371 }
14372
14373 if ( !element.length ) {
14374 element = this.document[ 0 ].body;
14375 }
14376
14377 return element;
14378 },
14379
14380 _toggleAttr: function() {
14381 this.button.attr( "aria-expanded", this.isOpen );
14382
14383 // We can't use two _toggleClass() calls here, because we need to make sure
14384 // we always remove classes first and add them second, otherwise if both classes have the
14385 // same theme class, it will be removed after we add it.
14386 this._removeClass( this.button, "ui-selectmenu-button-" +
14387 ( this.isOpen ? "closed" : "open" ) )
14388 ._addClass( this.button, "ui-selectmenu-button-" +
14389 ( this.isOpen ? "open" : "closed" ) )
14390 ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
14391
14392 this.menu.attr( "aria-hidden", !this.isOpen );
14393 },
14394
14395 _resizeButton: function() {
14396 var width = this.options.width;
14397
14398 // For `width: false`, just remove inline style and stop
14399 if ( width === false ) {
14400 this.button.css( "width", "" );
14401 return;
14402 }
14403
14404 // For `width: null`, match the width of the original element
14405 if ( width === null ) {
14406 width = this.element.show().outerWidth();
14407 this.element.hide();
14408 }
14409
14410 this.button.outerWidth( width );
14411 },
14412
14413 _resizeMenu: function() {
14414 this.menu.outerWidth( Math.max(
14415 this.button.outerWidth(),
14416
14417 // Support: IE10
14418 // IE10 wraps long text (possibly a rounding bug)
14419 // so we add 1px to avoid the wrapping
14420 this.menu.width( "" ).outerWidth() + 1
14421 ) );
14422 },
14423
14424 _getCreateOptions: function() {
14425 var options = this._super();
14426
14427 options.disabled = this.element.prop( "disabled" );
14428
14429 return options;
14430 },
14431
14432 _parseOptions: function( options ) {
14433 var that = this,
14434 data = [];
14435 options.each( function( index, item ) {
14436 data.push( that._parseOption( $( item ), index ) );
14437 } );
14438 this.items = data;
14439 },
14440
14441 _parseOption: function( option, index ) {
14442 var optgroup = option.parent( "optgroup" );
14443
14444 return {
14445 element: option,
14446 index: index,
14447 value: option.val(),
14448 label: option.text(),
14449 optgroup: optgroup.attr( "label" ) || "",
14450 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
14451 };
14452 },
14453
14454 _destroy: function() {
14455 this._unbindFormResetHandler();
14456 this.menuWrap.remove();
14457 this.button.remove();
14458 this.element.show();
14459 this.element.removeUniqueId();
14460 this.labels.attr( "for", this.ids.element );
14461 }
14462 } ] );
14463
14464
14465 /*!
14466 * jQuery UI Slider 1.12.1
14467 * http://jqueryui.com
14468 *
14469 * Copyright jQuery Foundation and other contributors
14470 * Released under the MIT license.
14471 * http://jquery.org/license
14472 */
14473
14474 //>>label: Slider
14475 //>>group: Widgets
14476 //>>description: Displays a flexible slider with ranges and accessibility via keyboard.
14477 //>>docs: http://api.jqueryui.com/slider/
14478 //>>demos: http://jqueryui.com/slider/
14479 //>>css.structure: ../../themes/base/core.css
14480 //>>css.structure: ../../themes/base/slider.css
14481 //>>css.theme: ../../themes/base/theme.css
14482
14483
14484
14485 var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
14486 version: "1.12.1",
14487 widgetEventPrefix: "slide",
14488
14489 options: {
14490 animate: false,
14491 classes: {
14492 "ui-slider": "ui-corner-all",
14493 "ui-slider-handle": "ui-corner-all",
14494
14495 // Note: ui-widget-header isn't the most fittingly semantic framework class for this
14496 // element, but worked best visually with a variety of themes
14497 "ui-slider-range": "ui-corner-all ui-widget-header"
14498 },
14499 distance: 0,
14500 max: 100,
14501 min: 0,
14502 orientation: "horizontal",
14503 range: false,
14504 step: 1,
14505 value: 0,
14506 values: null,
14507
14508 // Callbacks
14509 change: null,
14510 slide: null,
14511 start: null,
14512 stop: null
14513 },
14514
14515 // Number of pages in a slider
14516 // (how many times can you page up/down to go through the whole range)
14517 numPages: 5,
14518
14519 _create: function() {
14520 this._keySliding = false;
14521 this._mouseSliding = false;
14522 this._animateOff = true;
14523 this._handleIndex = null;
14524 this._detectOrientation();
14525 this._mouseInit();
14526 this._calculateNewMax();
14527
14528 this._addClass( "ui-slider ui-slider-" + this.orientation,
14529 "ui-widget ui-widget-content" );
14530
14531 this._refresh();
14532
14533 this._animateOff = false;
14534 },
14535
14536 _refresh: function() {
14537 this._createRange();
14538 this._createHandles();
14539 this._setupEvents();
14540 this._refreshValue();
14541 },
14542
14543 _createHandles: function() {
14544 var i, handleCount,
14545 options = this.options,
14546 existingHandles = this.element.find( ".ui-slider-handle" ),
14547 handle = "<span tabindex='0'></span>",
14548 handles = [];
14549
14550 handleCount = ( options.values && options.values.length ) || 1;
14551
14552 if ( existingHandles.length > handleCount ) {
14553 existingHandles.slice( handleCount ).remove();
14554 existingHandles = existingHandles.slice( 0, handleCount );
14555 }
14556
14557 for ( i = existingHandles.length; i < handleCount; i++ ) {
14558 handles.push( handle );
14559 }
14560
14561 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
14562
14563 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
14564
14565 this.handle = this.handles.eq( 0 );
14566
14567 this.handles.each( function( i ) {
14568 $( this )
14569 .data( "ui-slider-handle-index", i )
14570 .attr( "tabIndex", 0 );
14571 } );
14572 },
14573
14574 _createRange: function() {
14575 var options = this.options;
14576
14577 if ( options.range ) {
14578 if ( options.range === true ) {
14579 if ( !options.values ) {
14580 options.values = [ this._valueMin(), this._valueMin() ];
14581 } else if ( options.values.length && options.values.length !== 2 ) {
14582 options.values = [ options.values[ 0 ], options.values[ 0 ] ];
14583 } else if ( $.isArray( options.values ) ) {
14584 options.values = options.values.slice( 0 );
14585 }
14586 }
14587
14588 if ( !this.range || !this.range.length ) {
14589 this.range = $( "<div>" )
14590 .appendTo( this.element );
14591
14592 this._addClass( this.range, "ui-slider-range" );
14593 } else {
14594 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
14595
14596 // Handle range switching from true to min/max
14597 this.range.css( {
14598 "left": "",
14599 "bottom": ""
14600 } );
14601 }
14602 if ( options.range === "min" || options.range === "max" ) {
14603 this._addClass( this.range, "ui-slider-range-" + options.range );
14604 }
14605 } else {
14606 if ( this.range ) {
14607 this.range.remove();
14608 }
14609 this.range = null;
14610 }
14611 },
14612
14613 _setupEvents: function() {
14614 this._off( this.handles );
14615 this._on( this.handles, this._handleEvents );
14616 this._hoverable( this.handles );
14617 this._focusable( this.handles );
14618 },
14619
14620 _destroy: function() {
14621 this.handles.remove();
14622 if ( this.range ) {
14623 this.range.remove();
14624 }
14625
14626 this._mouseDestroy();
14627 },
14628
14629 _mouseCapture: function( event ) {
14630 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
14631 that = this,
14632 o = this.options;
14633
14634 if ( o.disabled ) {
14635 return false;
14636 }
14637
14638 this.elementSize = {
14639 width: this.element.outerWidth(),
14640 height: this.element.outerHeight()
14641 };
14642 this.elementOffset = this.element.offset();
14643
14644 position = { x: event.pageX, y: event.pageY };
14645 normValue = this._normValueFromMouse( position );
14646 distance = this._valueMax() - this._valueMin() + 1;
14647 this.handles.each( function( i ) {
14648 var thisDistance = Math.abs( normValue - that.values( i ) );
14649 if ( ( distance > thisDistance ) ||
14650 ( distance === thisDistance &&
14651 ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
14652 distance = thisDistance;
14653 closestHandle = $( this );
14654 index = i;
14655 }
14656 } );
14657
14658 allowed = this._start( event, index );
14659 if ( allowed === false ) {
14660 return false;
14661 }
14662 this._mouseSliding = true;
14663
14664 this._handleIndex = index;
14665
14666 this._addClass( closestHandle, null, "ui-state-active" );
14667 closestHandle.trigger( "focus" );
14668
14669 offset = closestHandle.offset();
14670 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
14671 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
14672 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
14673 top: event.pageY - offset.top -
14674 ( closestHandle.height() / 2 ) -
14675 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
14676 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
14677 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
14678 };
14679
14680 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
14681 this._slide( event, index, normValue );
14682 }
14683 this._animateOff = true;
14684 return true;
14685 },
14686
14687 _mouseStart: function() {
14688 return true;
14689 },
14690
14691 _mouseDrag: function( event ) {
14692 var position = { x: event.pageX, y: event.pageY },
14693 normValue = this._normValueFromMouse( position );
14694
14695 this._slide( event, this._handleIndex, normValue );
14696
14697 return false;
14698 },
14699
14700 _mouseStop: function( event ) {
14701 this._removeClass( this.handles, null, "ui-state-active" );
14702 this._mouseSliding = false;
14703
14704 this._stop( event, this._handleIndex );
14705 this._change( event, this._handleIndex );
14706
14707 this._handleIndex = null;
14708 this._clickOffset = null;
14709 this._animateOff = false;
14710
14711 return false;
14712 },
14713
14714 _detectOrientation: function() {
14715 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
14716 },
14717
14718 _normValueFromMouse: function( position ) {
14719 var pixelTotal,
14720 pixelMouse,
14721 percentMouse,
14722 valueTotal,
14723 valueMouse;
14724
14725 if ( this.orientation === "horizontal" ) {
14726 pixelTotal = this.elementSize.width;
14727 pixelMouse = position.x - this.elementOffset.left -
14728 ( this._clickOffset ? this._clickOffset.left : 0 );
14729 } else {
14730 pixelTotal = this.elementSize.height;
14731 pixelMouse = position.y - this.elementOffset.top -
14732 ( this._clickOffset ? this._clickOffset.top : 0 );
14733 }
14734
14735 percentMouse = ( pixelMouse / pixelTotal );
14736 if ( percentMouse > 1 ) {
14737 percentMouse = 1;
14738 }
14739 if ( percentMouse < 0 ) {
14740 percentMouse = 0;
14741 }
14742 if ( this.orientation === "vertical" ) {
14743 percentMouse = 1 - percentMouse;
14744 }
14745
14746 valueTotal = this._valueMax() - this._valueMin();
14747 valueMouse = this._valueMin() + percentMouse * valueTotal;
14748
14749 return this._trimAlignValue( valueMouse );
14750 },
14751
14752 _uiHash: function( index, value, values ) {
14753 var uiHash = {
14754 handle: this.handles[ index ],
14755 handleIndex: index,
14756 value: value !== undefined ? value : this.value()
14757 };
14758
14759 if ( this._hasMultipleValues() ) {
14760 uiHash.value = value !== undefined ? value : this.values( index );
14761 uiHash.values = values || this.values();
14762 }
14763
14764 return uiHash;
14765 },
14766
14767 _hasMultipleValues: function() {
14768 return this.options.values && this.options.values.length;
14769 },
14770
14771 _start: function( event, index ) {
14772 return this._trigger( "start", event, this._uiHash( index ) );
14773 },
14774
14775 _slide: function( event, index, newVal ) {
14776 var allowed, otherVal,
14777 currentValue = this.value(),
14778 newValues = this.values();
14779
14780 if ( this._hasMultipleValues() ) {
14781 otherVal = this.values( index ? 0 : 1 );
14782 currentValue = this.values( index );
14783
14784 if ( this.options.values.length === 2 && this.options.range === true ) {
14785 newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
14786 }
14787
14788 newValues[ index ] = newVal;
14789 }
14790
14791 if ( newVal === currentValue ) {
14792 return;
14793 }
14794
14795 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
14796
14797 // A slide can be canceled by returning false from the slide callback
14798 if ( allowed === false ) {
14799 return;
14800 }
14801
14802 if ( this._hasMultipleValues() ) {
14803 this.values( index, newVal );
14804 } else {
14805 this.value( newVal );
14806 }
14807 },
14808
14809 _stop: function( event, index ) {
14810 this._trigger( "stop", event, this._uiHash( index ) );
14811 },
14812
14813 _change: function( event, index ) {
14814 if ( !this._keySliding && !this._mouseSliding ) {
14815
14816 //store the last changed value index for reference when handles overlap
14817 this._lastChangedValue = index;
14818 this._trigger( "change", event, this._uiHash( index ) );
14819 }
14820 },
14821
14822 value: function( newValue ) {
14823 if ( arguments.length ) {
14824 this.options.value = this._trimAlignValue( newValue );
14825 this._refreshValue();
14826 this._change( null, 0 );
14827 return;
14828 }
14829
14830 return this._value();
14831 },
14832
14833 values: function( index, newValue ) {
14834 var vals,
14835 newValues,
14836 i;
14837
14838 if ( arguments.length > 1 ) {
14839 this.options.values[ index ] = this._trimAlignValue( newValue );
14840 this._refreshValue();
14841 this._change( null, index );
14842 return;
14843 }
14844
14845 if ( arguments.length ) {
14846 if ( $.isArray( arguments[ 0 ] ) ) {
14847 vals = this.options.values;
14848 newValues = arguments[ 0 ];
14849 for ( i = 0; i < vals.length; i += 1 ) {
14850 vals[ i ] = this._trimAlignValue( newValues[ i ] );
14851 this._change( null, i );
14852 }
14853 this._refreshValue();
14854 } else {
14855 if ( this._hasMultipleValues() ) {
14856 return this._values( index );
14857 } else {
14858 return this.value();
14859 }
14860 }
14861 } else {
14862 return this._values();
14863 }
14864 },
14865
14866 _setOption: function( key, value ) {
14867 var i,
14868 valsLength = 0;
14869
14870 if ( key === "range" && this.options.range === true ) {
14871 if ( value === "min" ) {
14872 this.options.value = this._values( 0 );
14873 this.options.values = null;
14874 } else if ( value === "max" ) {
14875 this.options.value = this._values( this.options.values.length - 1 );
14876 this.options.values = null;
14877 }
14878 }
14879
14880 if ( $.isArray( this.options.values ) ) {
14881 valsLength = this.options.values.length;
14882 }
14883
14884 this._super( key, value );
14885
14886 switch ( key ) {
14887 case "orientation":
14888 this._detectOrientation();
14889 this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
14890 ._addClass( "ui-slider-" + this.orientation );
14891 this._refreshValue();
14892 if ( this.options.range ) {
14893 this._refreshRange( value );
14894 }
14895
14896 // Reset positioning from previous orientation
14897 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
14898 break;
14899 case "value":
14900 this._animateOff = true;
14901 this._refreshValue();
14902 this._change( null, 0 );
14903 this._animateOff = false;
14904 break;
14905 case "values":
14906 this._animateOff = true;
14907 this._refreshValue();
14908
14909 // Start from the last handle to prevent unreachable handles (#9046)
14910 for ( i = valsLength - 1; i >= 0; i-- ) {
14911 this._change( null, i );
14912 }
14913 this._animateOff = false;
14914 break;
14915 case "step":
14916 case "min":
14917 case "max":
14918 this._animateOff = true;
14919 this._calculateNewMax();
14920 this._refreshValue();
14921 this._animateOff = false;
14922 break;
14923 case "range":
14924 this._animateOff = true;
14925 this._refresh();
14926 this._animateOff = false;
14927 break;
14928 }
14929 },
14930
14931 _setOptionDisabled: function( value ) {
14932 this._super( value );
14933
14934 this._toggleClass( null, "ui-state-disabled", !!value );
14935 },
14936
14937 //internal value getter
14938 // _value() returns value trimmed by min and max, aligned by step
14939 _value: function() {
14940 var val = this.options.value;
14941 val = this._trimAlignValue( val );
14942
14943 return val;
14944 },
14945
14946 //internal values getter
14947 // _values() returns array of values trimmed by min and max, aligned by step
14948 // _values( index ) returns single value trimmed by min and max, aligned by step
14949 _values: function( index ) {
14950 var val,
14951 vals,
14952 i;
14953
14954 if ( arguments.length ) {
14955 val = this.options.values[ index ];
14956 val = this._trimAlignValue( val );
14957
14958 return val;
14959 } else if ( this._hasMultipleValues() ) {
14960
14961 // .slice() creates a copy of the array
14962 // this copy gets trimmed by min and max and then returned
14963 vals = this.options.values.slice();
14964 for ( i = 0; i < vals.length; i += 1 ) {
14965 vals[ i ] = this._trimAlignValue( vals[ i ] );
14966 }
14967
14968 return vals;
14969 } else {
14970 return [];
14971 }
14972 },
14973
14974 // Returns the step-aligned value that val is closest to, between (inclusive) min and max
14975 _trimAlignValue: function( val ) {
14976 if ( val <= this._valueMin() ) {
14977 return this._valueMin();
14978 }
14979 if ( val >= this._valueMax() ) {
14980 return this._valueMax();
14981 }
14982 var step = ( this.options.step > 0 ) ? this.options.step : 1,
14983 valModStep = ( val - this._valueMin() ) % step,
14984 alignValue = val - valModStep;
14985
14986 if ( Math.abs( valModStep ) * 2 >= step ) {
14987 alignValue += ( valModStep > 0 ) ? step : ( -step );
14988 }
14989
14990 // Since JavaScript has problems with large floats, round
14991 // the final value to 5 digits after the decimal point (see #4124)
14992 return parseFloat( alignValue.toFixed( 5 ) );
14993 },
14994
14995 _calculateNewMax: function() {
14996 var max = this.options.max,
14997 min = this._valueMin(),
14998 step = this.options.step,
14999 aboveMin = Math.round( ( max - min ) / step ) * step;
15000 max = aboveMin + min;
15001 if ( max > this.options.max ) {
15002
15003 //If max is not divisible by step, rounding off may increase its value
15004 max -= step;
15005 }
15006 this.max = parseFloat( max.toFixed( this._precision() ) );
15007 },
15008
15009 _precision: function() {
15010 var precision = this._precisionOf( this.options.step );
15011 if ( this.options.min !== null ) {
15012 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15013 }
15014 return precision;
15015 },
15016
15017 _precisionOf: function( num ) {
15018 var str = num.toString(),
15019 decimal = str.indexOf( "." );
15020 return decimal === -1 ? 0 : str.length - decimal - 1;
15021 },
15022
15023 _valueMin: function() {
15024 return this.options.min;
15025 },
15026
15027 _valueMax: function() {
15028 return this.max;
15029 },
15030
15031 _refreshRange: function( orientation ) {
15032 if ( orientation === "vertical" ) {
15033 this.range.css( { "width": "", "left": "" } );
15034 }
15035 if ( orientation === "horizontal" ) {
15036 this.range.css( { "height": "", "bottom": "" } );
15037 }
15038 },
15039
15040 _refreshValue: function() {
15041 var lastValPercent, valPercent, value, valueMin, valueMax,
15042 oRange = this.options.range,
15043 o = this.options,
15044 that = this,
15045 animate = ( !this._animateOff ) ? o.animate : false,
15046 _set = {};
15047
15048 if ( this._hasMultipleValues() ) {
15049 this.handles.each( function( i ) {
15050 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
15051 that._valueMin() ) * 100;
15052 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
15053 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
15054 if ( that.options.range === true ) {
15055 if ( that.orientation === "horizontal" ) {
15056 if ( i === 0 ) {
15057 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15058 left: valPercent + "%"
15059 }, o.animate );
15060 }
15061 if ( i === 1 ) {
15062 that.range[ animate ? "animate" : "css" ]( {
15063 width: ( valPercent - lastValPercent ) + "%"
15064 }, {
15065 queue: false,
15066 duration: o.animate
15067 } );
15068 }
15069 } else {
15070 if ( i === 0 ) {
15071 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15072 bottom: ( valPercent ) + "%"
15073 }, o.animate );
15074 }
15075 if ( i === 1 ) {
15076 that.range[ animate ? "animate" : "css" ]( {
15077 height: ( valPercent - lastValPercent ) + "%"
15078 }, {
15079 queue: false,
15080 duration: o.animate
15081 } );
15082 }
15083 }
15084 }
15085 lastValPercent = valPercent;
15086 } );
15087 } else {
15088 value = this.value();
15089 valueMin = this._valueMin();
15090 valueMax = this._valueMax();
15091 valPercent = ( valueMax !== valueMin ) ?
15092 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
15093 0;
15094 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
15095 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
15096
15097 if ( oRange === "min" && this.orientation === "horizontal" ) {
15098 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15099 width: valPercent + "%"
15100 }, o.animate );
15101 }
15102 if ( oRange === "max" && this.orientation === "horizontal" ) {
15103 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15104 width: ( 100 - valPercent ) + "%"
15105 }, o.animate );
15106 }
15107 if ( oRange === "min" && this.orientation === "vertical" ) {
15108 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15109 height: valPercent + "%"
15110 }, o.animate );
15111 }
15112 if ( oRange === "max" && this.orientation === "vertical" ) {
15113 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
15114 height: ( 100 - valPercent ) + "%"
15115 }, o.animate );
15116 }
15117 }
15118 },
15119
15120 _handleEvents: {
15121 keydown: function( event ) {
15122 var allowed, curVal, newVal, step,
15123 index = $( event.target ).data( "ui-slider-handle-index" );
15124
15125 switch ( event.keyCode ) {
15126 case $.ui.keyCode.HOME:
15127 case $.ui.keyCode.END:
15128 case $.ui.keyCode.PAGE_UP:
15129 case $.ui.keyCode.PAGE_DOWN:
15130 case $.ui.keyCode.UP:
15131 case $.ui.keyCode.RIGHT:
15132 case $.ui.keyCode.DOWN:
15133 case $.ui.keyCode.LEFT:
15134 event.preventDefault();
15135 if ( !this._keySliding ) {
15136 this._keySliding = true;
15137 this._addClass( $( event.target ), null, "ui-state-active" );
15138 allowed = this._start( event, index );
15139 if ( allowed === false ) {
15140 return;
15141 }
15142 }
15143 break;
15144 }
15145
15146 step = this.options.step;
15147 if ( this._hasMultipleValues() ) {
15148 curVal = newVal = this.values( index );
15149 } else {
15150 curVal = newVal = this.value();
15151 }
15152
15153 switch ( event.keyCode ) {
15154 case $.ui.keyCode.HOME:
15155 newVal = this._valueMin();
15156 break;
15157 case $.ui.keyCode.END:
15158 newVal = this._valueMax();
15159 break;
15160 case $.ui.keyCode.PAGE_UP:
15161 newVal = this._trimAlignValue(
15162 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
15163 );
15164 break;
15165 case $.ui.keyCode.PAGE_DOWN:
15166 newVal = this._trimAlignValue(
15167 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
15168 break;
15169 case $.ui.keyCode.UP:
15170 case $.ui.keyCode.RIGHT:
15171 if ( curVal === this._valueMax() ) {
15172 return;
15173 }
15174 newVal = this._trimAlignValue( curVal + step );
15175 break;
15176 case $.ui.keyCode.DOWN:
15177 case $.ui.keyCode.LEFT:
15178 if ( curVal === this._valueMin() ) {
15179 return;
15180 }
15181 newVal = this._trimAlignValue( curVal - step );
15182 break;
15183 }
15184
15185 this._slide( event, index, newVal );
15186 },
15187 keyup: function( event ) {
15188 var index = $( event.target ).data( "ui-slider-handle-index" );
15189
15190 if ( this._keySliding ) {
15191 this._keySliding = false;
15192 this._stop( event, index );
15193 this._change( event, index );
15194 this._removeClass( $( event.target ), null, "ui-state-active" );
15195 }
15196 }
15197 }
15198 } );
15199
15200
15201 /*!
15202 * jQuery UI Sortable 1.12.1
15203 * http://jqueryui.com
15204 *
15205 * Copyright jQuery Foundation and other contributors
15206 * Released under the MIT license.
15207 * http://jquery.org/license
15208 */
15209
15210 //>>label: Sortable
15211 //>>group: Interactions
15212 //>>description: Enables items in a list to be sorted using the mouse.
15213 //>>docs: http://api.jqueryui.com/sortable/
15214 //>>demos: http://jqueryui.com/sortable/
15215 //>>css.structure: ../../themes/base/sortable.css
15216
15217
15218
15219 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
15220 version: "1.12.1",
15221 widgetEventPrefix: "sort",
15222 ready: false,
15223 options: {
15224 appendTo: "parent",
15225 axis: false,
15226 connectWith: false,
15227 containment: false,
15228 cursor: "auto",
15229 cursorAt: false,
15230 dropOnEmpty: true,
15231 forcePlaceholderSize: false,
15232 forceHelperSize: false,
15233 grid: false,
15234 handle: false,
15235 helper: "original",
15236 items: "> *",
15237 opacity: false,
15238 placeholder: false,
15239 revert: false,
15240 scroll: true,
15241 scrollSensitivity: 20,
15242 scrollSpeed: 20,
15243 scope: "default",
15244 tolerance: "intersect",
15245 zIndex: 1000,
15246
15247 // Callbacks
15248 activate: null,
15249 beforeStop: null,
15250 change: null,
15251 deactivate: null,
15252 out: null,
15253 over: null,
15254 receive: null,
15255 remove: null,
15256 sort: null,
15257 start: null,
15258 stop: null,
15259 update: null
15260 },
15261
15262 _isOverAxis: function( x, reference, size ) {
15263 return ( x >= reference ) && ( x < ( reference + size ) );
15264 },
15265
15266 _isFloating: function( item ) {
15267 return ( /left|right/ ).test( item.css( "float" ) ) ||
15268 ( /inline|table-cell/ ).test( item.css( "display" ) );
15269 },
15270
15271 _create: function() {
15272 this.containerCache = {};
15273 this._addClass( "ui-sortable" );
15274
15275 //Get the items
15276 this.refresh();
15277
15278 //Let's determine the parent's offset
15279 this.offset = this.element.offset();
15280
15281 //Initialize mouse events for interaction
15282 this._mouseInit();
15283
15284 this._setHandleClassName();
15285
15286 //We're ready to go
15287 this.ready = true;
15288
15289 },
15290
15291 _setOption: function( key, value ) {
15292 this._super( key, value );
15293
15294 if ( key === "handle" ) {
15295 this._setHandleClassName();
15296 }
15297 },
15298
15299 _setHandleClassName: function() {
15300 var that = this;
15301 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
15302 $.each( this.items, function() {
15303 that._addClass(
15304 this.instance.options.handle ?
15305 this.item.find( this.instance.options.handle ) :
15306 this.item,
15307 "ui-sortable-handle"
15308 );
15309 } );
15310 },
15311
15312 _destroy: function() {
15313 this._mouseDestroy();
15314
15315 for ( var i = this.items.length - 1; i >= 0; i-- ) {
15316 this.items[ i ].item.removeData( this.widgetName + "-item" );
15317 }
15318
15319 return this;
15320 },
15321
15322 _mouseCapture: function( event, overrideHandle ) {
15323 var currentItem = null,
15324 validHandle = false,
15325 that = this;
15326
15327 if ( this.reverting ) {
15328 return false;
15329 }
15330
15331 if ( this.options.disabled || this.options.type === "static" ) {
15332 return false;
15333 }
15334
15335 //We have to refresh the items data once first
15336 this._refreshItems( event );
15337
15338 //Find out if the clicked node (or one of its parents) is a actual item in this.items
15339 $( event.target ).parents().each( function() {
15340 if ( $.data( this, that.widgetName + "-item" ) === that ) {
15341 currentItem = $( this );
15342 return false;
15343 }
15344 } );
15345 if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
15346 currentItem = $( event.target );
15347 }
15348
15349 if ( !currentItem ) {
15350 return false;
15351 }
15352 if ( this.options.handle && !overrideHandle ) {
15353 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
15354 if ( this === event.target ) {
15355 validHandle = true;
15356 }
15357 } );
15358 if ( !validHandle ) {
15359 return false;
15360 }
15361 }
15362
15363 this.currentItem = currentItem;
15364 this._removeCurrentsFromItems();
15365 return true;
15366
15367 },
15368
15369 _mouseStart: function( event, overrideHandle, noActivation ) {
15370
15371 var i, body,
15372 o = this.options;
15373
15374 this.currentContainer = this;
15375
15376 //We only need to call refreshPositions, because the refreshItems call has been moved to
15377 // mouseCapture
15378 this.refreshPositions();
15379
15380 //Create and append the visible helper
15381 this.helper = this._createHelper( event );
15382
15383 //Cache the helper size
15384 this._cacheHelperProportions();
15385
15386 /*
15387 * - Position generation -
15388 * This block generates everything position related - it's the core of draggables.
15389 */
15390
15391 //Cache the margins of the original element
15392 this._cacheMargins();
15393
15394 //Get the next scrolling parent
15395 this.scrollParent = this.helper.scrollParent();
15396
15397 //The element's absolute position on the page minus margins
15398 this.offset = this.currentItem.offset();
15399 this.offset = {
15400 top: this.offset.top - this.margins.top,
15401 left: this.offset.left - this.margins.left
15402 };
15403
15404 $.extend( this.offset, {
15405 click: { //Where the click happened, relative to the element
15406 left: event.pageX - this.offset.left,
15407 top: event.pageY - this.offset.top
15408 },
15409 parent: this._getParentOffset(),
15410
15411 // This is a relative to absolute position minus the actual position calculation -
15412 // only used for relative positioned helper
15413 relative: this._getRelativeOffset()
15414 } );
15415
15416 // Only after we got the offset, we can change the helper's position to absolute
15417 // TODO: Still need to figure out a way to make relative sorting possible
15418 this.helper.css( "position", "absolute" );
15419 this.cssPosition = this.helper.css( "position" );
15420
15421 //Generate the original position
15422 this.originalPosition = this._generatePosition( event );
15423 this.originalPageX = event.pageX;
15424 this.originalPageY = event.pageY;
15425
15426 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
15427 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
15428
15429 //Cache the former DOM position
15430 this.domPosition = {
15431 prev: this.currentItem.prev()[ 0 ],
15432 parent: this.currentItem.parent()[ 0 ]
15433 };
15434
15435 // If the helper is not the original, hide the original so it's not playing any role during
15436 // the drag, won't cause anything bad this way
15437 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
15438 this.currentItem.hide();
15439 }
15440
15441 //Create the placeholder
15442 this._createPlaceholder();
15443
15444 //Set a containment if given in the options
15445 if ( o.containment ) {
15446 this._setContainment();
15447 }
15448
15449 if ( o.cursor && o.cursor !== "auto" ) { // cursor option
15450 body = this.document.find( "body" );
15451
15452 // Support: IE
15453 this.storedCursor = body.css( "cursor" );
15454 body.css( "cursor", o.cursor );
15455
15456 this.storedStylesheet =
15457 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
15458 }
15459
15460 if ( o.opacity ) { // opacity option
15461 if ( this.helper.css( "opacity" ) ) {
15462 this._storedOpacity = this.helper.css( "opacity" );
15463 }
15464 this.helper.css( "opacity", o.opacity );
15465 }
15466
15467 if ( o.zIndex ) { // zIndex option
15468 if ( this.helper.css( "zIndex" ) ) {
15469 this._storedZIndex = this.helper.css( "zIndex" );
15470 }
15471 this.helper.css( "zIndex", o.zIndex );
15472 }
15473
15474 //Prepare scrolling
15475 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
15476 this.scrollParent[ 0 ].tagName !== "HTML" ) {
15477 this.overflowOffset = this.scrollParent.offset();
15478 }
15479
15480 //Call callbacks
15481 this._trigger( "start", event, this._uiHash() );
15482
15483 //Recache the helper size
15484 if ( !this._preserveHelperProportions ) {
15485 this._cacheHelperProportions();
15486 }
15487
15488 //Post "activate" events to possible containers
15489 if ( !noActivation ) {
15490 for ( i = this.containers.length - 1; i >= 0; i-- ) {
15491 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
15492 }
15493 }
15494
15495 //Prepare possible droppables
15496 if ( $.ui.ddmanager ) {
15497 $.ui.ddmanager.current = this;
15498 }
15499
15500 if ( $.ui.ddmanager && !o.dropBehaviour ) {
15501 $.ui.ddmanager.prepareOffsets( this, event );
15502 }
15503
15504 this.dragging = true;
15505
15506 this._addClass( this.helper, "ui-sortable-helper" );
15507
15508 // Execute the drag once - this causes the helper not to be visiblebefore getting its
15509 // correct position
15510 this._mouseDrag( event );
15511 return true;
15512
15513 },
15514
15515 _mouseDrag: function( event ) {
15516 var i, item, itemElement, intersection,
15517 o = this.options,
15518 scrolled = false;
15519
15520 //Compute the helpers position
15521 this.position = this._generatePosition( event );
15522 this.positionAbs = this._convertPositionTo( "absolute" );
15523
15524 if ( !this.lastPositionAbs ) {
15525 this.lastPositionAbs = this.positionAbs;
15526 }
15527
15528 //Do scrolling
15529 if ( this.options.scroll ) {
15530 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
15531 this.scrollParent[ 0 ].tagName !== "HTML" ) {
15532
15533 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
15534 event.pageY < o.scrollSensitivity ) {
15535 this.scrollParent[ 0 ].scrollTop =
15536 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
15537 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
15538 this.scrollParent[ 0 ].scrollTop =
15539 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
15540 }
15541
15542 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
15543 event.pageX < o.scrollSensitivity ) {
15544 this.scrollParent[ 0 ].scrollLeft = scrolled =
15545 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
15546 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
15547 this.scrollParent[ 0 ].scrollLeft = scrolled =
15548 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
15549 }
15550
15551 } else {
15552
15553 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
15554 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
15555 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
15556 o.scrollSensitivity ) {
15557 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
15558 }
15559
15560 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
15561 scrolled = this.document.scrollLeft(
15562 this.document.scrollLeft() - o.scrollSpeed
15563 );
15564 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
15565 o.scrollSensitivity ) {
15566 scrolled = this.document.scrollLeft(
15567 this.document.scrollLeft() + o.scrollSpeed
15568 );
15569 }
15570
15571 }
15572
15573 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
15574 $.ui.ddmanager.prepareOffsets( this, event );
15575 }
15576 }
15577
15578 //Regenerate the absolute position used for position checks
15579 this.positionAbs = this._convertPositionTo( "absolute" );
15580
15581 //Set the helper position
15582 if ( !this.options.axis || this.options.axis !== "y" ) {
15583 this.helper[ 0 ].style.left = this.position.left + "px";
15584 }
15585 if ( !this.options.axis || this.options.axis !== "x" ) {
15586 this.helper[ 0 ].style.top = this.position.top + "px";
15587 }
15588
15589 //Rearrange
15590 for ( i = this.items.length - 1; i >= 0; i-- ) {
15591
15592 //Cache variables and intersection, continue if no intersection
15593 item = this.items[ i ];
15594 itemElement = item.item[ 0 ];
15595 intersection = this._intersectsWithPointer( item );
15596 if ( !intersection ) {
15597 continue;
15598 }
15599
15600 // Only put the placeholder inside the current Container, skip all
15601 // items from other containers. This works because when moving
15602 // an item from one container to another the
15603 // currentContainer is switched before the placeholder is moved.
15604 //
15605 // Without this, moving items in "sub-sortables" can cause
15606 // the placeholder to jitter between the outer and inner container.
15607 if ( item.instance !== this.currentContainer ) {
15608 continue;
15609 }
15610
15611 // Cannot intersect with itself
15612 // no useless actions that have been done before
15613 // no action if the item moved is the parent of the item checked
15614 if ( itemElement !== this.currentItem[ 0 ] &&
15615 this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
15616 !$.contains( this.placeholder[ 0 ], itemElement ) &&
15617 ( this.options.type === "semi-dynamic" ?
15618 !$.contains( this.element[ 0 ], itemElement ) :
15619 true
15620 )
15621 ) {
15622
15623 this.direction = intersection === 1 ? "down" : "up";
15624
15625 if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
15626 this._rearrange( event, item );
15627 } else {
15628 break;
15629 }
15630
15631 this._trigger( "change", event, this._uiHash() );
15632 break;
15633 }
15634 }
15635
15636 //Post events to containers
15637 this._contactContainers( event );
15638
15639 //Interconnect with droppables
15640 if ( $.ui.ddmanager ) {
15641 $.ui.ddmanager.drag( this, event );
15642 }
15643
15644 //Call callbacks
15645 this._trigger( "sort", event, this._uiHash() );
15646
15647 this.lastPositionAbs = this.positionAbs;
15648 return false;
15649
15650 },
15651
15652 _mouseStop: function( event, noPropagation ) {
15653
15654 if ( !event ) {
15655 return;
15656 }
15657
15658 //If we are using droppables, inform the manager about the drop
15659 if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
15660 $.ui.ddmanager.drop( this, event );
15661 }
15662
15663 if ( this.options.revert ) {
15664 var that = this,
15665 cur = this.placeholder.offset(),
15666 axis = this.options.axis,
15667 animation = {};
15668
15669 if ( !axis || axis === "x" ) {
15670 animation.left = cur.left - this.offset.parent.left - this.margins.left +
15671 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
15672 0 :
15673 this.offsetParent[ 0 ].scrollLeft
15674 );
15675 }
15676 if ( !axis || axis === "y" ) {
15677 animation.top = cur.top - this.offset.parent.top - this.margins.top +
15678 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
15679 0 :
15680 this.offsetParent[ 0 ].scrollTop
15681 );
15682 }
15683 this.reverting = true;
15684 $( this.helper ).animate(
15685 animation,
15686 parseInt( this.options.revert, 10 ) || 500,
15687 function() {
15688 that._clear( event );
15689 }
15690 );
15691 } else {
15692 this._clear( event, noPropagation );
15693 }
15694
15695 return false;
15696
15697 },
15698
15699 cancel: function() {
15700
15701 if ( this.dragging ) {
15702
15703 this._mouseUp( new $.Event( "mouseup", { target: null } ) );
15704
15705 if ( this.options.helper === "original" ) {
15706 this.currentItem.css( this._storedCSS );
15707 this._removeClass( this.currentItem, "ui-sortable-helper" );
15708 } else {
15709 this.currentItem.show();
15710 }
15711
15712 //Post deactivating events to containers
15713 for ( var i = this.containers.length - 1; i >= 0; i-- ) {
15714 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
15715 if ( this.containers[ i ].containerCache.over ) {
15716 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
15717 this.containers[ i ].containerCache.over = 0;
15718 }
15719 }
15720
15721 }
15722
15723 if ( this.placeholder ) {
15724
15725 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
15726 // it unbinds ALL events from the original node!
15727 if ( this.placeholder[ 0 ].parentNode ) {
15728 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
15729 }
15730 if ( this.options.helper !== "original" && this.helper &&
15731 this.helper[ 0 ].parentNode ) {
15732 this.helper.remove();
15733 }
15734
15735 $.extend( this, {
15736 helper: null,
15737 dragging: false,
15738 reverting: false,
15739 _noFinalSort: null
15740 } );
15741
15742 if ( this.domPosition.prev ) {
15743 $( this.domPosition.prev ).after( this.currentItem );
15744 } else {
15745 $( this.domPosition.parent ).prepend( this.currentItem );
15746 }
15747 }
15748
15749 return this;
15750
15751 },
15752
15753 serialize: function( o ) {
15754
15755 var items = this._getItemsAsjQuery( o && o.connected ),
15756 str = [];
15757 o = o || {};
15758
15759 $( items ).each( function() {
15760 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
15761 .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
15762 if ( res ) {
15763 str.push(
15764 ( o.key || res[ 1 ] + "[]" ) +
15765 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
15766 }
15767 } );
15768
15769 if ( !str.length && o.key ) {
15770 str.push( o.key + "=" );
15771 }
15772
15773 return str.join( "&" );
15774
15775 },
15776
15777 toArray: function( o ) {
15778
15779 var items = this._getItemsAsjQuery( o && o.connected ),
15780 ret = [];
15781
15782 o = o || {};
15783
15784 items.each( function() {
15785 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
15786 } );
15787 return ret;
15788
15789 },
15790
15791 /* Be careful with the following core functions */
15792 _intersectsWith: function( item ) {
15793
15794 var x1 = this.positionAbs.left,
15795 x2 = x1 + this.helperProportions.width,
15796 y1 = this.positionAbs.top,
15797 y2 = y1 + this.helperProportions.height,
15798 l = item.left,
15799 r = l + item.width,
15800 t = item.top,
15801 b = t + item.height,
15802 dyClick = this.offset.click.top,
15803 dxClick = this.offset.click.left,
15804 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
15805 ( y1 + dyClick ) < b ),
15806 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
15807 ( x1 + dxClick ) < r ),
15808 isOverElement = isOverElementHeight && isOverElementWidth;
15809
15810 if ( this.options.tolerance === "pointer" ||
15811 this.options.forcePointerForContainers ||
15812 ( this.options.tolerance !== "pointer" &&
15813 this.helperProportions[ this.floating ? "width" : "height" ] >
15814 item[ this.floating ? "width" : "height" ] )
15815 ) {
15816 return isOverElement;
15817 } else {
15818
15819 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
15820 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
15821 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
15822 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
15823
15824 }
15825 },
15826
15827 _intersectsWithPointer: function( item ) {
15828 var verticalDirection, horizontalDirection,
15829 isOverElementHeight = ( this.options.axis === "x" ) ||
15830 this._isOverAxis(
15831 this.positionAbs.top + this.offset.click.top, item.top, item.height ),
15832 isOverElementWidth = ( this.options.axis === "y" ) ||
15833 this._isOverAxis(
15834 this.positionAbs.left + this.offset.click.left, item.left, item.width ),
15835 isOverElement = isOverElementHeight && isOverElementWidth;
15836
15837 if ( !isOverElement ) {
15838 return false;
15839 }
15840
15841 verticalDirection = this._getDragVerticalDirection();
15842 horizontalDirection = this._getDragHorizontalDirection();
15843
15844 return this.floating ?
15845 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
15846 : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
15847
15848 },
15849
15850 _intersectsWithSides: function( item ) {
15851
15852 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
15853 this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
15854 isOverRightHalf = this._isOverAxis( this.positionAbs.left +
15855 this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
15856 verticalDirection = this._getDragVerticalDirection(),
15857 horizontalDirection = this._getDragHorizontalDirection();
15858
15859 if ( this.floating && horizontalDirection ) {
15860 return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
15861 ( horizontalDirection === "left" && !isOverRightHalf ) );
15862 } else {
15863 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
15864 ( verticalDirection === "up" && !isOverBottomHalf ) );
15865 }
15866
15867 },
15868
15869 _getDragVerticalDirection: function() {
15870 var delta = this.positionAbs.top - this.lastPositionAbs.top;
15871 return delta !== 0 && ( delta > 0 ? "down" : "up" );
15872 },
15873
15874 _getDragHorizontalDirection: function() {
15875 var delta = this.positionAbs.left - this.lastPositionAbs.left;
15876 return delta !== 0 && ( delta > 0 ? "right" : "left" );
15877 },
15878
15879 refresh: function( event ) {
15880 this._refreshItems( event );
15881 this._setHandleClassName();
15882 this.refreshPositions();
15883 return this;
15884 },
15885
15886 _connectWith: function() {
15887 var options = this.options;
15888 return options.connectWith.constructor === String ?
15889 [ options.connectWith ] :
15890 options.connectWith;
15891 },
15892
15893 _getItemsAsjQuery: function( connected ) {
15894
15895 var i, j, cur, inst,
15896 items = [],
15897 queries = [],
15898 connectWith = this._connectWith();
15899
15900 if ( connectWith && connected ) {
15901 for ( i = connectWith.length - 1; i >= 0; i-- ) {
15902 cur = $( connectWith[ i ], this.document[ 0 ] );
15903 for ( j = cur.length - 1; j >= 0; j-- ) {
15904 inst = $.data( cur[ j ], this.widgetFullName );
15905 if ( inst && inst !== this && !inst.options.disabled ) {
15906 queries.push( [ $.isFunction( inst.options.items ) ?
15907 inst.options.items.call( inst.element ) :
15908 $( inst.options.items, inst.element )
15909 .not( ".ui-sortable-helper" )
15910 .not( ".ui-sortable-placeholder" ), inst ] );
15911 }
15912 }
15913 }
15914 }
15915
15916 queries.push( [ $.isFunction( this.options.items ) ?
15917 this.options.items
15918 .call( this.element, null, { options: this.options, item: this.currentItem } ) :
15919 $( this.options.items, this.element )
15920 .not( ".ui-sortable-helper" )
15921 .not( ".ui-sortable-placeholder" ), this ] );
15922
15923 function addItems() {
15924 items.push( this );
15925 }
15926 for ( i = queries.length - 1; i >= 0; i-- ) {
15927 queries[ i ][ 0 ].each( addItems );
15928 }
15929
15930 return $( items );
15931
15932 },
15933
15934 _removeCurrentsFromItems: function() {
15935
15936 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
15937
15938 this.items = $.grep( this.items, function( item ) {
15939 for ( var j = 0; j < list.length; j++ ) {
15940 if ( list[ j ] === item.item[ 0 ] ) {
15941 return false;
15942 }
15943 }
15944 return true;
15945 } );
15946
15947 },
15948
15949 _refreshItems: function( event ) {
15950
15951 this.items = [];
15952 this.containers = [ this ];
15953
15954 var i, j, cur, inst, targetData, _queries, item, queriesLength,
15955 items = this.items,
15956 queries = [ [ $.isFunction( this.options.items ) ?
15957 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
15958 $( this.options.items, this.element ), this ] ],
15959 connectWith = this._connectWith();
15960
15961 //Shouldn't be run the first time through due to massive slow-down
15962 if ( connectWith && this.ready ) {
15963 for ( i = connectWith.length - 1; i >= 0; i-- ) {
15964 cur = $( connectWith[ i ], this.document[ 0 ] );
15965 for ( j = cur.length - 1; j >= 0; j-- ) {
15966 inst = $.data( cur[ j ], this.widgetFullName );
15967 if ( inst && inst !== this && !inst.options.disabled ) {
15968 queries.push( [ $.isFunction( inst.options.items ) ?
15969 inst.options.items
15970 .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
15971 $( inst.options.items, inst.element ), inst ] );
15972 this.containers.push( inst );
15973 }
15974 }
15975 }
15976 }
15977
15978 for ( i = queries.length - 1; i >= 0; i-- ) {
15979 targetData = queries[ i ][ 1 ];
15980 _queries = queries[ i ][ 0 ];
15981
15982 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
15983 item = $( _queries[ j ] );
15984
15985 // Data for target checking (mouse manager)
15986 item.data( this.widgetName + "-item", targetData );
15987
15988 items.push( {
15989 item: item,
15990 instance: targetData,
15991 width: 0, height: 0,
15992 left: 0, top: 0
15993 } );
15994 }
15995 }
15996
15997 },
15998
15999 refreshPositions: function( fast ) {
16000
16001 // Determine whether items are being displayed horizontally
16002 this.floating = this.items.length ?
16003 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
16004 false;
16005
16006 //This has to be redone because due to the item being moved out/into the offsetParent,
16007 // the offsetParent's position will change
16008 if ( this.offsetParent && this.helper ) {
16009 this.offset.parent = this._getParentOffset();
16010 }
16011
16012 var i, item, t, p;
16013
16014 for ( i = this.items.length - 1; i >= 0; i-- ) {
16015 item = this.items[ i ];
16016
16017 //We ignore calculating positions of all connected containers when we're not over them
16018 if ( item.instance !== this.currentContainer && this.currentContainer &&
16019 item.item[ 0 ] !== this.currentItem[ 0 ] ) {
16020 continue;
16021 }
16022
16023 t = this.options.toleranceElement ?
16024 $( this.options.toleranceElement, item.item ) :
16025 item.item;
16026
16027 if ( !fast ) {
16028 item.width = t.outerWidth();
16029 item.height = t.outerHeight();
16030 }
16031
16032 p = t.offset();
16033 item.left = p.left;
16034 item.top = p.top;
16035 }
16036
16037 if ( this.options.custom && this.options.custom.refreshContainers ) {
16038 this.options.custom.refreshContainers.call( this );
16039 } else {
16040 for ( i = this.containers.length - 1; i >= 0; i-- ) {
16041 p = this.containers[ i ].element.offset();
16042 this.containers[ i ].containerCache.left = p.left;
16043 this.containers[ i ].containerCache.top = p.top;
16044 this.containers[ i ].containerCache.width =
16045 this.containers[ i ].element.outerWidth();
16046 this.containers[ i ].containerCache.height =
16047 this.containers[ i ].element.outerHeight();
16048 }
16049 }
16050
16051 return this;
16052 },
16053
16054 _createPlaceholder: function( that ) {
16055 that = that || this;
16056 var className,
16057 o = that.options;
16058
16059 if ( !o.placeholder || o.placeholder.constructor === String ) {
16060 className = o.placeholder;
16061 o.placeholder = {
16062 element: function() {
16063
16064 var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
16065 element = $( "<" + nodeName + ">", that.document[ 0 ] );
16066
16067 that._addClass( element, "ui-sortable-placeholder",
16068 className || that.currentItem[ 0 ].className )
16069 ._removeClass( element, "ui-sortable-helper" );
16070
16071 if ( nodeName === "tbody" ) {
16072 that._createTrPlaceholder(
16073 that.currentItem.find( "tr" ).eq( 0 ),
16074 $( "<tr>", that.document[ 0 ] ).appendTo( element )
16075 );
16076 } else if ( nodeName === "tr" ) {
16077 that._createTrPlaceholder( that.currentItem, element );
16078 } else if ( nodeName === "img" ) {
16079 element.attr( "src", that.currentItem.attr( "src" ) );
16080 }
16081
16082 if ( !className ) {
16083 element.css( "visibility", "hidden" );
16084 }
16085
16086 return element;
16087 },
16088 update: function( container, p ) {
16089
16090 // 1. If a className is set as 'placeholder option, we don't force sizes -
16091 // the class is responsible for that
16092 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
16093 // class name is specified
16094 if ( className && !o.forcePlaceholderSize ) {
16095 return;
16096 }
16097
16098 //If the element doesn't have a actual height by itself (without styles coming
16099 // from a stylesheet), it receives the inline height from the dragged item
16100 if ( !p.height() ) {
16101 p.height(
16102 that.currentItem.innerHeight() -
16103 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
16104 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
16105 }
16106 if ( !p.width() ) {
16107 p.width(
16108 that.currentItem.innerWidth() -
16109 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
16110 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
16111 }
16112 }
16113 };
16114 }
16115
16116 //Create the placeholder
16117 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
16118
16119 //Append it after the actual current item
16120 that.currentItem.after( that.placeholder );
16121
16122 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
16123 o.placeholder.update( that, that.placeholder );
16124
16125 },
16126
16127 _createTrPlaceholder: function( sourceTr, targetTr ) {
16128 var that = this;
16129
16130 sourceTr.children().each( function() {
16131 $( "<td>&#160;</td>", that.document[ 0 ] )
16132 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
16133 .appendTo( targetTr );
16134 } );
16135 },
16136
16137 _contactContainers: function( event ) {
16138 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
16139 floating, axis,
16140 innermostContainer = null,
16141 innermostIndex = null;
16142
16143 // Get innermost container that intersects with item
16144 for ( i = this.containers.length - 1; i >= 0; i-- ) {
16145
16146 // Never consider a container that's located within the item itself
16147 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
16148 continue;
16149 }
16150
16151 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
16152
16153 // If we've already found a container and it's more "inner" than this, then continue
16154 if ( innermostContainer &&
16155 $.contains(
16156 this.containers[ i ].element[ 0 ],
16157 innermostContainer.element[ 0 ] ) ) {
16158 continue;
16159 }
16160
16161 innermostContainer = this.containers[ i ];
16162 innermostIndex = i;
16163
16164 } else {
16165
16166 // container doesn't intersect. trigger "out" event if necessary
16167 if ( this.containers[ i ].containerCache.over ) {
16168 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
16169 this.containers[ i ].containerCache.over = 0;
16170 }
16171 }
16172
16173 }
16174
16175 // If no intersecting containers found, return
16176 if ( !innermostContainer ) {
16177 return;
16178 }
16179
16180 // Move the item into the container if it's not there already
16181 if ( this.containers.length === 1 ) {
16182 if ( !this.containers[ innermostIndex ].containerCache.over ) {
16183 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
16184 this.containers[ innermostIndex ].containerCache.over = 1;
16185 }
16186 } else {
16187
16188 // When entering a new container, we will find the item with the least distance and
16189 // append our item near it
16190 dist = 10000;
16191 itemWithLeastDistance = null;
16192 floating = innermostContainer.floating || this._isFloating( this.currentItem );
16193 posProperty = floating ? "left" : "top";
16194 sizeProperty = floating ? "width" : "height";
16195 axis = floating ? "pageX" : "pageY";
16196
16197 for ( j = this.items.length - 1; j >= 0; j-- ) {
16198 if ( !$.contains(
16199 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
16200 ) {
16201 continue;
16202 }
16203 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
16204 continue;
16205 }
16206
16207 cur = this.items[ j ].item.offset()[ posProperty ];
16208 nearBottom = false;
16209 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
16210 nearBottom = true;
16211 }
16212
16213 if ( Math.abs( event[ axis ] - cur ) < dist ) {
16214 dist = Math.abs( event[ axis ] - cur );
16215 itemWithLeastDistance = this.items[ j ];
16216 this.direction = nearBottom ? "up" : "down";
16217 }
16218 }
16219
16220 //Check if dropOnEmpty is enabled
16221 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
16222 return;
16223 }
16224
16225 if ( this.currentContainer === this.containers[ innermostIndex ] ) {
16226 if ( !this.currentContainer.containerCache.over ) {
16227 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
16228 this.currentContainer.containerCache.over = 1;
16229 }
16230 return;
16231 }
16232
16233 itemWithLeastDistance ?
16234 this._rearrange( event, itemWithLeastDistance, null, true ) :
16235 this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
16236 this._trigger( "change", event, this._uiHash() );
16237 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
16238 this.currentContainer = this.containers[ innermostIndex ];
16239
16240 //Update the placeholder
16241 this.options.placeholder.update( this.currentContainer, this.placeholder );
16242
16243 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
16244 this.containers[ innermostIndex ].containerCache.over = 1;
16245 }
16246
16247 },
16248
16249 _createHelper: function( event ) {
16250
16251 var o = this.options,
16252 helper = $.isFunction( o.helper ) ?
16253 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
16254 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
16255
16256 //Add the helper to the DOM if that didn't happen already
16257 if ( !helper.parents( "body" ).length ) {
16258 $( o.appendTo !== "parent" ?
16259 o.appendTo :
16260 this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
16261 }
16262
16263 if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
16264 this._storedCSS = {
16265 width: this.currentItem[ 0 ].style.width,
16266 height: this.currentItem[ 0 ].style.height,
16267 position: this.currentItem.css( "position" ),
16268 top: this.currentItem.css( "top" ),
16269 left: this.currentItem.css( "left" )
16270 };
16271 }
16272
16273 if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
16274 helper.width( this.currentItem.width() );
16275 }
16276 if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
16277 helper.height( this.currentItem.height() );
16278 }
16279
16280 return helper;
16281
16282 },
16283
16284 _adjustOffsetFromHelper: function( obj ) {
16285 if ( typeof obj === "string" ) {
16286 obj = obj.split( " " );
16287 }
16288 if ( $.isArray( obj ) ) {
16289 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
16290 }
16291 if ( "left" in obj ) {
16292 this.offset.click.left = obj.left + this.margins.left;
16293 }
16294 if ( "right" in obj ) {
16295 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
16296 }
16297 if ( "top" in obj ) {
16298 this.offset.click.top = obj.top + this.margins.top;
16299 }
16300 if ( "bottom" in obj ) {
16301 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
16302 }
16303 },
16304
16305 _getParentOffset: function() {
16306
16307 //Get the offsetParent and cache its position
16308 this.offsetParent = this.helper.offsetParent();
16309 var po = this.offsetParent.offset();
16310
16311 // This is a special case where we need to modify a offset calculated on start, since the
16312 // following happened:
16313 // 1. The position of the helper is absolute, so it's position is calculated based on the
16314 // next positioned parent
16315 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
16316 // the document, which means that the scroll is included in the initial calculation of the
16317 // offset of the parent, and never recalculated upon drag
16318 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16319 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
16320 po.left += this.scrollParent.scrollLeft();
16321 po.top += this.scrollParent.scrollTop();
16322 }
16323
16324 // This needs to be actually done for all browsers, since pageX/pageY includes this
16325 // information with an ugly IE fix
16326 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
16327 ( this.offsetParent[ 0 ].tagName &&
16328 this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
16329 po = { top: 0, left: 0 };
16330 }
16331
16332 return {
16333 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
16334 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
16335 };
16336
16337 },
16338
16339 _getRelativeOffset: function() {
16340
16341 if ( this.cssPosition === "relative" ) {
16342 var p = this.currentItem.position();
16343 return {
16344 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
16345 this.scrollParent.scrollTop(),
16346 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
16347 this.scrollParent.scrollLeft()
16348 };
16349 } else {
16350 return { top: 0, left: 0 };
16351 }
16352
16353 },
16354
16355 _cacheMargins: function() {
16356 this.margins = {
16357 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
16358 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
16359 };
16360 },
16361
16362 _cacheHelperProportions: function() {
16363 this.helperProportions = {
16364 width: this.helper.outerWidth(),
16365 height: this.helper.outerHeight()
16366 };
16367 },
16368
16369 _setContainment: function() {
16370
16371 var ce, co, over,
16372 o = this.options;
16373 if ( o.containment === "parent" ) {
16374 o.containment = this.helper[ 0 ].parentNode;
16375 }
16376 if ( o.containment === "document" || o.containment === "window" ) {
16377 this.containment = [
16378 0 - this.offset.relative.left - this.offset.parent.left,
16379 0 - this.offset.relative.top - this.offset.parent.top,
16380 o.containment === "document" ?
16381 this.document.width() :
16382 this.window.width() - this.helperProportions.width - this.margins.left,
16383 ( o.containment === "document" ?
16384 ( this.document.height() || document.body.parentNode.scrollHeight ) :
16385 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
16386 ) - this.helperProportions.height - this.margins.top
16387 ];
16388 }
16389
16390 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
16391 ce = $( o.containment )[ 0 ];
16392 co = $( o.containment ).offset();
16393 over = ( $( ce ).css( "overflow" ) !== "hidden" );
16394
16395 this.containment = [
16396 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
16397 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
16398 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
16399 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
16400 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
16401 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
16402 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
16403 this.helperProportions.width - this.margins.left,
16404 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
16405 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
16406 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
16407 this.helperProportions.height - this.margins.top
16408 ];
16409 }
16410
16411 },
16412
16413 _convertPositionTo: function( d, pos ) {
16414
16415 if ( !pos ) {
16416 pos = this.position;
16417 }
16418 var mod = d === "absolute" ? 1 : -1,
16419 scroll = this.cssPosition === "absolute" &&
16420 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16421 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
16422 this.offsetParent :
16423 this.scrollParent,
16424 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
16425
16426 return {
16427 top: (
16428
16429 // The absolute mouse position
16430 pos.top +
16431
16432 // Only for relative positioned nodes: Relative offset from element to offset parent
16433 this.offset.relative.top * mod +
16434
16435 // The offsetParent's offset without borders (offset + border)
16436 this.offset.parent.top * mod -
16437 ( ( this.cssPosition === "fixed" ?
16438 -this.scrollParent.scrollTop() :
16439 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
16440 ),
16441 left: (
16442
16443 // The absolute mouse position
16444 pos.left +
16445
16446 // Only for relative positioned nodes: Relative offset from element to offset parent
16447 this.offset.relative.left * mod +
16448
16449 // The offsetParent's offset without borders (offset + border)
16450 this.offset.parent.left * mod -
16451 ( ( this.cssPosition === "fixed" ?
16452 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
16453 scroll.scrollLeft() ) * mod )
16454 )
16455 };
16456
16457 },
16458
16459 _generatePosition: function( event ) {
16460
16461 var top, left,
16462 o = this.options,
16463 pageX = event.pageX,
16464 pageY = event.pageY,
16465 scroll = this.cssPosition === "absolute" &&
16466 !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16467 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
16468 this.offsetParent :
16469 this.scrollParent,
16470 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
16471
16472 // This is another very weird special case that only happens for relative elements:
16473 // 1. If the css position is relative
16474 // 2. and the scroll parent is the document or similar to the offset parent
16475 // we have to refresh the relative offset during the scroll so there are no jumps
16476 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
16477 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
16478 this.offset.relative = this._getRelativeOffset();
16479 }
16480
16481 /*
16482 * - Position constraining -
16483 * Constrain the position to a mix of grid, containment.
16484 */
16485
16486 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
16487
16488 if ( this.containment ) {
16489 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
16490 pageX = this.containment[ 0 ] + this.offset.click.left;
16491 }
16492 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
16493 pageY = this.containment[ 1 ] + this.offset.click.top;
16494 }
16495 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
16496 pageX = this.containment[ 2 ] + this.offset.click.left;
16497 }
16498 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
16499 pageY = this.containment[ 3 ] + this.offset.click.top;
16500 }
16501 }
16502
16503 if ( o.grid ) {
16504 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
16505 o.grid[ 1 ] ) * o.grid[ 1 ];
16506 pageY = this.containment ?
16507 ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
16508 top - this.offset.click.top <= this.containment[ 3 ] ) ?
16509 top :
16510 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
16511 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
16512 top;
16513
16514 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
16515 o.grid[ 0 ] ) * o.grid[ 0 ];
16516 pageX = this.containment ?
16517 ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
16518 left - this.offset.click.left <= this.containment[ 2 ] ) ?
16519 left :
16520 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
16521 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
16522 left;
16523 }
16524
16525 }
16526
16527 return {
16528 top: (
16529
16530 // The absolute mouse position
16531 pageY -
16532
16533 // Click offset (relative to the element)
16534 this.offset.click.top -
16535
16536 // Only for relative positioned nodes: Relative offset from element to offset parent
16537 this.offset.relative.top -
16538
16539 // The offsetParent's offset without borders (offset + border)
16540 this.offset.parent.top +
16541 ( ( this.cssPosition === "fixed" ?
16542 -this.scrollParent.scrollTop() :
16543 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
16544 ),
16545 left: (
16546
16547 // The absolute mouse position
16548 pageX -
16549
16550 // Click offset (relative to the element)
16551 this.offset.click.left -
16552
16553 // Only for relative positioned nodes: Relative offset from element to offset parent
16554 this.offset.relative.left -
16555
16556 // The offsetParent's offset without borders (offset + border)
16557 this.offset.parent.left +
16558 ( ( this.cssPosition === "fixed" ?
16559 -this.scrollParent.scrollLeft() :
16560 scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
16561 )
16562 };
16563
16564 },
16565
16566 _rearrange: function( event, i, a, hardRefresh ) {
16567
16568 a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
16569 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
16570 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
16571
16572 //Various things done here to improve the performance:
16573 // 1. we create a setTimeout, that calls refreshPositions
16574 // 2. on the instance, we have a counter variable, that get's higher after every append
16575 // 3. on the local scope, we copy the counter variable, and check in the timeout,
16576 // if it's still the same
16577 // 4. this lets only the last addition to the timeout stack through
16578 this.counter = this.counter ? ++this.counter : 1;
16579 var counter = this.counter;
16580
16581 this._delay( function() {
16582 if ( counter === this.counter ) {
16583
16584 //Precompute after each DOM insertion, NOT on mousemove
16585 this.refreshPositions( !hardRefresh );
16586 }
16587 } );
16588
16589 },
16590
16591 _clear: function( event, noPropagation ) {
16592
16593 this.reverting = false;
16594
16595 // We delay all events that have to be triggered to after the point where the placeholder
16596 // has been removed and everything else normalized again
16597 var i,
16598 delayedTriggers = [];
16599
16600 // We first have to update the dom position of the actual currentItem
16601 // Note: don't do it if the current item is already removed (by a user), or it gets
16602 // reappended (see #4088)
16603 if ( !this._noFinalSort && this.currentItem.parent().length ) {
16604 this.placeholder.before( this.currentItem );
16605 }
16606 this._noFinalSort = null;
16607
16608 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
16609 for ( i in this._storedCSS ) {
16610 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
16611 this._storedCSS[ i ] = "";
16612 }
16613 }
16614 this.currentItem.css( this._storedCSS );
16615 this._removeClass( this.currentItem, "ui-sortable-helper" );
16616 } else {
16617 this.currentItem.show();
16618 }
16619
16620 if ( this.fromOutside && !noPropagation ) {
16621 delayedTriggers.push( function( event ) {
16622 this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
16623 } );
16624 }
16625 if ( ( this.fromOutside ||
16626 this.domPosition.prev !==
16627 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
16628 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
16629
16630 // Trigger update callback if the DOM position has changed
16631 delayedTriggers.push( function( event ) {
16632 this._trigger( "update", event, this._uiHash() );
16633 } );
16634 }
16635
16636 // Check if the items Container has Changed and trigger appropriate
16637 // events.
16638 if ( this !== this.currentContainer ) {
16639 if ( !noPropagation ) {
16640 delayedTriggers.push( function( event ) {
16641 this._trigger( "remove", event, this._uiHash() );
16642 } );
16643 delayedTriggers.push( ( function( c ) {
16644 return function( event ) {
16645 c._trigger( "receive", event, this._uiHash( this ) );
16646 };
16647 } ).call( this, this.currentContainer ) );
16648 delayedTriggers.push( ( function( c ) {
16649 return function( event ) {
16650 c._trigger( "update", event, this._uiHash( this ) );
16651 };
16652 } ).call( this, this.currentContainer ) );
16653 }
16654 }
16655
16656 //Post events to containers
16657 function delayEvent( type, instance, container ) {
16658 return function( event ) {
16659 container._trigger( type, event, instance._uiHash( instance ) );
16660 };
16661 }
16662 for ( i = this.containers.length - 1; i >= 0; i-- ) {
16663 if ( !noPropagation ) {
16664 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
16665 }
16666 if ( this.containers[ i ].containerCache.over ) {
16667 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
16668 this.containers[ i ].containerCache.over = 0;
16669 }
16670 }
16671
16672 //Do what was originally in plugins
16673 if ( this.storedCursor ) {
16674 this.document.find( "body" ).css( "cursor", this.storedCursor );
16675 this.storedStylesheet.remove();
16676 }
16677 if ( this._storedOpacity ) {
16678 this.helper.css( "opacity", this._storedOpacity );
16679 }
16680 if ( this._storedZIndex ) {
16681 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
16682 }
16683
16684 this.dragging = false;
16685
16686 if ( !noPropagation ) {
16687 this._trigger( "beforeStop", event, this._uiHash() );
16688 }
16689
16690 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
16691 // it unbinds ALL events from the original node!
16692 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
16693
16694 if ( !this.cancelHelperRemoval ) {
16695 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
16696 this.helper.remove();
16697 }
16698 this.helper = null;
16699 }
16700
16701 if ( !noPropagation ) {
16702 for ( i = 0; i < delayedTriggers.length; i++ ) {
16703
16704 // Trigger all delayed events
16705 delayedTriggers[ i ].call( this, event );
16706 }
16707 this._trigger( "stop", event, this._uiHash() );
16708 }
16709
16710 this.fromOutside = false;
16711 return !this.cancelHelperRemoval;
16712
16713 },
16714
16715 _trigger: function() {
16716 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
16717 this.cancel();
16718 }
16719 },
16720
16721 _uiHash: function( _inst ) {
16722 var inst = _inst || this;
16723 return {
16724 helper: inst.helper,
16725 placeholder: inst.placeholder || $( [] ),
16726 position: inst.position,
16727 originalPosition: inst.originalPosition,
16728 offset: inst.positionAbs,
16729 item: inst.currentItem,
16730 sender: _inst ? _inst.element : null
16731 };
16732 }
16733
16734 } );
16735
16736
16737 /*!
16738 * jQuery UI Spinner 1.12.1
16739 * http://jqueryui.com
16740 *
16741 * Copyright jQuery Foundation and other contributors
16742 * Released under the MIT license.
16743 * http://jquery.org/license
16744 */
16745
16746 //>>label: Spinner
16747 //>>group: Widgets
16748 //>>description: Displays buttons to easily input numbers via the keyboard or mouse.
16749 //>>docs: http://api.jqueryui.com/spinner/
16750 //>>demos: http://jqueryui.com/spinner/
16751 //>>css.structure: ../../themes/base/core.css
16752 //>>css.structure: ../../themes/base/spinner.css
16753 //>>css.theme: ../../themes/base/theme.css
16754
16755
16756
16757 function spinnerModifer( fn ) {
16758 return function() {
16759 var previous = this.element.val();
16760 fn.apply( this, arguments );
16761 this._refresh();
16762 if ( previous !== this.element.val() ) {
16763 this._trigger( "change" );
16764 }
16765 };
16766 }
16767
16768 $.widget( "ui.spinner", {
16769 version: "1.12.1",
16770 defaultElement: "<input>",
16771 widgetEventPrefix: "spin",
16772 options: {
16773 classes: {
16774 "ui-spinner": "ui-corner-all",
16775 "ui-spinner-down": "ui-corner-br",
16776 "ui-spinner-up": "ui-corner-tr"
16777 },
16778 culture: null,
16779 icons: {
16780 down: "ui-icon-triangle-1-s",
16781 up: "ui-icon-triangle-1-n"
16782 },
16783 incremental: true,
16784 max: null,
16785 min: null,
16786 numberFormat: null,
16787 page: 10,
16788 step: 1,
16789
16790 change: null,
16791 spin: null,
16792 start: null,
16793 stop: null
16794 },
16795
16796 _create: function() {
16797
16798 // handle string values that need to be parsed
16799 this._setOption( "max", this.options.max );
16800 this._setOption( "min", this.options.min );
16801 this._setOption( "step", this.options.step );
16802
16803 // Only format if there is a value, prevents the field from being marked
16804 // as invalid in Firefox, see #9573.
16805 if ( this.value() !== "" ) {
16806
16807 // Format the value, but don't constrain.
16808 this._value( this.element.val(), true );
16809 }
16810
16811 this._draw();
16812 this._on( this._events );
16813 this._refresh();
16814
16815 // Turning off autocomplete prevents the browser from remembering the
16816 // value when navigating through history, so we re-enable autocomplete
16817 // if the page is unloaded before the widget is destroyed. #7790
16818 this._on( this.window, {
16819 beforeunload: function() {
16820 this.element.removeAttr( "autocomplete" );
16821 }
16822 } );
16823 },
16824
16825 _getCreateOptions: function() {
16826 var options = this._super();
16827 var element = this.element;
16828
16829 $.each( [ "min", "max", "step" ], function( i, option ) {
16830 var value = element.attr( option );
16831 if ( value != null && value.length ) {
16832 options[ option ] = value;
16833 }
16834 } );
16835
16836 return options;
16837 },
16838
16839 _events: {
16840 keydown: function( event ) {
16841 if ( this._start( event ) && this._keydown( event ) ) {
16842 event.preventDefault();
16843 }
16844 },
16845 keyup: "_stop",
16846 focus: function() {
16847 this.previous = this.element.val();
16848 },
16849 blur: function( event ) {
16850 if ( this.cancelBlur ) {
16851 delete this.cancelBlur;
16852 return;
16853 }
16854
16855 this._stop();
16856 this._refresh();
16857 if ( this.previous !== this.element.val() ) {
16858 this._trigger( "change", event );
16859 }
16860 },
16861 mousewheel: function( event, delta ) {
16862 if ( !delta ) {
16863 return;
16864 }
16865 if ( !this.spinning && !this._start( event ) ) {
16866 return false;
16867 }
16868
16869 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
16870 clearTimeout( this.mousewheelTimer );
16871 this.mousewheelTimer = this._delay( function() {
16872 if ( this.spinning ) {
16873 this._stop( event );
16874 }
16875 }, 100 );
16876 event.preventDefault();
16877 },
16878 "mousedown .ui-spinner-button": function( event ) {
16879 var previous;
16880
16881 // We never want the buttons to have focus; whenever the user is
16882 // interacting with the spinner, the focus should be on the input.
16883 // If the input is focused then this.previous is properly set from
16884 // when the input first received focus. If the input is not focused
16885 // then we need to set this.previous based on the value before spinning.
16886 previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
16887 this.previous : this.element.val();
16888 function checkFocus() {
16889 var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
16890 if ( !isActive ) {
16891 this.element.trigger( "focus" );
16892 this.previous = previous;
16893
16894 // support: IE
16895 // IE sets focus asynchronously, so we need to check if focus
16896 // moved off of the input because the user clicked on the button.
16897 this._delay( function() {
16898 this.previous = previous;
16899 } );
16900 }
16901 }
16902
16903 // Ensure focus is on (or stays on) the text field
16904 event.preventDefault();
16905 checkFocus.call( this );
16906
16907 // Support: IE
16908 // IE doesn't prevent moving focus even with event.preventDefault()
16909 // so we set a flag to know when we should ignore the blur event
16910 // and check (again) if focus moved off of the input.
16911 this.cancelBlur = true;
16912 this._delay( function() {
16913 delete this.cancelBlur;
16914 checkFocus.call( this );
16915 } );
16916
16917 if ( this._start( event ) === false ) {
16918 return;
16919 }
16920
16921 this._repeat( null, $( event.currentTarget )
16922 .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
16923 },
16924 "mouseup .ui-spinner-button": "_stop",
16925 "mouseenter .ui-spinner-button": function( event ) {
16926
16927 // button will add ui-state-active if mouse was down while mouseleave and kept down
16928 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
16929 return;
16930 }
16931
16932 if ( this._start( event ) === false ) {
16933 return false;
16934 }
16935 this._repeat( null, $( event.currentTarget )
16936 .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
16937 },
16938
16939 // TODO: do we really want to consider this a stop?
16940 // shouldn't we just stop the repeater and wait until mouseup before
16941 // we trigger the stop event?
16942 "mouseleave .ui-spinner-button": "_stop"
16943 },
16944
16945 // Support mobile enhanced option and make backcompat more sane
16946 _enhance: function() {
16947 this.uiSpinner = this.element
16948 .attr( "autocomplete", "off" )
16949 .wrap( "<span>" )
16950 .parent()
16951
16952 // Add buttons
16953 .append(
16954 "<a></a><a></a>"
16955 );
16956 },
16957
16958 _draw: function() {
16959 this._enhance();
16960
16961 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
16962 this._addClass( "ui-spinner-input" );
16963
16964 this.element.attr( "role", "spinbutton" );
16965
16966 // Button bindings
16967 this.buttons = this.uiSpinner.children( "a" )
16968 .attr( "tabIndex", -1 )
16969 .attr( "aria-hidden", true )
16970 .button( {
16971 classes: {
16972 "ui-button": ""
16973 }
16974 } );
16975
16976 // TODO: Right now button does not support classes this is already updated in button PR
16977 this._removeClass( this.buttons, "ui-corner-all" );
16978
16979 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
16980 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
16981 this.buttons.first().button( {
16982 "icon": this.options.icons.up,
16983 "showLabel": false
16984 } );
16985 this.buttons.last().button( {
16986 "icon": this.options.icons.down,
16987 "showLabel": false
16988 } );
16989
16990 // IE 6 doesn't understand height: 50% for the buttons
16991 // unless the wrapper has an explicit height
16992 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
16993 this.uiSpinner.height() > 0 ) {
16994 this.uiSpinner.height( this.uiSpinner.height() );
16995 }
16996 },
16997
16998 _keydown: function( event ) {
16999 var options = this.options,
17000 keyCode = $.ui.keyCode;
17001
17002 switch ( event.keyCode ) {
17003 case keyCode.UP:
17004 this._repeat( null, 1, event );
17005 return true;
17006 case keyCode.DOWN:
17007 this._repeat( null, -1, event );
17008 return true;
17009 case keyCode.PAGE_UP:
17010 this._repeat( null, options.page, event );
17011 return true;
17012 case keyCode.PAGE_DOWN:
17013 this._repeat( null, -options.page, event );
17014 return true;
17015 }
17016
17017 return false;
17018 },
17019
17020 _start: function( event ) {
17021 if ( !this.spinning && this._trigger( "start", event ) === false ) {
17022 return false;
17023 }
17024
17025 if ( !this.counter ) {
17026 this.counter = 1;
17027 }
17028 this.spinning = true;
17029 return true;
17030 },
17031
17032 _repeat: function( i, steps, event ) {
17033 i = i || 500;
17034
17035 clearTimeout( this.timer );
17036 this.timer = this._delay( function() {
17037 this._repeat( 40, steps, event );
17038 }, i );
17039
17040 this._spin( steps * this.options.step, event );
17041 },
17042
17043 _spin: function( step, event ) {
17044 var value = this.value() || 0;
17045
17046 if ( !this.counter ) {
17047 this.counter = 1;
17048 }
17049
17050 value = this._adjustValue( value + step * this._increment( this.counter ) );
17051
17052 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
17053 this._value( value );
17054 this.counter++;
17055 }
17056 },
17057
17058 _increment: function( i ) {
17059 var incremental = this.options.incremental;
17060
17061 if ( incremental ) {
17062 return $.isFunction( incremental ) ?
17063 incremental( i ) :
17064 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
17065 }
17066
17067 return 1;
17068 },
17069
17070 _precision: function() {
17071 var precision = this._precisionOf( this.options.step );
17072 if ( this.options.min !== null ) {
17073 precision = Math.max( precision, this._precisionOf( this.options.min ) );
17074 }
17075 return precision;
17076 },
17077
17078 _precisionOf: function( num ) {
17079 var str = num.toString(),
17080 decimal = str.indexOf( "." );
17081 return decimal === -1 ? 0 : str.length - decimal - 1;
17082 },
17083
17084 _adjustValue: function( value ) {
17085 var base, aboveMin,
17086 options = this.options;
17087
17088 // Make sure we're at a valid step
17089 // - find out where we are relative to the base (min or 0)
17090 base = options.min !== null ? options.min : 0;
17091 aboveMin = value - base;
17092
17093 // - round to the nearest step
17094 aboveMin = Math.round( aboveMin / options.step ) * options.step;
17095
17096 // - rounding is based on 0, so adjust back to our base
17097 value = base + aboveMin;
17098
17099 // Fix precision from bad JS floating point math
17100 value = parseFloat( value.toFixed( this._precision() ) );
17101
17102 // Clamp the value
17103 if ( options.max !== null && value > options.max ) {
17104 return options.max;
17105 }
17106 if ( options.min !== null && value < options.min ) {
17107 return options.min;
17108 }
17109
17110 return value;
17111 },
17112
17113 _stop: function( event ) {
17114 if ( !this.spinning ) {
17115 return;
17116 }
17117
17118 clearTimeout( this.timer );
17119 clearTimeout( this.mousewheelTimer );
17120 this.counter = 0;
17121 this.spinning = false;
17122 this._trigger( "stop", event );
17123 },
17124
17125 _setOption: function( key, value ) {
17126 var prevValue, first, last;
17127
17128 if ( key === "culture" || key === "numberFormat" ) {
17129 prevValue = this._parse( this.element.val() );
17130 this.options[ key ] = value;
17131 this.element.val( this._format( prevValue ) );
17132 return;
17133 }
17134
17135 if ( key === "max" || key === "min" || key === "step" ) {
17136 if ( typeof value === "string" ) {
17137 value = this._parse( value );
17138 }
17139 }
17140 if ( key === "icons" ) {
17141 first = this.buttons.first().find( ".ui-icon" );
17142 this._removeClass( first, null, this.options.icons.up );
17143 this._addClass( first, null, value.up );
17144 last = this.buttons.last().find( ".ui-icon" );
17145 this._removeClass( last, null, this.options.icons.down );
17146 this._addClass( last, null, value.down );
17147 }
17148
17149 this._super( key, value );
17150 },
17151
17152 _setOptionDisabled: function( value ) {
17153 this._super( value );
17154
17155 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
17156 this.element.prop( "disabled", !!value );
17157 this.buttons.button( value ? "disable" : "enable" );
17158 },
17159
17160 _setOptions: spinnerModifer( function( options ) {
17161 this._super( options );
17162 } ),
17163
17164 _parse: function( val ) {
17165 if ( typeof val === "string" && val !== "" ) {
17166 val = window.Globalize && this.options.numberFormat ?
17167 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
17168 }
17169 return val === "" || isNaN( val ) ? null : val;
17170 },
17171
17172 _format: function( value ) {
17173 if ( value === "" ) {
17174 return "";
17175 }
17176 return window.Globalize && this.options.numberFormat ?
17177 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
17178 value;
17179 },
17180
17181 _refresh: function() {
17182 this.element.attr( {
17183 "aria-valuemin": this.options.min,
17184 "aria-valuemax": this.options.max,
17185
17186 // TODO: what should we do with values that can't be parsed?
17187 "aria-valuenow": this._parse( this.element.val() )
17188 } );
17189 },
17190
17191 isValid: function() {
17192 var value = this.value();
17193
17194 // Null is invalid
17195 if ( value === null ) {
17196 return false;
17197 }
17198
17199 // If value gets adjusted, it's invalid
17200 return value === this._adjustValue( value );
17201 },
17202
17203 // Update the value without triggering change
17204 _value: function( value, allowAny ) {
17205 var parsed;
17206 if ( value !== "" ) {
17207 parsed = this._parse( value );
17208 if ( parsed !== null ) {
17209 if ( !allowAny ) {
17210 parsed = this._adjustValue( parsed );
17211 }
17212 value = this._format( parsed );
17213 }
17214 }
17215 this.element.val( value );
17216 this._refresh();
17217 },
17218
17219 _destroy: function() {
17220 this.element
17221 .prop( "disabled", false )
17222 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
17223
17224 this.uiSpinner.replaceWith( this.element );
17225 },
17226
17227 stepUp: spinnerModifer( function( steps ) {
17228 this._stepUp( steps );
17229 } ),
17230 _stepUp: function( steps ) {
17231 if ( this._start() ) {
17232 this._spin( ( steps || 1 ) * this.options.step );
17233 this._stop();
17234 }
17235 },
17236
17237 stepDown: spinnerModifer( function( steps ) {
17238 this._stepDown( steps );
17239 } ),
17240 _stepDown: function( steps ) {
17241 if ( this._start() ) {
17242 this._spin( ( steps || 1 ) * -this.options.step );
17243 this._stop();
17244 }
17245 },
17246
17247 pageUp: spinnerModifer( function( pages ) {
17248 this._stepUp( ( pages || 1 ) * this.options.page );
17249 } ),
17250
17251 pageDown: spinnerModifer( function( pages ) {
17252 this._stepDown( ( pages || 1 ) * this.options.page );
17253 } ),
17254
17255 value: function( newVal ) {
17256 if ( !arguments.length ) {
17257 return this._parse( this.element.val() );
17258 }
17259 spinnerModifer( this._value ).call( this, newVal );
17260 },
17261
17262 widget: function() {
17263 return this.uiSpinner;
17264 }
17265 } );
17266
17267 // DEPRECATED
17268 // TODO: switch return back to widget declaration at top of file when this is removed
17269 if ( $.uiBackCompat !== false ) {
17270
17271 // Backcompat for spinner html extension points
17272 $.widget( "ui.spinner", $.ui.spinner, {
17273 _enhance: function() {
17274 this.uiSpinner = this.element
17275 .attr( "autocomplete", "off" )
17276 .wrap( this._uiSpinnerHtml() )
17277 .parent()
17278
17279 // Add buttons
17280 .append( this._buttonHtml() );
17281 },
17282 _uiSpinnerHtml: function() {
17283 return "<span>";
17284 },
17285
17286 _buttonHtml: function() {
17287 return "<a></a><a></a>";
17288 }
17289 } );
17290 }
17291
17292 var widgetsSpinner = $.ui.spinner;
17293
17294
17295 /*!
17296 * jQuery UI Tabs 1.12.1
17297 * http://jqueryui.com
17298 *
17299 * Copyright jQuery Foundation and other contributors
17300 * Released under the MIT license.
17301 * http://jquery.org/license
17302 */
17303
17304 //>>label: Tabs
17305 //>>group: Widgets
17306 //>>description: Transforms a set of container elements into a tab structure.
17307 //>>docs: http://api.jqueryui.com/tabs/
17308 //>>demos: http://jqueryui.com/tabs/
17309 //>>css.structure: ../../themes/base/core.css
17310 //>>css.structure: ../../themes/base/tabs.css
17311 //>>css.theme: ../../themes/base/theme.css
17312
17313
17314
17315 $.widget( "ui.tabs", {
17316 version: "1.12.1",
17317 delay: 300,
17318 options: {
17319 active: null,
17320 classes: {
17321 "ui-tabs": "ui-corner-all",
17322 "ui-tabs-nav": "ui-corner-all",
17323 "ui-tabs-panel": "ui-corner-bottom",
17324 "ui-tabs-tab": "ui-corner-top"
17325 },
17326 collapsible: false,
17327 event: "click",
17328 heightStyle: "content",
17329 hide: null,
17330 show: null,
17331
17332 // Callbacks
17333 activate: null,
17334 beforeActivate: null,
17335 beforeLoad: null,
17336 load: null
17337 },
17338
17339 _isLocal: ( function() {
17340 var rhash = /#.*$/;
17341
17342 return function( anchor ) {
17343 var anchorUrl, locationUrl;
17344
17345 anchorUrl = anchor.href.replace( rhash, "" );
17346 locationUrl = location.href.replace( rhash, "" );
17347
17348 // Decoding may throw an error if the URL isn't UTF-8 (#9518)
17349 try {
17350 anchorUrl = decodeURIComponent( anchorUrl );
17351 } catch ( error ) {}
17352 try {
17353 locationUrl = decodeURIComponent( locationUrl );
17354 } catch ( error ) {}
17355
17356 return anchor.hash.length > 1 && anchorUrl === locationUrl;
17357 };
17358 } )(),
17359
17360 _create: function() {
17361 var that = this,
17362 options = this.options;
17363
17364 this.running = false;
17365
17366 this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
17367 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
17368
17369 this._processTabs();
17370 options.active = this._initialActive();
17371
17372 // Take disabling tabs via class attribute from HTML
17373 // into account and update option properly.
17374 if ( $.isArray( options.disabled ) ) {
17375 options.disabled = $.unique( options.disabled.concat(
17376 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
17377 return that.tabs.index( li );
17378 } )
17379 ) ).sort();
17380 }
17381
17382 // Check for length avoids error when initializing empty list
17383 if ( this.options.active !== false && this.anchors.length ) {
17384 this.active = this._findActive( options.active );
17385 } else {
17386 this.active = $();
17387 }
17388
17389 this._refresh();
17390
17391 if ( this.active.length ) {
17392 this.load( options.active );
17393 }
17394 },
17395
17396 _initialActive: function() {
17397 var active = this.options.active,
17398 collapsible = this.options.collapsible,
17399 locationHash = location.hash.substring( 1 );
17400
17401 if ( active === null ) {
17402
17403 // check the fragment identifier in the URL
17404 if ( locationHash ) {
17405 this.tabs.each( function( i, tab ) {
17406 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
17407 active = i;
17408 return false;
17409 }
17410 } );
17411 }
17412
17413 // Check for a tab marked active via a class
17414 if ( active === null ) {
17415 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
17416 }
17417
17418 // No active tab, set to false
17419 if ( active === null || active === -1 ) {
17420 active = this.tabs.length ? 0 : false;
17421 }
17422 }
17423
17424 // Handle numbers: negative, out of range
17425 if ( active !== false ) {
17426 active = this.tabs.index( this.tabs.eq( active ) );
17427 if ( active === -1 ) {
17428 active = collapsible ? false : 0;
17429 }
17430 }
17431
17432 // Don't allow collapsible: false and active: false
17433 if ( !collapsible && active === false && this.anchors.length ) {
17434 active = 0;
17435 }
17436
17437 return active;
17438 },
17439
17440 _getCreateEventData: function() {
17441 return {
17442 tab: this.active,
17443 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
17444 };
17445 },
17446
17447 _tabKeydown: function( event ) {
17448 var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
17449 selectedIndex = this.tabs.index( focusedTab ),
17450 goingForward = true;
17451
17452 if ( this._handlePageNav( event ) ) {
17453 return;
17454 }
17455
17456 switch ( event.keyCode ) {
17457 case $.ui.keyCode.RIGHT:
17458 case $.ui.keyCode.DOWN:
17459 selectedIndex++;
17460 break;
17461 case $.ui.keyCode.UP:
17462 case $.ui.keyCode.LEFT:
17463 goingForward = false;
17464 selectedIndex--;
17465 break;
17466 case $.ui.keyCode.END:
17467 selectedIndex = this.anchors.length - 1;
17468 break;
17469 case $.ui.keyCode.HOME:
17470 selectedIndex = 0;
17471 break;
17472 case $.ui.keyCode.SPACE:
17473
17474 // Activate only, no collapsing
17475 event.preventDefault();
17476 clearTimeout( this.activating );
17477 this._activate( selectedIndex );
17478 return;
17479 case $.ui.keyCode.ENTER:
17480
17481 // Toggle (cancel delayed activation, allow collapsing)
17482 event.preventDefault();
17483 clearTimeout( this.activating );
17484
17485 // Determine if we should collapse or activate
17486 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
17487 return;
17488 default:
17489 return;
17490 }
17491
17492 // Focus the appropriate tab, based on which key was pressed
17493 event.preventDefault();
17494 clearTimeout( this.activating );
17495 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
17496
17497 // Navigating with control/command key will prevent automatic activation
17498 if ( !event.ctrlKey && !event.metaKey ) {
17499
17500 // Update aria-selected immediately so that AT think the tab is already selected.
17501 // Otherwise AT may confuse the user by stating that they need to activate the tab,
17502 // but the tab will already be activated by the time the announcement finishes.
17503 focusedTab.attr( "aria-selected", "false" );
17504 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
17505
17506 this.activating = this._delay( function() {
17507 this.option( "active", selectedIndex );
17508 }, this.delay );
17509 }
17510 },
17511
17512 _panelKeydown: function( event ) {
17513 if ( this._handlePageNav( event ) ) {
17514 return;
17515 }
17516
17517 // Ctrl+up moves focus to the current tab
17518 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
17519 event.preventDefault();
17520 this.active.trigger( "focus" );
17521 }
17522 },
17523
17524 // Alt+page up/down moves focus to the previous/next tab (and activates)
17525 _handlePageNav: function( event ) {
17526 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
17527 this._activate( this._focusNextTab( this.options.active - 1, false ) );
17528 return true;
17529 }
17530 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
17531 this._activate( this._focusNextTab( this.options.active + 1, true ) );
17532 return true;
17533 }
17534 },
17535
17536 _findNextTab: function( index, goingForward ) {
17537 var lastTabIndex = this.tabs.length - 1;
17538
17539 function constrain() {
17540 if ( index > lastTabIndex ) {
17541 index = 0;
17542 }
17543 if ( index < 0 ) {
17544 index = lastTabIndex;
17545 }
17546 return index;
17547 }
17548
17549 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
17550 index = goingForward ? index + 1 : index - 1;
17551 }
17552
17553 return index;
17554 },
17555
17556 _focusNextTab: function( index, goingForward ) {
17557 index = this._findNextTab( index, goingForward );
17558 this.tabs.eq( index ).trigger( "focus" );
17559 return index;
17560 },
17561
17562 _setOption: function( key, value ) {
17563 if ( key === "active" ) {
17564
17565 // _activate() will handle invalid values and update this.options
17566 this._activate( value );
17567 return;
17568 }
17569
17570 this._super( key, value );
17571
17572 if ( key === "collapsible" ) {
17573 this._toggleClass( "ui-tabs-collapsible", null, value );
17574
17575 // Setting collapsible: false while collapsed; open first panel
17576 if ( !value && this.options.active === false ) {
17577 this._activate( 0 );
17578 }
17579 }
17580
17581 if ( key === "event" ) {
17582 this._setupEvents( value );
17583 }
17584
17585 if ( key === "heightStyle" ) {
17586 this._setupHeightStyle( value );
17587 }
17588 },
17589
17590 _sanitizeSelector: function( hash ) {
17591 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
17592 },
17593
17594 refresh: function() {
17595 var options = this.options,
17596 lis = this.tablist.children( ":has(a[href])" );
17597
17598 // Get disabled tabs from class attribute from HTML
17599 // this will get converted to a boolean if needed in _refresh()
17600 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
17601 return lis.index( tab );
17602 } );
17603
17604 this._processTabs();
17605
17606 // Was collapsed or no tabs
17607 if ( options.active === false || !this.anchors.length ) {
17608 options.active = false;
17609 this.active = $();
17610
17611 // was active, but active tab is gone
17612 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
17613
17614 // all remaining tabs are disabled
17615 if ( this.tabs.length === options.disabled.length ) {
17616 options.active = false;
17617 this.active = $();
17618
17619 // activate previous tab
17620 } else {
17621 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
17622 }
17623
17624 // was active, active tab still exists
17625 } else {
17626
17627 // make sure active index is correct
17628 options.active = this.tabs.index( this.active );
17629 }
17630
17631 this._refresh();
17632 },
17633
17634 _refresh: function() {
17635 this._setOptionDisabled( this.options.disabled );
17636 this._setupEvents( this.options.event );
17637 this._setupHeightStyle( this.options.heightStyle );
17638
17639 this.tabs.not( this.active ).attr( {
17640 "aria-selected": "false",
17641 "aria-expanded": "false",
17642 tabIndex: -1
17643 } );
17644 this.panels.not( this._getPanelForTab( this.active ) )
17645 .hide()
17646 .attr( {
17647 "aria-hidden": "true"
17648 } );
17649
17650 // Make sure one tab is in the tab order
17651 if ( !this.active.length ) {
17652 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
17653 } else {
17654 this.active
17655 .attr( {
17656 "aria-selected": "true",
17657 "aria-expanded": "true",
17658 tabIndex: 0
17659 } );
17660 this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
17661 this._getPanelForTab( this.active )
17662 .show()
17663 .attr( {
17664 "aria-hidden": "false"
17665 } );
17666 }
17667 },
17668
17669 _processTabs: function() {
17670 var that = this,
17671 prevTabs = this.tabs,
17672 prevAnchors = this.anchors,
17673 prevPanels = this.panels;
17674
17675 this.tablist = this._getList().attr( "role", "tablist" );
17676 this._addClass( this.tablist, "ui-tabs-nav",
17677 "ui-helper-reset ui-helper-clearfix ui-widget-header" );
17678
17679 // Prevent users from focusing disabled tabs via click
17680 this.tablist
17681 .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
17682 if ( $( this ).is( ".ui-state-disabled" ) ) {
17683 event.preventDefault();
17684 }
17685 } )
17686
17687 // Support: IE <9
17688 // Preventing the default action in mousedown doesn't prevent IE
17689 // from focusing the element, so if the anchor gets focused, blur.
17690 // We don't have to worry about focusing the previously focused
17691 // element since clicking on a non-focusable element should focus
17692 // the body anyway.
17693 .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
17694 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
17695 this.blur();
17696 }
17697 } );
17698
17699 this.tabs = this.tablist.find( "> li:has(a[href])" )
17700 .attr( {
17701 role: "tab",
17702 tabIndex: -1
17703 } );
17704 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
17705
17706 this.anchors = this.tabs.map( function() {
17707 return $( "a", this )[ 0 ];
17708 } )
17709 .attr( {
17710 role: "presentation",
17711 tabIndex: -1
17712 } );
17713 this._addClass( this.anchors, "ui-tabs-anchor" );
17714
17715 this.panels = $();
17716
17717 this.anchors.each( function( i, anchor ) {
17718 var selector, panel, panelId,
17719 anchorId = $( anchor ).uniqueId().attr( "id" ),
17720 tab = $( anchor ).closest( "li" ),
17721 originalAriaControls = tab.attr( "aria-controls" );
17722
17723 // Inline tab
17724 if ( that._isLocal( anchor ) ) {
17725 selector = anchor.hash;
17726 panelId = selector.substring( 1 );
17727 panel = that.element.find( that._sanitizeSelector( selector ) );
17728
17729 // remote tab
17730 } else {
17731
17732 // If the tab doesn't already have aria-controls,
17733 // generate an id by using a throw-away element
17734 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
17735 selector = "#" + panelId;
17736 panel = that.element.find( selector );
17737 if ( !panel.length ) {
17738 panel = that._createPanel( panelId );
17739 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
17740 }
17741 panel.attr( "aria-live", "polite" );
17742 }
17743
17744 if ( panel.length ) {
17745 that.panels = that.panels.add( panel );
17746 }
17747 if ( originalAriaControls ) {
17748 tab.data( "ui-tabs-aria-controls", originalAriaControls );
17749 }
17750 tab.attr( {
17751 "aria-controls": panelId,
17752 "aria-labelledby": anchorId
17753 } );
17754 panel.attr( "aria-labelledby", anchorId );
17755 } );
17756
17757 this.panels.attr( "role", "tabpanel" );
17758 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
17759
17760 // Avoid memory leaks (#10056)
17761 if ( prevTabs ) {
17762 this._off( prevTabs.not( this.tabs ) );
17763 this._off( prevAnchors.not( this.anchors ) );
17764 this._off( prevPanels.not( this.panels ) );
17765 }
17766 },
17767
17768 // Allow overriding how to find the list for rare usage scenarios (#7715)
17769 _getList: function() {
17770 return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
17771 },
17772
17773 _createPanel: function( id ) {
17774 return $( "<div>" )
17775 .attr( "id", id )
17776 .data( "ui-tabs-destroy", true );
17777 },
17778
17779 _setOptionDisabled: function( disabled ) {
17780 var currentItem, li, i;
17781
17782 if ( $.isArray( disabled ) ) {
17783 if ( !disabled.length ) {
17784 disabled = false;
17785 } else if ( disabled.length === this.anchors.length ) {
17786 disabled = true;
17787 }
17788 }
17789
17790 // Disable tabs
17791 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
17792 currentItem = $( li );
17793 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
17794 currentItem.attr( "aria-disabled", "true" );
17795 this._addClass( currentItem, null, "ui-state-disabled" );
17796 } else {
17797 currentItem.removeAttr( "aria-disabled" );
17798 this._removeClass( currentItem, null, "ui-state-disabled" );
17799 }
17800 }
17801
17802 this.options.disabled = disabled;
17803
17804 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
17805 disabled === true );
17806 },
17807
17808 _setupEvents: function( event ) {
17809 var events = {};
17810 if ( event ) {
17811 $.each( event.split( " " ), function( index, eventName ) {
17812 events[ eventName ] = "_eventHandler";
17813 } );
17814 }
17815
17816 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
17817
17818 // Always prevent the default action, even when disabled
17819 this._on( true, this.anchors, {
17820 click: function( event ) {
17821 event.preventDefault();
17822 }
17823 } );
17824 this._on( this.anchors, events );
17825 this._on( this.tabs, { keydown: "_tabKeydown" } );
17826 this._on( this.panels, { keydown: "_panelKeydown" } );
17827
17828 this._focusable( this.tabs );
17829 this._hoverable( this.tabs );
17830 },
17831
17832 _setupHeightStyle: function( heightStyle ) {
17833 var maxHeight,
17834 parent = this.element.parent();
17835
17836 if ( heightStyle === "fill" ) {
17837 maxHeight = parent.height();
17838 maxHeight -= this.element.outerHeight() - this.element.height();
17839
17840 this.element.siblings( ":visible" ).each( function() {
17841 var elem = $( this ),
17842 position = elem.css( "position" );
17843
17844 if ( position === "absolute" || position === "fixed" ) {
17845 return;
17846 }
17847 maxHeight -= elem.outerHeight( true );
17848 } );
17849
17850 this.element.children().not( this.panels ).each( function() {
17851 maxHeight -= $( this ).outerHeight( true );
17852 } );
17853
17854 this.panels.each( function() {
17855 $( this ).height( Math.max( 0, maxHeight -
17856 $( this ).innerHeight() + $( this ).height() ) );
17857 } )
17858 .css( "overflow", "auto" );
17859 } else if ( heightStyle === "auto" ) {
17860 maxHeight = 0;
17861 this.panels.each( function() {
17862 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
17863 } ).height( maxHeight );
17864 }
17865 },
17866
17867 _eventHandler: function( event ) {
17868 var options = this.options,
17869 active = this.active,
17870 anchor = $( event.currentTarget ),
17871 tab = anchor.closest( "li" ),
17872 clickedIsActive = tab[ 0 ] === active[ 0 ],
17873 collapsing = clickedIsActive && options.collapsible,
17874 toShow = collapsing ? $() : this._getPanelForTab( tab ),
17875 toHide = !active.length ? $() : this._getPanelForTab( active ),
17876 eventData = {
17877 oldTab: active,
17878 oldPanel: toHide,
17879 newTab: collapsing ? $() : tab,
17880 newPanel: toShow
17881 };
17882
17883 event.preventDefault();
17884
17885 if ( tab.hasClass( "ui-state-disabled" ) ||
17886
17887 // tab is already loading
17888 tab.hasClass( "ui-tabs-loading" ) ||
17889
17890 // can't switch durning an animation
17891 this.running ||
17892
17893 // click on active header, but not collapsible
17894 ( clickedIsActive && !options.collapsible ) ||
17895
17896 // allow canceling activation
17897 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
17898 return;
17899 }
17900
17901 options.active = collapsing ? false : this.tabs.index( tab );
17902
17903 this.active = clickedIsActive ? $() : tab;
17904 if ( this.xhr ) {
17905 this.xhr.abort();
17906 }
17907
17908 if ( !toHide.length && !toShow.length ) {
17909 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
17910 }
17911
17912 if ( toShow.length ) {
17913 this.load( this.tabs.index( tab ), event );
17914 }
17915 this._toggle( event, eventData );
17916 },
17917
17918 // Handles show/hide for selecting tabs
17919 _toggle: function( event, eventData ) {
17920 var that = this,
17921 toShow = eventData.newPanel,
17922 toHide = eventData.oldPanel;
17923
17924 this.running = true;
17925
17926 function complete() {
17927 that.running = false;
17928 that._trigger( "activate", event, eventData );
17929 }
17930
17931 function show() {
17932 that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
17933
17934 if ( toShow.length && that.options.show ) {
17935 that._show( toShow, that.options.show, complete );
17936 } else {
17937 toShow.show();
17938 complete();
17939 }
17940 }
17941
17942 // Start out by hiding, then showing, then completing
17943 if ( toHide.length && this.options.hide ) {
17944 this._hide( toHide, this.options.hide, function() {
17945 that._removeClass( eventData.oldTab.closest( "li" ),
17946 "ui-tabs-active", "ui-state-active" );
17947 show();
17948 } );
17949 } else {
17950 this._removeClass( eventData.oldTab.closest( "li" ),
17951 "ui-tabs-active", "ui-state-active" );
17952 toHide.hide();
17953 show();
17954 }
17955
17956 toHide.attr( "aria-hidden", "true" );
17957 eventData.oldTab.attr( {
17958 "aria-selected": "false",
17959 "aria-expanded": "false"
17960 } );
17961
17962 // If we're switching tabs, remove the old tab from the tab order.
17963 // If we're opening from collapsed state, remove the previous tab from the tab order.
17964 // If we're collapsing, then keep the collapsing tab in the tab order.
17965 if ( toShow.length && toHide.length ) {
17966 eventData.oldTab.attr( "tabIndex", -1 );
17967 } else if ( toShow.length ) {
17968 this.tabs.filter( function() {
17969 return $( this ).attr( "tabIndex" ) === 0;
17970 } )
17971 .attr( "tabIndex", -1 );
17972 }
17973
17974 toShow.attr( "aria-hidden", "false" );
17975 eventData.newTab.attr( {
17976 "aria-selected": "true",
17977 "aria-expanded": "true",
17978 tabIndex: 0
17979 } );
17980 },
17981
17982 _activate: function( index ) {
17983 var anchor,
17984 active = this._findActive( index );
17985
17986 // Trying to activate the already active panel
17987 if ( active[ 0 ] === this.active[ 0 ] ) {
17988 return;
17989 }
17990
17991 // Trying to collapse, simulate a click on the current active header
17992 if ( !active.length ) {
17993 active = this.active;
17994 }
17995
17996 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
17997 this._eventHandler( {
17998 target: anchor,
17999 currentTarget: anchor,
18000 preventDefault: $.noop
18001 } );
18002 },
18003
18004 _findActive: function( index ) {
18005 return index === false ? $() : this.tabs.eq( index );
18006 },
18007
18008 _getIndex: function( index ) {
18009
18010 // meta-function to give users option to provide a href string instead of a numerical index.
18011 if ( typeof index === "string" ) {
18012 index = this.anchors.index( this.anchors.filter( "[href$='" +
18013 $.ui.escapeSelector( index ) + "']" ) );
18014 }
18015
18016 return index;
18017 },
18018
18019 _destroy: function() {
18020 if ( this.xhr ) {
18021 this.xhr.abort();
18022 }
18023
18024 this.tablist
18025 .removeAttr( "role" )
18026 .off( this.eventNamespace );
18027
18028 this.anchors
18029 .removeAttr( "role tabIndex" )
18030 .removeUniqueId();
18031
18032 this.tabs.add( this.panels ).each( function() {
18033 if ( $.data( this, "ui-tabs-destroy" ) ) {
18034 $( this ).remove();
18035 } else {
18036 $( this ).removeAttr( "role tabIndex " +
18037 "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
18038 }
18039 } );
18040
18041 this.tabs.each( function() {
18042 var li = $( this ),
18043 prev = li.data( "ui-tabs-aria-controls" );
18044 if ( prev ) {
18045 li
18046 .attr( "aria-controls", prev )
18047 .removeData( "ui-tabs-aria-controls" );
18048 } else {
18049 li.removeAttr( "aria-controls" );
18050 }
18051 } );
18052
18053 this.panels.show();
18054
18055 if ( this.options.heightStyle !== "content" ) {
18056 this.panels.css( "height", "" );
18057 }
18058 },
18059
18060 enable: function( index ) {
18061 var disabled = this.options.disabled;
18062 if ( disabled === false ) {
18063 return;
18064 }
18065
18066 if ( index === undefined ) {
18067 disabled = false;
18068 } else {
18069 index = this._getIndex( index );
18070 if ( $.isArray( disabled ) ) {
18071 disabled = $.map( disabled, function( num ) {
18072 return num !== index ? num : null;
18073 } );
18074 } else {
18075 disabled = $.map( this.tabs, function( li, num ) {
18076 return num !== index ? num : null;
18077 } );
18078 }
18079 }
18080 this._setOptionDisabled( disabled );
18081 },
18082
18083 disable: function( index ) {
18084 var disabled = this.options.disabled;
18085 if ( disabled === true ) {
18086 return;
18087 }
18088
18089 if ( index === undefined ) {
18090 disabled = true;
18091 } else {
18092 index = this._getIndex( index );
18093 if ( $.inArray( index, disabled ) !== -1 ) {
18094 return;
18095 }
18096 if ( $.isArray( disabled ) ) {
18097 disabled = $.merge( [ index ], disabled ).sort();
18098 } else {
18099 disabled = [ index ];
18100 }
18101 }
18102 this._setOptionDisabled( disabled );
18103 },
18104
18105 load: function( index, event ) {
18106 index = this._getIndex( index );
18107 var that = this,
18108 tab = this.tabs.eq( index ),
18109 anchor = tab.find( ".ui-tabs-anchor" ),
18110 panel = this._getPanelForTab( tab ),
18111 eventData = {
18112 tab: tab,
18113 panel: panel
18114 },
18115 complete = function( jqXHR, status ) {
18116 if ( status === "abort" ) {
18117 that.panels.stop( false, true );
18118 }
18119
18120 that._removeClass( tab, "ui-tabs-loading" );
18121 panel.removeAttr( "aria-busy" );
18122
18123 if ( jqXHR === that.xhr ) {
18124 delete that.xhr;
18125 }
18126 };
18127
18128 // Not remote
18129 if ( this._isLocal( anchor[ 0 ] ) ) {
18130 return;
18131 }
18132
18133 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
18134
18135 // Support: jQuery <1.8
18136 // jQuery <1.8 returns false if the request is canceled in beforeSend,
18137 // but as of 1.8, $.ajax() always returns a jqXHR object.
18138 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
18139 this._addClass( tab, "ui-tabs-loading" );
18140 panel.attr( "aria-busy", "true" );
18141
18142 this.xhr
18143 .done( function( response, status, jqXHR ) {
18144
18145 // support: jQuery <1.8
18146 // http://bugs.jquery.com/ticket/11778
18147 setTimeout( function() {
18148 panel.html( response );
18149 that._trigger( "load", event, eventData );
18150
18151 complete( jqXHR, status );
18152 }, 1 );
18153 } )
18154 .fail( function( jqXHR, status ) {
18155
18156 // support: jQuery <1.8
18157 // http://bugs.jquery.com/ticket/11778
18158 setTimeout( function() {
18159 complete( jqXHR, status );
18160 }, 1 );
18161 } );
18162 }
18163 },
18164
18165 _ajaxSettings: function( anchor, event, eventData ) {
18166 var that = this;
18167 return {
18168
18169 // Support: IE <11 only
18170 // Strip any hash that exists to prevent errors with the Ajax request
18171 url: anchor.attr( "href" ).replace( /#.*$/, "" ),
18172 beforeSend: function( jqXHR, settings ) {
18173 return that._trigger( "beforeLoad", event,
18174 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
18175 }
18176 };
18177 },
18178
18179 _getPanelForTab: function( tab ) {
18180 var id = $( tab ).attr( "aria-controls" );
18181 return this.element.find( this._sanitizeSelector( "#" + id ) );
18182 }
18183 } );
18184
18185 // DEPRECATED
18186 // TODO: Switch return back to widget declaration at top of file when this is removed
18187 if ( $.uiBackCompat !== false ) {
18188
18189 // Backcompat for ui-tab class (now ui-tabs-tab)
18190 $.widget( "ui.tabs", $.ui.tabs, {
18191 _processTabs: function() {
18192 this._superApply( arguments );
18193 this._addClass( this.tabs, "ui-tab" );
18194 }
18195 } );
18196 }
18197
18198 var widgetsTabs = $.ui.tabs;
18199
18200
18201 /*!
18202 * jQuery UI Tooltip 1.12.1
18203 * http://jqueryui.com
18204 *
18205 * Copyright jQuery Foundation and other contributors
18206 * Released under the MIT license.
18207 * http://jquery.org/license
18208 */
18209
18210 //>>label: Tooltip
18211 //>>group: Widgets
18212 //>>description: Shows additional information for any element on hover or focus.
18213 //>>docs: http://api.jqueryui.com/tooltip/
18214 //>>demos: http://jqueryui.com/tooltip/
18215 //>>css.structure: ../../themes/base/core.css
18216 //>>css.structure: ../../themes/base/tooltip.css
18217 //>>css.theme: ../../themes/base/theme.css
18218
18219
18220
18221 $.widget( "ui.tooltip", {
18222 version: "1.12.1",
18223 options: {
18224 classes: {
18225 "ui-tooltip": "ui-corner-all ui-widget-shadow"
18226 },
18227 content: function() {
18228
18229 // support: IE<9, Opera in jQuery <1.7
18230 // .text() can't accept undefined, so coerce to a string
18231 var title = $( this ).attr( "title" ) || "";
18232
18233 // Escape title, since we're going from an attribute to raw HTML
18234 return $( "<a>" ).text( title ).html();
18235 },
18236 hide: true,
18237
18238 // Disabled elements have inconsistent behavior across browsers (#8661)
18239 items: "[title]:not([disabled])",
18240 position: {
18241 my: "left top+15",
18242 at: "left bottom",
18243 collision: "flipfit flip"
18244 },
18245 show: true,
18246 track: false,
18247
18248 // Callbacks
18249 close: null,
18250 open: null
18251 },
18252
18253 _addDescribedBy: function( elem, id ) {
18254 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
18255 describedby.push( id );
18256 elem
18257 .data( "ui-tooltip-id", id )
18258 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
18259 },
18260
18261 _removeDescribedBy: function( elem ) {
18262 var id = elem.data( "ui-tooltip-id" ),
18263 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
18264 index = $.inArray( id, describedby );
18265
18266 if ( index !== -1 ) {
18267 describedby.splice( index, 1 );
18268 }
18269
18270 elem.removeData( "ui-tooltip-id" );
18271 describedby = $.trim( describedby.join( " " ) );
18272 if ( describedby ) {
18273 elem.attr( "aria-describedby", describedby );
18274 } else {
18275 elem.removeAttr( "aria-describedby" );
18276 }
18277 },
18278
18279 _create: function() {
18280 this._on( {
18281 mouseover: "open",
18282 focusin: "open"
18283 } );
18284
18285 // IDs of generated tooltips, needed for destroy
18286 this.tooltips = {};
18287
18288 // IDs of parent tooltips where we removed the title attribute
18289 this.parents = {};
18290
18291 // Append the aria-live region so tooltips announce correctly
18292 this.liveRegion = $( "<div>" )
18293 .attr( {
18294 role: "log",
18295 "aria-live": "assertive",
18296 "aria-relevant": "additions"
18297 } )
18298 .appendTo( this.document[ 0 ].body );
18299 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
18300
18301 this.disabledTitles = $( [] );
18302 },
18303
18304 _setOption: function( key, value ) {
18305 var that = this;
18306
18307 this._super( key, value );
18308
18309 if ( key === "content" ) {
18310 $.each( this.tooltips, function( id, tooltipData ) {
18311 that._updateContent( tooltipData.element );
18312 } );
18313 }
18314 },
18315
18316 _setOptionDisabled: function( value ) {
18317 this[ value ? "_disable" : "_enable" ]();
18318 },
18319
18320 _disable: function() {
18321 var that = this;
18322
18323 // Close open tooltips
18324 $.each( this.tooltips, function( id, tooltipData ) {
18325 var event = $.Event( "blur" );
18326 event.target = event.currentTarget = tooltipData.element[ 0 ];
18327 that.close( event, true );
18328 } );
18329
18330 // Remove title attributes to prevent native tooltips
18331 this.disabledTitles = this.disabledTitles.add(
18332 this.element.find( this.options.items ).addBack()
18333 .filter( function() {
18334 var element = $( this );
18335 if ( element.is( "[title]" ) ) {
18336 return element
18337 .data( "ui-tooltip-title", element.attr( "title" ) )
18338 .removeAttr( "title" );
18339 }
18340 } )
18341 );
18342 },
18343
18344 _enable: function() {
18345
18346 // restore title attributes
18347 this.disabledTitles.each( function() {
18348 var element = $( this );
18349 if ( element.data( "ui-tooltip-title" ) ) {
18350 element.attr( "title", element.data( "ui-tooltip-title" ) );
18351 }
18352 } );
18353 this.disabledTitles = $( [] );
18354 },
18355
18356 open: function( event ) {
18357 var that = this,
18358 target = $( event ? event.target : this.element )
18359
18360 // we need closest here due to mouseover bubbling,
18361 // but always pointing at the same event target
18362 .closest( this.options.items );
18363
18364 // No element to show a tooltip for or the tooltip is already open
18365 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
18366 return;
18367 }
18368
18369 if ( target.attr( "title" ) ) {
18370 target.data( "ui-tooltip-title", target.attr( "title" ) );
18371 }
18372
18373 target.data( "ui-tooltip-open", true );
18374
18375 // Kill parent tooltips, custom or native, for hover
18376 if ( event && event.type === "mouseover" ) {
18377 target.parents().each( function() {
18378 var parent = $( this ),
18379 blurEvent;
18380 if ( parent.data( "ui-tooltip-open" ) ) {
18381 blurEvent = $.Event( "blur" );
18382 blurEvent.target = blurEvent.currentTarget = this;
18383 that.close( blurEvent, true );
18384 }
18385 if ( parent.attr( "title" ) ) {
18386 parent.uniqueId();
18387 that.parents[ this.id ] = {
18388 element: this,
18389 title: parent.attr( "title" )
18390 };
18391 parent.attr( "title", "" );
18392 }
18393 } );
18394 }
18395
18396 this._registerCloseHandlers( event, target );
18397 this._updateContent( target, event );
18398 },
18399
18400 _updateContent: function( target, event ) {
18401 var content,
18402 contentOption = this.options.content,
18403 that = this,
18404 eventType = event ? event.type : null;
18405
18406 if ( typeof contentOption === "string" || contentOption.nodeType ||
18407 contentOption.jquery ) {
18408 return this._open( event, target, contentOption );
18409 }
18410
18411 content = contentOption.call( target[ 0 ], function( response ) {
18412
18413 // IE may instantly serve a cached response for ajax requests
18414 // delay this call to _open so the other call to _open runs first
18415 that._delay( function() {
18416
18417 // Ignore async response if tooltip was closed already
18418 if ( !target.data( "ui-tooltip-open" ) ) {
18419 return;
18420 }
18421
18422 // JQuery creates a special event for focusin when it doesn't
18423 // exist natively. To improve performance, the native event
18424 // object is reused and the type is changed. Therefore, we can't
18425 // rely on the type being correct after the event finished
18426 // bubbling, so we set it back to the previous value. (#8740)
18427 if ( event ) {
18428 event.type = eventType;
18429 }
18430 this._open( event, target, response );
18431 } );
18432 } );
18433 if ( content ) {
18434 this._open( event, target, content );
18435 }
18436 },
18437
18438 _open: function( event, target, content ) {
18439 var tooltipData, tooltip, delayedShow, a11yContent,
18440 positionOption = $.extend( {}, this.options.position );
18441
18442 if ( !content ) {
18443 return;
18444 }
18445
18446 // Content can be updated multiple times. If the tooltip already
18447 // exists, then just update the content and bail.
18448 tooltipData = this._find( target );
18449 if ( tooltipData ) {
18450 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
18451 return;
18452 }
18453
18454 // If we have a title, clear it to prevent the native tooltip
18455 // we have to check first to avoid defining a title if none exists
18456 // (we don't want to cause an element to start matching [title])
18457 //
18458 // We use removeAttr only for key events, to allow IE to export the correct
18459 // accessible attributes. For mouse events, set to empty string to avoid
18460 // native tooltip showing up (happens only when removing inside mouseover).
18461 if ( target.is( "[title]" ) ) {
18462 if ( event && event.type === "mouseover" ) {
18463 target.attr( "title", "" );
18464 } else {
18465 target.removeAttr( "title" );
18466 }
18467 }
18468
18469 tooltipData = this._tooltip( target );
18470 tooltip = tooltipData.tooltip;
18471 this._addDescribedBy( target, tooltip.attr( "id" ) );
18472 tooltip.find( ".ui-tooltip-content" ).html( content );
18473
18474 // Support: Voiceover on OS X, JAWS on IE <= 9
18475 // JAWS announces deletions even when aria-relevant="additions"
18476 // Voiceover will sometimes re-read the entire log region's contents from the beginning
18477 this.liveRegion.children().hide();
18478 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
18479 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
18480 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
18481 a11yContent.appendTo( this.liveRegion );
18482
18483 function position( event ) {
18484 positionOption.of = event;
18485 if ( tooltip.is( ":hidden" ) ) {
18486 return;
18487 }
18488 tooltip.position( positionOption );
18489 }
18490 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
18491 this._on( this.document, {
18492 mousemove: position
18493 } );
18494
18495 // trigger once to override element-relative positioning
18496 position( event );
18497 } else {
18498 tooltip.position( $.extend( {
18499 of: target
18500 }, this.options.position ) );
18501 }
18502
18503 tooltip.hide();
18504
18505 this._show( tooltip, this.options.show );
18506
18507 // Handle tracking tooltips that are shown with a delay (#8644). As soon
18508 // as the tooltip is visible, position the tooltip using the most recent
18509 // event.
18510 // Adds the check to add the timers only when both delay and track options are set (#14682)
18511 if ( this.options.track && this.options.show && this.options.show.delay ) {
18512 delayedShow = this.delayedShow = setInterval( function() {
18513 if ( tooltip.is( ":visible" ) ) {
18514 position( positionOption.of );
18515 clearInterval( delayedShow );
18516 }
18517 }, $.fx.interval );
18518 }
18519
18520 this._trigger( "open", event, { tooltip: tooltip } );
18521 },
18522
18523 _registerCloseHandlers: function( event, target ) {
18524 var events = {
18525 keyup: function( event ) {
18526 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
18527 var fakeEvent = $.Event( event );
18528 fakeEvent.currentTarget = target[ 0 ];
18529 this.close( fakeEvent, true );
18530 }
18531 }
18532 };
18533
18534 // Only bind remove handler for delegated targets. Non-delegated
18535 // tooltips will handle this in destroy.
18536 if ( target[ 0 ] !== this.element[ 0 ] ) {
18537 events.remove = function() {
18538 this._removeTooltip( this._find( target ).tooltip );
18539 };
18540 }
18541
18542 if ( !event || event.type === "mouseover" ) {
18543 events.mouseleave = "close";
18544 }
18545 if ( !event || event.type === "focusin" ) {
18546 events.focusout = "close";
18547 }
18548 this._on( true, target, events );
18549 },
18550
18551 close: function( event ) {
18552 var tooltip,
18553 that = this,
18554 target = $( event ? event.currentTarget : this.element ),
18555 tooltipData = this._find( target );
18556
18557 // The tooltip may already be closed
18558 if ( !tooltipData ) {
18559
18560 // We set ui-tooltip-open immediately upon open (in open()), but only set the
18561 // additional data once there's actually content to show (in _open()). So even if the
18562 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
18563 // the period between open() and _open().
18564 target.removeData( "ui-tooltip-open" );
18565 return;
18566 }
18567
18568 tooltip = tooltipData.tooltip;
18569
18570 // Disabling closes the tooltip, so we need to track when we're closing
18571 // to avoid an infinite loop in case the tooltip becomes disabled on close
18572 if ( tooltipData.closing ) {
18573 return;
18574 }
18575
18576 // Clear the interval for delayed tracking tooltips
18577 clearInterval( this.delayedShow );
18578
18579 // Only set title if we had one before (see comment in _open())
18580 // If the title attribute has changed since open(), don't restore
18581 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
18582 target.attr( "title", target.data( "ui-tooltip-title" ) );
18583 }
18584
18585 this._removeDescribedBy( target );
18586
18587 tooltipData.hiding = true;
18588 tooltip.stop( true );
18589 this._hide( tooltip, this.options.hide, function() {
18590 that._removeTooltip( $( this ) );
18591 } );
18592
18593 target.removeData( "ui-tooltip-open" );
18594 this._off( target, "mouseleave focusout keyup" );
18595
18596 // Remove 'remove' binding only on delegated targets
18597 if ( target[ 0 ] !== this.element[ 0 ] ) {
18598 this._off( target, "remove" );
18599 }
18600 this._off( this.document, "mousemove" );
18601
18602 if ( event && event.type === "mouseleave" ) {
18603 $.each( this.parents, function( id, parent ) {
18604 $( parent.element ).attr( "title", parent.title );
18605 delete that.parents[ id ];
18606 } );
18607 }
18608
18609 tooltipData.closing = true;
18610 this._trigger( "close", event, { tooltip: tooltip } );
18611 if ( !tooltipData.hiding ) {
18612 tooltipData.closing = false;
18613 }
18614 },
18615
18616 _tooltip: function( element ) {
18617 var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
18618 content = $( "<div>" ).appendTo( tooltip ),
18619 id = tooltip.uniqueId().attr( "id" );
18620
18621 this._addClass( content, "ui-tooltip-content" );
18622 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
18623
18624 tooltip.appendTo( this._appendTo( element ) );
18625
18626 return this.tooltips[ id ] = {
18627 element: element,
18628 tooltip: tooltip
18629 };
18630 },
18631
18632 _find: function( target ) {
18633 var id = target.data( "ui-tooltip-id" );
18634 return id ? this.tooltips[ id ] : null;
18635 },
18636
18637 _removeTooltip: function( tooltip ) {
18638 tooltip.remove();
18639 delete this.tooltips[ tooltip.attr( "id" ) ];
18640 },
18641
18642 _appendTo: function( target ) {
18643 var element = target.closest( ".ui-front, dialog" );
18644
18645 if ( !element.length ) {
18646 element = this.document[ 0 ].body;
18647 }
18648
18649 return element;
18650 },
18651
18652 _destroy: function() {
18653 var that = this;
18654
18655 // Close open tooltips
18656 $.each( this.tooltips, function( id, tooltipData ) {
18657
18658 // Delegate to close method to handle common cleanup
18659 var event = $.Event( "blur" ),
18660 element = tooltipData.element;
18661 event.target = event.currentTarget = element[ 0 ];
18662 that.close( event, true );
18663
18664 // Remove immediately; destroying an open tooltip doesn't use the
18665 // hide animation
18666 $( "#" + id ).remove();
18667
18668 // Restore the title
18669 if ( element.data( "ui-tooltip-title" ) ) {
18670
18671 // If the title attribute has changed since open(), don't restore
18672 if ( !element.attr( "title" ) ) {
18673 element.attr( "title", element.data( "ui-tooltip-title" ) );
18674 }
18675 element.removeData( "ui-tooltip-title" );
18676 }
18677 } );
18678 this.liveRegion.remove();
18679 }
18680 } );
18681
18682 // DEPRECATED
18683 // TODO: Switch return back to widget declaration at top of file when this is removed
18684 if ( $.uiBackCompat !== false ) {
18685
18686 // Backcompat for tooltipClass option
18687 $.widget( "ui.tooltip", $.ui.tooltip, {
18688 options: {
18689 tooltipClass: null
18690 },
18691 _tooltip: function() {
18692 var tooltipData = this._superApply( arguments );
18693 if ( this.options.tooltipClass ) {
18694 tooltipData.tooltip.addClass( this.options.tooltipClass );
18695 }
18696 return tooltipData;
18697 }
18698 } );
18699 }
18700
18701 var widgetsTooltip = $.ui.tooltip;
18702
18703
18704
18705
18706 }));