]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/static/AdminLTE-2.3.7/plugins/jQueryUI/jquery-ui.js
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / pybind / mgr / dashboard / static / AdminLTE-2.3.7 / plugins / jQueryUI / jquery-ui.js
1 /*! jQuery UI - v1.11.4 - 2015-03-11
2 * http://jqueryui.com
3 * Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js
4 * Copyright 2015 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 * jQuery UI Core 1.11.4
19 * http://jqueryui.com
20 *
21 * Copyright jQuery Foundation and other contributors
22 * Released under the MIT license.
23 * http://jquery.org/license
24 *
25 * http://api.jqueryui.com/category/ui-core/
26 */
27
28
29 // $.ui might exist from components with no dependencies, e.g., $.ui.position
30 $.ui = $.ui || {};
31
32 $.extend( $.ui, {
33 version: "1.11.4",
34
35 keyCode: {
36 BACKSPACE: 8,
37 COMMA: 188,
38 DELETE: 46,
39 DOWN: 40,
40 END: 35,
41 ENTER: 13,
42 ESCAPE: 27,
43 HOME: 36,
44 LEFT: 37,
45 PAGE_DOWN: 34,
46 PAGE_UP: 33,
47 PERIOD: 190,
48 RIGHT: 39,
49 SPACE: 32,
50 TAB: 9,
51 UP: 38
52 }
53 });
54
55 // plugins
56 $.fn.extend({
57 scrollParent: function( includeHidden ) {
58 var position = this.css( "position" ),
59 excludeStaticParent = position === "absolute",
60 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
61 scrollParent = this.parents().filter( function() {
62 var parent = $( this );
63 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
64 return false;
65 }
66 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
67 }).eq( 0 );
68
69 return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
70 },
71
72 uniqueId: (function() {
73 var uuid = 0;
74
75 return function() {
76 return this.each(function() {
77 if ( !this.id ) {
78 this.id = "ui-id-" + ( ++uuid );
79 }
80 });
81 };
82 })(),
83
84 removeUniqueId: function() {
85 return this.each(function() {
86 if ( /^ui-id-\d+$/.test( this.id ) ) {
87 $( this ).removeAttr( "id" );
88 }
89 });
90 }
91 });
92
93 // selectors
94 function focusable( element, isTabIndexNotNaN ) {
95 var map, mapName, img,
96 nodeName = element.nodeName.toLowerCase();
97 if ( "area" === nodeName ) {
98 map = element.parentNode;
99 mapName = map.name;
100 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
101 return false;
102 }
103 img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
104 return !!img && visible( img );
105 }
106 return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ?
107 !element.disabled :
108 "a" === nodeName ?
109 element.href || isTabIndexNotNaN :
110 isTabIndexNotNaN) &&
111 // the element and all of its ancestors must be visible
112 visible( element );
113 }
114
115 function visible( element ) {
116 return $.expr.filters.visible( element ) &&
117 !$( element ).parents().addBack().filter(function() {
118 return $.css( this, "visibility" ) === "hidden";
119 }).length;
120 }
121
122 $.extend( $.expr[ ":" ], {
123 data: $.expr.createPseudo ?
124 $.expr.createPseudo(function( dataName ) {
125 return function( elem ) {
126 return !!$.data( elem, dataName );
127 };
128 }) :
129 // support: jQuery <1.8
130 function( elem, i, match ) {
131 return !!$.data( elem, match[ 3 ] );
132 },
133
134 focusable: function( element ) {
135 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
136 },
137
138 tabbable: function( element ) {
139 var tabIndex = $.attr( element, "tabindex" ),
140 isTabIndexNaN = isNaN( tabIndex );
141 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
142 }
143 });
144
145 // support: jQuery <1.8
146 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
147 $.each( [ "Width", "Height" ], function( i, name ) {
148 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
149 type = name.toLowerCase(),
150 orig = {
151 innerWidth: $.fn.innerWidth,
152 innerHeight: $.fn.innerHeight,
153 outerWidth: $.fn.outerWidth,
154 outerHeight: $.fn.outerHeight
155 };
156
157 function reduce( elem, size, border, margin ) {
158 $.each( side, function() {
159 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
160 if ( border ) {
161 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
162 }
163 if ( margin ) {
164 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
165 }
166 });
167 return size;
168 }
169
170 $.fn[ "inner" + name ] = function( size ) {
171 if ( size === undefined ) {
172 return orig[ "inner" + name ].call( this );
173 }
174
175 return this.each(function() {
176 $( this ).css( type, reduce( this, size ) + "px" );
177 });
178 };
179
180 $.fn[ "outer" + name] = function( size, margin ) {
181 if ( typeof size !== "number" ) {
182 return orig[ "outer" + name ].call( this, size );
183 }
184
185 return this.each(function() {
186 $( this).css( type, reduce( this, size, true, margin ) + "px" );
187 });
188 };
189 });
190 }
191
192 // support: jQuery <1.8
193 if ( !$.fn.addBack ) {
194 $.fn.addBack = function( selector ) {
195 return this.add( selector == null ?
196 this.prevObject : this.prevObject.filter( selector )
197 );
198 };
199 }
200
201 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
202 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
203 $.fn.removeData = (function( removeData ) {
204 return function( key ) {
205 if ( arguments.length ) {
206 return removeData.call( this, $.camelCase( key ) );
207 } else {
208 return removeData.call( this );
209 }
210 };
211 })( $.fn.removeData );
212 }
213
214 // deprecated
215 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
216
217 $.fn.extend({
218 focus: (function( orig ) {
219 return function( delay, fn ) {
220 return typeof delay === "number" ?
221 this.each(function() {
222 var elem = this;
223 setTimeout(function() {
224 $( elem ).focus();
225 if ( fn ) {
226 fn.call( elem );
227 }
228 }, delay );
229 }) :
230 orig.apply( this, arguments );
231 };
232 })( $.fn.focus ),
233
234 disableSelection: (function() {
235 var eventType = "onselectstart" in document.createElement( "div" ) ?
236 "selectstart" :
237 "mousedown";
238
239 return function() {
240 return this.bind( eventType + ".ui-disableSelection", function( event ) {
241 event.preventDefault();
242 });
243 };
244 })(),
245
246 enableSelection: function() {
247 return this.unbind( ".ui-disableSelection" );
248 },
249
250 zIndex: function( zIndex ) {
251 if ( zIndex !== undefined ) {
252 return this.css( "zIndex", zIndex );
253 }
254
255 if ( this.length ) {
256 var elem = $( this[ 0 ] ), position, value;
257 while ( elem.length && elem[ 0 ] !== document ) {
258 // Ignore z-index if position is set to a value where z-index is ignored by the browser
259 // This makes behavior of this function consistent across browsers
260 // WebKit always returns auto if the element is positioned
261 position = elem.css( "position" );
262 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
263 // IE returns 0 when zIndex is not specified
264 // other browsers return a string
265 // we ignore the case of nested elements with an explicit value of 0
266 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
267 value = parseInt( elem.css( "zIndex" ), 10 );
268 if ( !isNaN( value ) && value !== 0 ) {
269 return value;
270 }
271 }
272 elem = elem.parent();
273 }
274 }
275
276 return 0;
277 }
278 });
279
280 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
281 $.ui.plugin = {
282 add: function( module, option, set ) {
283 var i,
284 proto = $.ui[ module ].prototype;
285 for ( i in set ) {
286 proto.plugins[ i ] = proto.plugins[ i ] || [];
287 proto.plugins[ i ].push( [ option, set[ i ] ] );
288 }
289 },
290 call: function( instance, name, args, allowDisconnected ) {
291 var i,
292 set = instance.plugins[ name ];
293
294 if ( !set ) {
295 return;
296 }
297
298 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
299 return;
300 }
301
302 for ( i = 0; i < set.length; i++ ) {
303 if ( instance.options[ set[ i ][ 0 ] ] ) {
304 set[ i ][ 1 ].apply( instance.element, args );
305 }
306 }
307 }
308 };
309
310
311 /*!
312 * jQuery UI Widget 1.11.4
313 * http://jqueryui.com
314 *
315 * Copyright jQuery Foundation and other contributors
316 * Released under the MIT license.
317 * http://jquery.org/license
318 *
319 * http://api.jqueryui.com/jQuery.widget/
320 */
321
322
323 var widget_uuid = 0,
324 widget_slice = Array.prototype.slice;
325
326 $.cleanData = (function( orig ) {
327 return function( elems ) {
328 var events, elem, i;
329 for ( i = 0; (elem = elems[i]) != null; i++ ) {
330 try {
331
332 // Only trigger remove when necessary to save time
333 events = $._data( elem, "events" );
334 if ( events && events.remove ) {
335 $( elem ).triggerHandler( "remove" );
336 }
337
338 // http://bugs.jquery.com/ticket/8235
339 } catch ( e ) {}
340 }
341 orig( elems );
342 };
343 })( $.cleanData );
344
345 $.widget = function( name, base, prototype ) {
346 var fullName, existingConstructor, constructor, basePrototype,
347 // proxiedPrototype allows the provided prototype to remain unmodified
348 // so that it can be used as a mixin for multiple widgets (#8876)
349 proxiedPrototype = {},
350 namespace = name.split( "." )[ 0 ];
351
352 name = name.split( "." )[ 1 ];
353 fullName = namespace + "-" + name;
354
355 if ( !prototype ) {
356 prototype = base;
357 base = $.Widget;
358 }
359
360 // create selector for plugin
361 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
362 return !!$.data( elem, fullName );
363 };
364
365 $[ namespace ] = $[ namespace ] || {};
366 existingConstructor = $[ namespace ][ name ];
367 constructor = $[ namespace ][ name ] = function( options, element ) {
368 // allow instantiation without "new" keyword
369 if ( !this._createWidget ) {
370 return new constructor( options, element );
371 }
372
373 // allow instantiation without initializing for simple inheritance
374 // must use "new" keyword (the code above always passes args)
375 if ( arguments.length ) {
376 this._createWidget( options, element );
377 }
378 };
379 // extend with the existing constructor to carry over any static properties
380 $.extend( constructor, existingConstructor, {
381 version: prototype.version,
382 // copy the object used to create the prototype in case we need to
383 // redefine the widget later
384 _proto: $.extend( {}, prototype ),
385 // track widgets that inherit from this widget in case this widget is
386 // redefined after a widget inherits from it
387 _childConstructors: []
388 });
389
390 basePrototype = new base();
391 // we need to make the options hash a property directly on the new instance
392 // otherwise we'll modify the options hash on the prototype that we're
393 // inheriting from
394 basePrototype.options = $.widget.extend( {}, basePrototype.options );
395 $.each( prototype, function( prop, value ) {
396 if ( !$.isFunction( value ) ) {
397 proxiedPrototype[ prop ] = value;
398 return;
399 }
400 proxiedPrototype[ prop ] = (function() {
401 var _super = function() {
402 return base.prototype[ prop ].apply( this, arguments );
403 },
404 _superApply = function( args ) {
405 return base.prototype[ prop ].apply( this, args );
406 };
407 return function() {
408 var __super = this._super,
409 __superApply = this._superApply,
410 returnValue;
411
412 this._super = _super;
413 this._superApply = _superApply;
414
415 returnValue = value.apply( this, arguments );
416
417 this._super = __super;
418 this._superApply = __superApply;
419
420 return returnValue;
421 };
422 })();
423 });
424 constructor.prototype = $.widget.extend( basePrototype, {
425 // TODO: remove support for widgetEventPrefix
426 // always use the name + a colon as the prefix, e.g., draggable:start
427 // don't prefix for widgets that aren't DOM-based
428 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
429 }, proxiedPrototype, {
430 constructor: constructor,
431 namespace: namespace,
432 widgetName: name,
433 widgetFullName: fullName
434 });
435
436 // If this widget is being redefined then we need to find all widgets that
437 // are inheriting from it and redefine all of them so that they inherit from
438 // the new version of this widget. We're essentially trying to replace one
439 // level in the prototype chain.
440 if ( existingConstructor ) {
441 $.each( existingConstructor._childConstructors, function( i, child ) {
442 var childPrototype = child.prototype;
443
444 // redefine the child widget using the same prototype that was
445 // originally used, but inherit from the new version of the base
446 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
447 });
448 // remove the list of existing child constructors from the old constructor
449 // so the old child constructors can be garbage collected
450 delete existingConstructor._childConstructors;
451 } else {
452 base._childConstructors.push( constructor );
453 }
454
455 $.widget.bridge( name, constructor );
456
457 return constructor;
458 };
459
460 $.widget.extend = function( target ) {
461 var input = widget_slice.call( arguments, 1 ),
462 inputIndex = 0,
463 inputLength = input.length,
464 key,
465 value;
466 for ( ; inputIndex < inputLength; inputIndex++ ) {
467 for ( key in input[ inputIndex ] ) {
468 value = input[ inputIndex ][ key ];
469 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
470 // Clone objects
471 if ( $.isPlainObject( value ) ) {
472 target[ key ] = $.isPlainObject( target[ key ] ) ?
473 $.widget.extend( {}, target[ key ], value ) :
474 // Don't extend strings, arrays, etc. with objects
475 $.widget.extend( {}, value );
476 // Copy everything else by reference
477 } else {
478 target[ key ] = value;
479 }
480 }
481 }
482 }
483 return target;
484 };
485
486 $.widget.bridge = function( name, object ) {
487 var fullName = object.prototype.widgetFullName || name;
488 $.fn[ name ] = function( options ) {
489 var isMethodCall = typeof options === "string",
490 args = widget_slice.call( arguments, 1 ),
491 returnValue = this;
492
493 if ( isMethodCall ) {
494 this.each(function() {
495 var methodValue,
496 instance = $.data( this, fullName );
497 if ( options === "instance" ) {
498 returnValue = instance;
499 return false;
500 }
501 if ( !instance ) {
502 return $.error( "cannot call methods on " + name + " prior to initialization; " +
503 "attempted to call method '" + options + "'" );
504 }
505 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
506 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
507 }
508 methodValue = instance[ options ].apply( instance, args );
509 if ( methodValue !== instance && methodValue !== undefined ) {
510 returnValue = methodValue && methodValue.jquery ?
511 returnValue.pushStack( methodValue.get() ) :
512 methodValue;
513 return false;
514 }
515 });
516 } else {
517
518 // Allow multiple hashes to be passed on init
519 if ( args.length ) {
520 options = $.widget.extend.apply( null, [ options ].concat(args) );
521 }
522
523 this.each(function() {
524 var instance = $.data( this, fullName );
525 if ( instance ) {
526 instance.option( options || {} );
527 if ( instance._init ) {
528 instance._init();
529 }
530 } else {
531 $.data( this, fullName, new object( options, this ) );
532 }
533 });
534 }
535
536 return returnValue;
537 };
538 };
539
540 $.Widget = function( /* options, element */ ) {};
541 $.Widget._childConstructors = [];
542
543 $.Widget.prototype = {
544 widgetName: "widget",
545 widgetEventPrefix: "",
546 defaultElement: "<div>",
547 options: {
548 disabled: false,
549
550 // callbacks
551 create: null
552 },
553 _createWidget: function( options, element ) {
554 element = $( element || this.defaultElement || this )[ 0 ];
555 this.element = $( element );
556 this.uuid = widget_uuid++;
557 this.eventNamespace = "." + this.widgetName + this.uuid;
558
559 this.bindings = $();
560 this.hoverable = $();
561 this.focusable = $();
562
563 if ( element !== this ) {
564 $.data( element, this.widgetFullName, this );
565 this._on( true, this.element, {
566 remove: function( event ) {
567 if ( event.target === element ) {
568 this.destroy();
569 }
570 }
571 });
572 this.document = $( element.style ?
573 // element within the document
574 element.ownerDocument :
575 // element is window or document
576 element.document || element );
577 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
578 }
579
580 this.options = $.widget.extend( {},
581 this.options,
582 this._getCreateOptions(),
583 options );
584
585 this._create();
586 this._trigger( "create", null, this._getCreateEventData() );
587 this._init();
588 },
589 _getCreateOptions: $.noop,
590 _getCreateEventData: $.noop,
591 _create: $.noop,
592 _init: $.noop,
593
594 destroy: function() {
595 this._destroy();
596 // we can probably remove the unbind calls in 2.0
597 // all event bindings should go through this._on()
598 this.element
599 .unbind( this.eventNamespace )
600 .removeData( this.widgetFullName )
601 // support: jquery <1.6.3
602 // http://bugs.jquery.com/ticket/9413
603 .removeData( $.camelCase( this.widgetFullName ) );
604 this.widget()
605 .unbind( this.eventNamespace )
606 .removeAttr( "aria-disabled" )
607 .removeClass(
608 this.widgetFullName + "-disabled " +
609 "ui-state-disabled" );
610
611 // clean up events and states
612 this.bindings.unbind( this.eventNamespace );
613 this.hoverable.removeClass( "ui-state-hover" );
614 this.focusable.removeClass( "ui-state-focus" );
615 },
616 _destroy: $.noop,
617
618 widget: function() {
619 return this.element;
620 },
621
622 option: function( key, value ) {
623 var options = key,
624 parts,
625 curOption,
626 i;
627
628 if ( arguments.length === 0 ) {
629 // don't return a reference to the internal hash
630 return $.widget.extend( {}, this.options );
631 }
632
633 if ( typeof key === "string" ) {
634 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
635 options = {};
636 parts = key.split( "." );
637 key = parts.shift();
638 if ( parts.length ) {
639 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
640 for ( i = 0; i < parts.length - 1; i++ ) {
641 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
642 curOption = curOption[ parts[ i ] ];
643 }
644 key = parts.pop();
645 if ( arguments.length === 1 ) {
646 return curOption[ key ] === undefined ? null : curOption[ key ];
647 }
648 curOption[ key ] = value;
649 } else {
650 if ( arguments.length === 1 ) {
651 return this.options[ key ] === undefined ? null : this.options[ key ];
652 }
653 options[ key ] = value;
654 }
655 }
656
657 this._setOptions( options );
658
659 return this;
660 },
661 _setOptions: function( options ) {
662 var key;
663
664 for ( key in options ) {
665 this._setOption( key, options[ key ] );
666 }
667
668 return this;
669 },
670 _setOption: function( key, value ) {
671 this.options[ key ] = value;
672
673 if ( key === "disabled" ) {
674 this.widget()
675 .toggleClass( this.widgetFullName + "-disabled", !!value );
676
677 // If the widget is becoming disabled, then nothing is interactive
678 if ( value ) {
679 this.hoverable.removeClass( "ui-state-hover" );
680 this.focusable.removeClass( "ui-state-focus" );
681 }
682 }
683
684 return this;
685 },
686
687 enable: function() {
688 return this._setOptions({ disabled: false });
689 },
690 disable: function() {
691 return this._setOptions({ disabled: true });
692 },
693
694 _on: function( suppressDisabledCheck, element, handlers ) {
695 var delegateElement,
696 instance = this;
697
698 // no suppressDisabledCheck flag, shuffle arguments
699 if ( typeof suppressDisabledCheck !== "boolean" ) {
700 handlers = element;
701 element = suppressDisabledCheck;
702 suppressDisabledCheck = false;
703 }
704
705 // no element argument, shuffle and use this.element
706 if ( !handlers ) {
707 handlers = element;
708 element = this.element;
709 delegateElement = this.widget();
710 } else {
711 element = delegateElement = $( element );
712 this.bindings = this.bindings.add( element );
713 }
714
715 $.each( handlers, function( event, handler ) {
716 function handlerProxy() {
717 // allow widgets to customize the disabled handling
718 // - disabled as an array instead of boolean
719 // - disabled class as method for disabling individual parts
720 if ( !suppressDisabledCheck &&
721 ( instance.options.disabled === true ||
722 $( this ).hasClass( "ui-state-disabled" ) ) ) {
723 return;
724 }
725 return ( typeof handler === "string" ? instance[ handler ] : handler )
726 .apply( instance, arguments );
727 }
728
729 // copy the guid so direct unbinding works
730 if ( typeof handler !== "string" ) {
731 handlerProxy.guid = handler.guid =
732 handler.guid || handlerProxy.guid || $.guid++;
733 }
734
735 var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
736 eventName = match[1] + instance.eventNamespace,
737 selector = match[2];
738 if ( selector ) {
739 delegateElement.delegate( selector, eventName, handlerProxy );
740 } else {
741 element.bind( eventName, handlerProxy );
742 }
743 });
744 },
745
746 _off: function( element, eventName ) {
747 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
748 this.eventNamespace;
749 element.unbind( eventName ).undelegate( eventName );
750
751 // Clear the stack to avoid memory leaks (#10056)
752 this.bindings = $( this.bindings.not( element ).get() );
753 this.focusable = $( this.focusable.not( element ).get() );
754 this.hoverable = $( this.hoverable.not( element ).get() );
755 },
756
757 _delay: function( handler, delay ) {
758 function handlerProxy() {
759 return ( typeof handler === "string" ? instance[ handler ] : handler )
760 .apply( instance, arguments );
761 }
762 var instance = this;
763 return setTimeout( handlerProxy, delay || 0 );
764 },
765
766 _hoverable: function( element ) {
767 this.hoverable = this.hoverable.add( element );
768 this._on( element, {
769 mouseenter: function( event ) {
770 $( event.currentTarget ).addClass( "ui-state-hover" );
771 },
772 mouseleave: function( event ) {
773 $( event.currentTarget ).removeClass( "ui-state-hover" );
774 }
775 });
776 },
777
778 _focusable: function( element ) {
779 this.focusable = this.focusable.add( element );
780 this._on( element, {
781 focusin: function( event ) {
782 $( event.currentTarget ).addClass( "ui-state-focus" );
783 },
784 focusout: function( event ) {
785 $( event.currentTarget ).removeClass( "ui-state-focus" );
786 }
787 });
788 },
789
790 _trigger: function( type, event, data ) {
791 var prop, orig,
792 callback = this.options[ type ];
793
794 data = data || {};
795 event = $.Event( event );
796 event.type = ( type === this.widgetEventPrefix ?
797 type :
798 this.widgetEventPrefix + type ).toLowerCase();
799 // the original event may come from any element
800 // so we need to reset the target on the new event
801 event.target = this.element[ 0 ];
802
803 // copy original event properties over to the new event
804 orig = event.originalEvent;
805 if ( orig ) {
806 for ( prop in orig ) {
807 if ( !( prop in event ) ) {
808 event[ prop ] = orig[ prop ];
809 }
810 }
811 }
812
813 this.element.trigger( event, data );
814 return !( $.isFunction( callback ) &&
815 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
816 event.isDefaultPrevented() );
817 }
818 };
819
820 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
821 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
822 if ( typeof options === "string" ) {
823 options = { effect: options };
824 }
825 var hasOptions,
826 effectName = !options ?
827 method :
828 options === true || typeof options === "number" ?
829 defaultEffect :
830 options.effect || defaultEffect;
831 options = options || {};
832 if ( typeof options === "number" ) {
833 options = { duration: options };
834 }
835 hasOptions = !$.isEmptyObject( options );
836 options.complete = callback;
837 if ( options.delay ) {
838 element.delay( options.delay );
839 }
840 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
841 element[ method ]( options );
842 } else if ( effectName !== method && element[ effectName ] ) {
843 element[ effectName ]( options.duration, options.easing, callback );
844 } else {
845 element.queue(function( next ) {
846 $( this )[ method ]();
847 if ( callback ) {
848 callback.call( element[ 0 ] );
849 }
850 next();
851 });
852 }
853 };
854 });
855
856 var widget = $.widget;
857
858
859 /*!
860 * jQuery UI Mouse 1.11.4
861 * http://jqueryui.com
862 *
863 * Copyright jQuery Foundation and other contributors
864 * Released under the MIT license.
865 * http://jquery.org/license
866 *
867 * http://api.jqueryui.com/mouse/
868 */
869
870
871 var mouseHandled = false;
872 $( document ).mouseup( function() {
873 mouseHandled = false;
874 });
875
876 var mouse = $.widget("ui.mouse", {
877 version: "1.11.4",
878 options: {
879 cancel: "input,textarea,button,select,option",
880 distance: 1,
881 delay: 0
882 },
883 _mouseInit: function() {
884 var that = this;
885
886 this.element
887 .bind("mousedown." + this.widgetName, function(event) {
888 return that._mouseDown(event);
889 })
890 .bind("click." + this.widgetName, function(event) {
891 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
892 $.removeData(event.target, that.widgetName + ".preventClickEvent");
893 event.stopImmediatePropagation();
894 return false;
895 }
896 });
897
898 this.started = false;
899 },
900
901 // TODO: make sure destroying one instance of mouse doesn't mess with
902 // other instances of mouse
903 _mouseDestroy: function() {
904 this.element.unbind("." + this.widgetName);
905 if ( this._mouseMoveDelegate ) {
906 this.document
907 .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
908 .unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
909 }
910 },
911
912 _mouseDown: function(event) {
913 // don't let more than one widget handle mouseStart
914 if ( mouseHandled ) {
915 return;
916 }
917
918 this._mouseMoved = false;
919
920 // we may have missed mouseup (out of window)
921 (this._mouseStarted && this._mouseUp(event));
922
923 this._mouseDownEvent = event;
924
925 var that = this,
926 btnIsLeft = (event.which === 1),
927 // event.target.nodeName works around a bug in IE 8 with
928 // disabled inputs (#7620)
929 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
930 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
931 return true;
932 }
933
934 this.mouseDelayMet = !this.options.delay;
935 if (!this.mouseDelayMet) {
936 this._mouseDelayTimer = setTimeout(function() {
937 that.mouseDelayMet = true;
938 }, this.options.delay);
939 }
940
941 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
942 this._mouseStarted = (this._mouseStart(event) !== false);
943 if (!this._mouseStarted) {
944 event.preventDefault();
945 return true;
946 }
947 }
948
949 // Click event may never have fired (Gecko & Opera)
950 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
951 $.removeData(event.target, this.widgetName + ".preventClickEvent");
952 }
953
954 // these delegates are required to keep context
955 this._mouseMoveDelegate = function(event) {
956 return that._mouseMove(event);
957 };
958 this._mouseUpDelegate = function(event) {
959 return that._mouseUp(event);
960 };
961
962 this.document
963 .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
964 .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
965
966 event.preventDefault();
967
968 mouseHandled = true;
969 return true;
970 },
971
972 _mouseMove: function(event) {
973 // Only check for mouseups outside the document if you've moved inside the document
974 // at least once. This prevents the firing of mouseup in the case of IE<9, which will
975 // fire a mousemove event if content is placed under the cursor. See #7778
976 // Support: IE <9
977 if ( this._mouseMoved ) {
978 // IE mouseup check - mouseup happened when mouse was out of window
979 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
980 return this._mouseUp(event);
981
982 // Iframe mouseup check - mouseup occurred in another document
983 } else if ( !event.which ) {
984 return this._mouseUp( event );
985 }
986 }
987
988 if ( event.which || event.button ) {
989 this._mouseMoved = true;
990 }
991
992 if (this._mouseStarted) {
993 this._mouseDrag(event);
994 return event.preventDefault();
995 }
996
997 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
998 this._mouseStarted =
999 (this._mouseStart(this._mouseDownEvent, event) !== false);
1000 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
1001 }
1002
1003 return !this._mouseStarted;
1004 },
1005
1006 _mouseUp: function(event) {
1007 this.document
1008 .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
1009 .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
1010
1011 if (this._mouseStarted) {
1012 this._mouseStarted = false;
1013
1014 if (event.target === this._mouseDownEvent.target) {
1015 $.data(event.target, this.widgetName + ".preventClickEvent", true);
1016 }
1017
1018 this._mouseStop(event);
1019 }
1020
1021 mouseHandled = false;
1022 return false;
1023 },
1024
1025 _mouseDistanceMet: function(event) {
1026 return (Math.max(
1027 Math.abs(this._mouseDownEvent.pageX - event.pageX),
1028 Math.abs(this._mouseDownEvent.pageY - event.pageY)
1029 ) >= this.options.distance
1030 );
1031 },
1032
1033 _mouseDelayMet: function(/* event */) {
1034 return this.mouseDelayMet;
1035 },
1036
1037 // These are placeholder methods, to be overriden by extending plugin
1038 _mouseStart: function(/* event */) {},
1039 _mouseDrag: function(/* event */) {},
1040 _mouseStop: function(/* event */) {},
1041 _mouseCapture: function(/* event */) { return true; }
1042 });
1043
1044
1045 /*!
1046 * jQuery UI Position 1.11.4
1047 * http://jqueryui.com
1048 *
1049 * Copyright jQuery Foundation and other contributors
1050 * Released under the MIT license.
1051 * http://jquery.org/license
1052 *
1053 * http://api.jqueryui.com/position/
1054 */
1055
1056 (function() {
1057
1058 $.ui = $.ui || {};
1059
1060 var cachedScrollbarWidth, supportsOffsetFractions,
1061 max = Math.max,
1062 abs = Math.abs,
1063 round = Math.round,
1064 rhorizontal = /left|center|right/,
1065 rvertical = /top|center|bottom/,
1066 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
1067 rposition = /^\w+/,
1068 rpercent = /%$/,
1069 _position = $.fn.position;
1070
1071 function getOffsets( offsets, width, height ) {
1072 return [
1073 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1074 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1075 ];
1076 }
1077
1078 function parseCss( element, property ) {
1079 return parseInt( $.css( element, property ), 10 ) || 0;
1080 }
1081
1082 function getDimensions( elem ) {
1083 var raw = elem[0];
1084 if ( raw.nodeType === 9 ) {
1085 return {
1086 width: elem.width(),
1087 height: elem.height(),
1088 offset: { top: 0, left: 0 }
1089 };
1090 }
1091 if ( $.isWindow( raw ) ) {
1092 return {
1093 width: elem.width(),
1094 height: elem.height(),
1095 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
1096 };
1097 }
1098 if ( raw.preventDefault ) {
1099 return {
1100 width: 0,
1101 height: 0,
1102 offset: { top: raw.pageY, left: raw.pageX }
1103 };
1104 }
1105 return {
1106 width: elem.outerWidth(),
1107 height: elem.outerHeight(),
1108 offset: elem.offset()
1109 };
1110 }
1111
1112 $.position = {
1113 scrollbarWidth: function() {
1114 if ( cachedScrollbarWidth !== undefined ) {
1115 return cachedScrollbarWidth;
1116 }
1117 var w1, w2,
1118 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1119 innerDiv = div.children()[0];
1120
1121 $( "body" ).append( div );
1122 w1 = innerDiv.offsetWidth;
1123 div.css( "overflow", "scroll" );
1124
1125 w2 = innerDiv.offsetWidth;
1126
1127 if ( w1 === w2 ) {
1128 w2 = div[0].clientWidth;
1129 }
1130
1131 div.remove();
1132
1133 return (cachedScrollbarWidth = w1 - w2);
1134 },
1135 getScrollInfo: function( within ) {
1136 var overflowX = within.isWindow || within.isDocument ? "" :
1137 within.element.css( "overflow-x" ),
1138 overflowY = within.isWindow || within.isDocument ? "" :
1139 within.element.css( "overflow-y" ),
1140 hasOverflowX = overflowX === "scroll" ||
1141 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1142 hasOverflowY = overflowY === "scroll" ||
1143 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1144 return {
1145 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
1146 height: hasOverflowX ? $.position.scrollbarWidth() : 0
1147 };
1148 },
1149 getWithinInfo: function( element ) {
1150 var withinElement = $( element || window ),
1151 isWindow = $.isWindow( withinElement[0] ),
1152 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
1153 return {
1154 element: withinElement,
1155 isWindow: isWindow,
1156 isDocument: isDocument,
1157 offset: withinElement.offset() || { left: 0, top: 0 },
1158 scrollLeft: withinElement.scrollLeft(),
1159 scrollTop: withinElement.scrollTop(),
1160
1161 // support: jQuery 1.6.x
1162 // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
1163 width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
1164 height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
1165 };
1166 }
1167 };
1168
1169 $.fn.position = function( options ) {
1170 if ( !options || !options.of ) {
1171 return _position.apply( this, arguments );
1172 }
1173
1174 // make a copy, we don't want to modify arguments
1175 options = $.extend( {}, options );
1176
1177 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
1178 target = $( options.of ),
1179 within = $.position.getWithinInfo( options.within ),
1180 scrollInfo = $.position.getScrollInfo( within ),
1181 collision = ( options.collision || "flip" ).split( " " ),
1182 offsets = {};
1183
1184 dimensions = getDimensions( target );
1185 if ( target[0].preventDefault ) {
1186 // force left top to allow flipping
1187 options.at = "left top";
1188 }
1189 targetWidth = dimensions.width;
1190 targetHeight = dimensions.height;
1191 targetOffset = dimensions.offset;
1192 // clone to reuse original targetOffset later
1193 basePosition = $.extend( {}, targetOffset );
1194
1195 // force my and at to have valid horizontal and vertical positions
1196 // if a value is missing or invalid, it will be converted to center
1197 $.each( [ "my", "at" ], function() {
1198 var pos = ( options[ this ] || "" ).split( " " ),
1199 horizontalOffset,
1200 verticalOffset;
1201
1202 if ( pos.length === 1) {
1203 pos = rhorizontal.test( pos[ 0 ] ) ?
1204 pos.concat( [ "center" ] ) :
1205 rvertical.test( pos[ 0 ] ) ?
1206 [ "center" ].concat( pos ) :
1207 [ "center", "center" ];
1208 }
1209 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1210 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1211
1212 // calculate offsets
1213 horizontalOffset = roffset.exec( pos[ 0 ] );
1214 verticalOffset = roffset.exec( pos[ 1 ] );
1215 offsets[ this ] = [
1216 horizontalOffset ? horizontalOffset[ 0 ] : 0,
1217 verticalOffset ? verticalOffset[ 0 ] : 0
1218 ];
1219
1220 // reduce to just the positions without the offsets
1221 options[ this ] = [
1222 rposition.exec( pos[ 0 ] )[ 0 ],
1223 rposition.exec( pos[ 1 ] )[ 0 ]
1224 ];
1225 });
1226
1227 // normalize collision option
1228 if ( collision.length === 1 ) {
1229 collision[ 1 ] = collision[ 0 ];
1230 }
1231
1232 if ( options.at[ 0 ] === "right" ) {
1233 basePosition.left += targetWidth;
1234 } else if ( options.at[ 0 ] === "center" ) {
1235 basePosition.left += targetWidth / 2;
1236 }
1237
1238 if ( options.at[ 1 ] === "bottom" ) {
1239 basePosition.top += targetHeight;
1240 } else if ( options.at[ 1 ] === "center" ) {
1241 basePosition.top += targetHeight / 2;
1242 }
1243
1244 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1245 basePosition.left += atOffset[ 0 ];
1246 basePosition.top += atOffset[ 1 ];
1247
1248 return this.each(function() {
1249 var collisionPosition, using,
1250 elem = $( this ),
1251 elemWidth = elem.outerWidth(),
1252 elemHeight = elem.outerHeight(),
1253 marginLeft = parseCss( this, "marginLeft" ),
1254 marginTop = parseCss( this, "marginTop" ),
1255 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1256 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1257 position = $.extend( {}, basePosition ),
1258 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1259
1260 if ( options.my[ 0 ] === "right" ) {
1261 position.left -= elemWidth;
1262 } else if ( options.my[ 0 ] === "center" ) {
1263 position.left -= elemWidth / 2;
1264 }
1265
1266 if ( options.my[ 1 ] === "bottom" ) {
1267 position.top -= elemHeight;
1268 } else if ( options.my[ 1 ] === "center" ) {
1269 position.top -= elemHeight / 2;
1270 }
1271
1272 position.left += myOffset[ 0 ];
1273 position.top += myOffset[ 1 ];
1274
1275 // if the browser doesn't support fractions, then round for consistent results
1276 if ( !supportsOffsetFractions ) {
1277 position.left = round( position.left );
1278 position.top = round( position.top );
1279 }
1280
1281 collisionPosition = {
1282 marginLeft: marginLeft,
1283 marginTop: marginTop
1284 };
1285
1286 $.each( [ "left", "top" ], function( i, dir ) {
1287 if ( $.ui.position[ collision[ i ] ] ) {
1288 $.ui.position[ collision[ i ] ][ dir ]( position, {
1289 targetWidth: targetWidth,
1290 targetHeight: targetHeight,
1291 elemWidth: elemWidth,
1292 elemHeight: elemHeight,
1293 collisionPosition: collisionPosition,
1294 collisionWidth: collisionWidth,
1295 collisionHeight: collisionHeight,
1296 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1297 my: options.my,
1298 at: options.at,
1299 within: within,
1300 elem: elem
1301 });
1302 }
1303 });
1304
1305 if ( options.using ) {
1306 // adds feedback as second argument to using callback, if present
1307 using = function( props ) {
1308 var left = targetOffset.left - position.left,
1309 right = left + targetWidth - elemWidth,
1310 top = targetOffset.top - position.top,
1311 bottom = top + targetHeight - elemHeight,
1312 feedback = {
1313 target: {
1314 element: target,
1315 left: targetOffset.left,
1316 top: targetOffset.top,
1317 width: targetWidth,
1318 height: targetHeight
1319 },
1320 element: {
1321 element: elem,
1322 left: position.left,
1323 top: position.top,
1324 width: elemWidth,
1325 height: elemHeight
1326 },
1327 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1328 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1329 };
1330 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1331 feedback.horizontal = "center";
1332 }
1333 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1334 feedback.vertical = "middle";
1335 }
1336 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1337 feedback.important = "horizontal";
1338 } else {
1339 feedback.important = "vertical";
1340 }
1341 options.using.call( this, props, feedback );
1342 };
1343 }
1344
1345 elem.offset( $.extend( position, { using: using } ) );
1346 });
1347 };
1348
1349 $.ui.position = {
1350 fit: {
1351 left: function( position, data ) {
1352 var within = data.within,
1353 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1354 outerWidth = within.width,
1355 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1356 overLeft = withinOffset - collisionPosLeft,
1357 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1358 newOverRight;
1359
1360 // element is wider than within
1361 if ( data.collisionWidth > outerWidth ) {
1362 // element is initially over the left side of within
1363 if ( overLeft > 0 && overRight <= 0 ) {
1364 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1365 position.left += overLeft - newOverRight;
1366 // element is initially over right side of within
1367 } else if ( overRight > 0 && overLeft <= 0 ) {
1368 position.left = withinOffset;
1369 // element is initially over both left and right sides of within
1370 } else {
1371 if ( overLeft > overRight ) {
1372 position.left = withinOffset + outerWidth - data.collisionWidth;
1373 } else {
1374 position.left = withinOffset;
1375 }
1376 }
1377 // too far left -> align with left edge
1378 } else if ( overLeft > 0 ) {
1379 position.left += overLeft;
1380 // too far right -> align with right edge
1381 } else if ( overRight > 0 ) {
1382 position.left -= overRight;
1383 // adjust based on position and margin
1384 } else {
1385 position.left = max( position.left - collisionPosLeft, position.left );
1386 }
1387 },
1388 top: function( position, data ) {
1389 var within = data.within,
1390 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1391 outerHeight = data.within.height,
1392 collisionPosTop = position.top - data.collisionPosition.marginTop,
1393 overTop = withinOffset - collisionPosTop,
1394 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1395 newOverBottom;
1396
1397 // element is taller than within
1398 if ( data.collisionHeight > outerHeight ) {
1399 // element is initially over the top of within
1400 if ( overTop > 0 && overBottom <= 0 ) {
1401 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1402 position.top += overTop - newOverBottom;
1403 // element is initially over bottom of within
1404 } else if ( overBottom > 0 && overTop <= 0 ) {
1405 position.top = withinOffset;
1406 // element is initially over both top and bottom of within
1407 } else {
1408 if ( overTop > overBottom ) {
1409 position.top = withinOffset + outerHeight - data.collisionHeight;
1410 } else {
1411 position.top = withinOffset;
1412 }
1413 }
1414 // too far up -> align with top
1415 } else if ( overTop > 0 ) {
1416 position.top += overTop;
1417 // too far down -> align with bottom edge
1418 } else if ( overBottom > 0 ) {
1419 position.top -= overBottom;
1420 // adjust based on position and margin
1421 } else {
1422 position.top = max( position.top - collisionPosTop, position.top );
1423 }
1424 }
1425 },
1426 flip: {
1427 left: function( position, data ) {
1428 var within = data.within,
1429 withinOffset = within.offset.left + within.scrollLeft,
1430 outerWidth = within.width,
1431 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1432 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1433 overLeft = collisionPosLeft - offsetLeft,
1434 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1435 myOffset = data.my[ 0 ] === "left" ?
1436 -data.elemWidth :
1437 data.my[ 0 ] === "right" ?
1438 data.elemWidth :
1439 0,
1440 atOffset = data.at[ 0 ] === "left" ?
1441 data.targetWidth :
1442 data.at[ 0 ] === "right" ?
1443 -data.targetWidth :
1444 0,
1445 offset = -2 * data.offset[ 0 ],
1446 newOverRight,
1447 newOverLeft;
1448
1449 if ( overLeft < 0 ) {
1450 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1451 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1452 position.left += myOffset + atOffset + offset;
1453 }
1454 } else if ( overRight > 0 ) {
1455 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1456 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1457 position.left += myOffset + atOffset + offset;
1458 }
1459 }
1460 },
1461 top: function( position, data ) {
1462 var within = data.within,
1463 withinOffset = within.offset.top + within.scrollTop,
1464 outerHeight = within.height,
1465 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1466 collisionPosTop = position.top - data.collisionPosition.marginTop,
1467 overTop = collisionPosTop - offsetTop,
1468 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1469 top = data.my[ 1 ] === "top",
1470 myOffset = top ?
1471 -data.elemHeight :
1472 data.my[ 1 ] === "bottom" ?
1473 data.elemHeight :
1474 0,
1475 atOffset = data.at[ 1 ] === "top" ?
1476 data.targetHeight :
1477 data.at[ 1 ] === "bottom" ?
1478 -data.targetHeight :
1479 0,
1480 offset = -2 * data.offset[ 1 ],
1481 newOverTop,
1482 newOverBottom;
1483 if ( overTop < 0 ) {
1484 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1485 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
1486 position.top += myOffset + atOffset + offset;
1487 }
1488 } else if ( overBottom > 0 ) {
1489 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1490 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
1491 position.top += myOffset + atOffset + offset;
1492 }
1493 }
1494 }
1495 },
1496 flipfit: {
1497 left: function() {
1498 $.ui.position.flip.left.apply( this, arguments );
1499 $.ui.position.fit.left.apply( this, arguments );
1500 },
1501 top: function() {
1502 $.ui.position.flip.top.apply( this, arguments );
1503 $.ui.position.fit.top.apply( this, arguments );
1504 }
1505 }
1506 };
1507
1508 // fraction support test
1509 (function() {
1510 var testElement, testElementParent, testElementStyle, offsetLeft, i,
1511 body = document.getElementsByTagName( "body" )[ 0 ],
1512 div = document.createElement( "div" );
1513
1514 //Create a "fake body" for testing based on method used in jQuery.support
1515 testElement = document.createElement( body ? "div" : "body" );
1516 testElementStyle = {
1517 visibility: "hidden",
1518 width: 0,
1519 height: 0,
1520 border: 0,
1521 margin: 0,
1522 background: "none"
1523 };
1524 if ( body ) {
1525 $.extend( testElementStyle, {
1526 position: "absolute",
1527 left: "-1000px",
1528 top: "-1000px"
1529 });
1530 }
1531 for ( i in testElementStyle ) {
1532 testElement.style[ i ] = testElementStyle[ i ];
1533 }
1534 testElement.appendChild( div );
1535 testElementParent = body || document.documentElement;
1536 testElementParent.insertBefore( testElement, testElementParent.firstChild );
1537
1538 div.style.cssText = "position: absolute; left: 10.7432222px;";
1539
1540 offsetLeft = $( div ).offset().left;
1541 supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
1542
1543 testElement.innerHTML = "";
1544 testElementParent.removeChild( testElement );
1545 })();
1546
1547 })();
1548
1549 var position = $.ui.position;
1550
1551
1552 /*!
1553 * jQuery UI Accordion 1.11.4
1554 * http://jqueryui.com
1555 *
1556 * Copyright jQuery Foundation and other contributors
1557 * Released under the MIT license.
1558 * http://jquery.org/license
1559 *
1560 * http://api.jqueryui.com/accordion/
1561 */
1562
1563
1564 var accordion = $.widget( "ui.accordion", {
1565 version: "1.11.4",
1566 options: {
1567 active: 0,
1568 animate: {},
1569 collapsible: false,
1570 event: "click",
1571 header: "> li > :first-child,> :not(li):even",
1572 heightStyle: "auto",
1573 icons: {
1574 activeHeader: "ui-icon-triangle-1-s",
1575 header: "ui-icon-triangle-1-e"
1576 },
1577
1578 // callbacks
1579 activate: null,
1580 beforeActivate: null
1581 },
1582
1583 hideProps: {
1584 borderTopWidth: "hide",
1585 borderBottomWidth: "hide",
1586 paddingTop: "hide",
1587 paddingBottom: "hide",
1588 height: "hide"
1589 },
1590
1591 showProps: {
1592 borderTopWidth: "show",
1593 borderBottomWidth: "show",
1594 paddingTop: "show",
1595 paddingBottom: "show",
1596 height: "show"
1597 },
1598
1599 _create: function() {
1600 var options = this.options;
1601 this.prevShow = this.prevHide = $();
1602 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
1603 // ARIA
1604 .attr( "role", "tablist" );
1605
1606 // don't allow collapsible: false and active: false / null
1607 if ( !options.collapsible && (options.active === false || options.active == null) ) {
1608 options.active = 0;
1609 }
1610
1611 this._processPanels();
1612 // handle negative values
1613 if ( options.active < 0 ) {
1614 options.active += this.headers.length;
1615 }
1616 this._refresh();
1617 },
1618
1619 _getCreateEventData: function() {
1620 return {
1621 header: this.active,
1622 panel: !this.active.length ? $() : this.active.next()
1623 };
1624 },
1625
1626 _createIcons: function() {
1627 var icons = this.options.icons;
1628 if ( icons ) {
1629 $( "<span>" )
1630 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
1631 .prependTo( this.headers );
1632 this.active.children( ".ui-accordion-header-icon" )
1633 .removeClass( icons.header )
1634 .addClass( icons.activeHeader );
1635 this.headers.addClass( "ui-accordion-icons" );
1636 }
1637 },
1638
1639 _destroyIcons: function() {
1640 this.headers
1641 .removeClass( "ui-accordion-icons" )
1642 .children( ".ui-accordion-header-icon" )
1643 .remove();
1644 },
1645
1646 _destroy: function() {
1647 var contents;
1648
1649 // clean up main element
1650 this.element
1651 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
1652 .removeAttr( "role" );
1653
1654 // clean up headers
1655 this.headers
1656 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
1657 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
1658 .removeAttr( "role" )
1659 .removeAttr( "aria-expanded" )
1660 .removeAttr( "aria-selected" )
1661 .removeAttr( "aria-controls" )
1662 .removeAttr( "tabIndex" )
1663 .removeUniqueId();
1664
1665 this._destroyIcons();
1666
1667 // clean up content panels
1668 contents = this.headers.next()
1669 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
1670 "ui-accordion-content ui-accordion-content-active ui-state-disabled" )
1671 .css( "display", "" )
1672 .removeAttr( "role" )
1673 .removeAttr( "aria-hidden" )
1674 .removeAttr( "aria-labelledby" )
1675 .removeUniqueId();
1676
1677 if ( this.options.heightStyle !== "content" ) {
1678 contents.css( "height", "" );
1679 }
1680 },
1681
1682 _setOption: function( key, value ) {
1683 if ( key === "active" ) {
1684 // _activate() will handle invalid values and update this.options
1685 this._activate( value );
1686 return;
1687 }
1688
1689 if ( key === "event" ) {
1690 if ( this.options.event ) {
1691 this._off( this.headers, this.options.event );
1692 }
1693 this._setupEvents( value );
1694 }
1695
1696 this._super( key, value );
1697
1698 // setting collapsible: false while collapsed; open first panel
1699 if ( key === "collapsible" && !value && this.options.active === false ) {
1700 this._activate( 0 );
1701 }
1702
1703 if ( key === "icons" ) {
1704 this._destroyIcons();
1705 if ( value ) {
1706 this._createIcons();
1707 }
1708 }
1709
1710 // #5332 - opacity doesn't cascade to positioned elements in IE
1711 // so we need to add the disabled class to the headers and panels
1712 if ( key === "disabled" ) {
1713 this.element
1714 .toggleClass( "ui-state-disabled", !!value )
1715 .attr( "aria-disabled", value );
1716 this.headers.add( this.headers.next() )
1717 .toggleClass( "ui-state-disabled", !!value );
1718 }
1719 },
1720
1721 _keydown: function( event ) {
1722 if ( event.altKey || event.ctrlKey ) {
1723 return;
1724 }
1725
1726 var keyCode = $.ui.keyCode,
1727 length = this.headers.length,
1728 currentIndex = this.headers.index( event.target ),
1729 toFocus = false;
1730
1731 switch ( event.keyCode ) {
1732 case keyCode.RIGHT:
1733 case keyCode.DOWN:
1734 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
1735 break;
1736 case keyCode.LEFT:
1737 case keyCode.UP:
1738 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
1739 break;
1740 case keyCode.SPACE:
1741 case keyCode.ENTER:
1742 this._eventHandler( event );
1743 break;
1744 case keyCode.HOME:
1745 toFocus = this.headers[ 0 ];
1746 break;
1747 case keyCode.END:
1748 toFocus = this.headers[ length - 1 ];
1749 break;
1750 }
1751
1752 if ( toFocus ) {
1753 $( event.target ).attr( "tabIndex", -1 );
1754 $( toFocus ).attr( "tabIndex", 0 );
1755 toFocus.focus();
1756 event.preventDefault();
1757 }
1758 },
1759
1760 _panelKeyDown: function( event ) {
1761 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
1762 $( event.currentTarget ).prev().focus();
1763 }
1764 },
1765
1766 refresh: function() {
1767 var options = this.options;
1768 this._processPanels();
1769
1770 // was collapsed or no panel
1771 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
1772 options.active = false;
1773 this.active = $();
1774 // active false only when collapsible is true
1775 } else if ( options.active === false ) {
1776 this._activate( 0 );
1777 // was active, but active panel is gone
1778 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
1779 // all remaining panel are disabled
1780 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
1781 options.active = false;
1782 this.active = $();
1783 // activate previous panel
1784 } else {
1785 this._activate( Math.max( 0, options.active - 1 ) );
1786 }
1787 // was active, active panel still exists
1788 } else {
1789 // make sure active index is correct
1790 options.active = this.headers.index( this.active );
1791 }
1792
1793 this._destroyIcons();
1794
1795 this._refresh();
1796 },
1797
1798 _processPanels: function() {
1799 var prevHeaders = this.headers,
1800 prevPanels = this.panels;
1801
1802 this.headers = this.element.find( this.options.header )
1803 .addClass( "ui-accordion-header ui-state-default ui-corner-all" );
1804
1805 this.panels = this.headers.next()
1806 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
1807 .filter( ":not(.ui-accordion-content-active)" )
1808 .hide();
1809
1810 // Avoid memory leaks (#10056)
1811 if ( prevPanels ) {
1812 this._off( prevHeaders.not( this.headers ) );
1813 this._off( prevPanels.not( this.panels ) );
1814 }
1815 },
1816
1817 _refresh: function() {
1818 var maxHeight,
1819 options = this.options,
1820 heightStyle = options.heightStyle,
1821 parent = this.element.parent();
1822
1823 this.active = this._findActive( options.active )
1824 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
1825 .removeClass( "ui-corner-all" );
1826 this.active.next()
1827 .addClass( "ui-accordion-content-active" )
1828 .show();
1829
1830 this.headers
1831 .attr( "role", "tab" )
1832 .each(function() {
1833 var header = $( this ),
1834 headerId = header.uniqueId().attr( "id" ),
1835 panel = header.next(),
1836 panelId = panel.uniqueId().attr( "id" );
1837 header.attr( "aria-controls", panelId );
1838 panel.attr( "aria-labelledby", headerId );
1839 })
1840 .next()
1841 .attr( "role", "tabpanel" );
1842
1843 this.headers
1844 .not( this.active )
1845 .attr({
1846 "aria-selected": "false",
1847 "aria-expanded": "false",
1848 tabIndex: -1
1849 })
1850 .next()
1851 .attr({
1852 "aria-hidden": "true"
1853 })
1854 .hide();
1855
1856 // make sure at least one header is in the tab order
1857 if ( !this.active.length ) {
1858 this.headers.eq( 0 ).attr( "tabIndex", 0 );
1859 } else {
1860 this.active.attr({
1861 "aria-selected": "true",
1862 "aria-expanded": "true",
1863 tabIndex: 0
1864 })
1865 .next()
1866 .attr({
1867 "aria-hidden": "false"
1868 });
1869 }
1870
1871 this._createIcons();
1872
1873 this._setupEvents( options.event );
1874
1875 if ( heightStyle === "fill" ) {
1876 maxHeight = parent.height();
1877 this.element.siblings( ":visible" ).each(function() {
1878 var elem = $( this ),
1879 position = elem.css( "position" );
1880
1881 if ( position === "absolute" || position === "fixed" ) {
1882 return;
1883 }
1884 maxHeight -= elem.outerHeight( true );
1885 });
1886
1887 this.headers.each(function() {
1888 maxHeight -= $( this ).outerHeight( true );
1889 });
1890
1891 this.headers.next()
1892 .each(function() {
1893 $( this ).height( Math.max( 0, maxHeight -
1894 $( this ).innerHeight() + $( this ).height() ) );
1895 })
1896 .css( "overflow", "auto" );
1897 } else if ( heightStyle === "auto" ) {
1898 maxHeight = 0;
1899 this.headers.next()
1900 .each(function() {
1901 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
1902 })
1903 .height( maxHeight );
1904 }
1905 },
1906
1907 _activate: function( index ) {
1908 var active = this._findActive( index )[ 0 ];
1909
1910 // trying to activate the already active panel
1911 if ( active === this.active[ 0 ] ) {
1912 return;
1913 }
1914
1915 // trying to collapse, simulate a click on the currently active header
1916 active = active || this.active[ 0 ];
1917
1918 this._eventHandler({
1919 target: active,
1920 currentTarget: active,
1921 preventDefault: $.noop
1922 });
1923 },
1924
1925 _findActive: function( selector ) {
1926 return typeof selector === "number" ? this.headers.eq( selector ) : $();
1927 },
1928
1929 _setupEvents: function( event ) {
1930 var events = {
1931 keydown: "_keydown"
1932 };
1933 if ( event ) {
1934 $.each( event.split( " " ), function( index, eventName ) {
1935 events[ eventName ] = "_eventHandler";
1936 });
1937 }
1938
1939 this._off( this.headers.add( this.headers.next() ) );
1940 this._on( this.headers, events );
1941 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
1942 this._hoverable( this.headers );
1943 this._focusable( this.headers );
1944 },
1945
1946 _eventHandler: function( event ) {
1947 var options = this.options,
1948 active = this.active,
1949 clicked = $( event.currentTarget ),
1950 clickedIsActive = clicked[ 0 ] === active[ 0 ],
1951 collapsing = clickedIsActive && options.collapsible,
1952 toShow = collapsing ? $() : clicked.next(),
1953 toHide = active.next(),
1954 eventData = {
1955 oldHeader: active,
1956 oldPanel: toHide,
1957 newHeader: collapsing ? $() : clicked,
1958 newPanel: toShow
1959 };
1960
1961 event.preventDefault();
1962
1963 if (
1964 // click on active header, but not collapsible
1965 ( clickedIsActive && !options.collapsible ) ||
1966 // allow canceling activation
1967 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
1968 return;
1969 }
1970
1971 options.active = collapsing ? false : this.headers.index( clicked );
1972
1973 // when the call to ._toggle() comes after the class changes
1974 // it causes a very odd bug in IE 8 (see #6720)
1975 this.active = clickedIsActive ? $() : clicked;
1976 this._toggle( eventData );
1977
1978 // switch classes
1979 // corner classes on the previously active header stay after the animation
1980 active.removeClass( "ui-accordion-header-active ui-state-active" );
1981 if ( options.icons ) {
1982 active.children( ".ui-accordion-header-icon" )
1983 .removeClass( options.icons.activeHeader )
1984 .addClass( options.icons.header );
1985 }
1986
1987 if ( !clickedIsActive ) {
1988 clicked
1989 .removeClass( "ui-corner-all" )
1990 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
1991 if ( options.icons ) {
1992 clicked.children( ".ui-accordion-header-icon" )
1993 .removeClass( options.icons.header )
1994 .addClass( options.icons.activeHeader );
1995 }
1996
1997 clicked
1998 .next()
1999 .addClass( "ui-accordion-content-active" );
2000 }
2001 },
2002
2003 _toggle: function( data ) {
2004 var toShow = data.newPanel,
2005 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
2006
2007 // handle activating a panel during the animation for another activation
2008 this.prevShow.add( this.prevHide ).stop( true, true );
2009 this.prevShow = toShow;
2010 this.prevHide = toHide;
2011
2012 if ( this.options.animate ) {
2013 this._animate( toShow, toHide, data );
2014 } else {
2015 toHide.hide();
2016 toShow.show();
2017 this._toggleComplete( data );
2018 }
2019
2020 toHide.attr({
2021 "aria-hidden": "true"
2022 });
2023 toHide.prev().attr({
2024 "aria-selected": "false",
2025 "aria-expanded": "false"
2026 });
2027 // if we're switching panels, remove the old header from the tab order
2028 // if we're opening from collapsed state, remove the previous header from the tab order
2029 // if we're collapsing, then keep the collapsing header in the tab order
2030 if ( toShow.length && toHide.length ) {
2031 toHide.prev().attr({
2032 "tabIndex": -1,
2033 "aria-expanded": "false"
2034 });
2035 } else if ( toShow.length ) {
2036 this.headers.filter(function() {
2037 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
2038 })
2039 .attr( "tabIndex", -1 );
2040 }
2041
2042 toShow
2043 .attr( "aria-hidden", "false" )
2044 .prev()
2045 .attr({
2046 "aria-selected": "true",
2047 "aria-expanded": "true",
2048 tabIndex: 0
2049 });
2050 },
2051
2052 _animate: function( toShow, toHide, data ) {
2053 var total, easing, duration,
2054 that = this,
2055 adjust = 0,
2056 boxSizing = toShow.css( "box-sizing" ),
2057 down = toShow.length &&
2058 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
2059 animate = this.options.animate || {},
2060 options = down && animate.down || animate,
2061 complete = function() {
2062 that._toggleComplete( data );
2063 };
2064
2065 if ( typeof options === "number" ) {
2066 duration = options;
2067 }
2068 if ( typeof options === "string" ) {
2069 easing = options;
2070 }
2071 // fall back from options to animation in case of partial down settings
2072 easing = easing || options.easing || animate.easing;
2073 duration = duration || options.duration || animate.duration;
2074
2075 if ( !toHide.length ) {
2076 return toShow.animate( this.showProps, duration, easing, complete );
2077 }
2078 if ( !toShow.length ) {
2079 return toHide.animate( this.hideProps, duration, easing, complete );
2080 }
2081
2082 total = toShow.show().outerHeight();
2083 toHide.animate( this.hideProps, {
2084 duration: duration,
2085 easing: easing,
2086 step: function( now, fx ) {
2087 fx.now = Math.round( now );
2088 }
2089 });
2090 toShow
2091 .hide()
2092 .animate( this.showProps, {
2093 duration: duration,
2094 easing: easing,
2095 complete: complete,
2096 step: function( now, fx ) {
2097 fx.now = Math.round( now );
2098 if ( fx.prop !== "height" ) {
2099 if ( boxSizing === "content-box" ) {
2100 adjust += fx.now;
2101 }
2102 } else if ( that.options.heightStyle !== "content" ) {
2103 fx.now = Math.round( total - toHide.outerHeight() - adjust );
2104 adjust = 0;
2105 }
2106 }
2107 });
2108 },
2109
2110 _toggleComplete: function( data ) {
2111 var toHide = data.oldPanel;
2112
2113 toHide
2114 .removeClass( "ui-accordion-content-active" )
2115 .prev()
2116 .removeClass( "ui-corner-top" )
2117 .addClass( "ui-corner-all" );
2118
2119 // Work around for rendering bug in IE (#5421)
2120 if ( toHide.length ) {
2121 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
2122 }
2123 this._trigger( "activate", null, data );
2124 }
2125 });
2126
2127
2128 /*!
2129 * jQuery UI Menu 1.11.4
2130 * http://jqueryui.com
2131 *
2132 * Copyright jQuery Foundation and other contributors
2133 * Released under the MIT license.
2134 * http://jquery.org/license
2135 *
2136 * http://api.jqueryui.com/menu/
2137 */
2138
2139
2140 var menu = $.widget( "ui.menu", {
2141 version: "1.11.4",
2142 defaultElement: "<ul>",
2143 delay: 300,
2144 options: {
2145 icons: {
2146 submenu: "ui-icon-carat-1-e"
2147 },
2148 items: "> *",
2149 menus: "ul",
2150 position: {
2151 my: "left-1 top",
2152 at: "right top"
2153 },
2154 role: "menu",
2155
2156 // callbacks
2157 blur: null,
2158 focus: null,
2159 select: null
2160 },
2161
2162 _create: function() {
2163 this.activeMenu = this.element;
2164
2165 // Flag used to prevent firing of the click handler
2166 // as the event bubbles up through nested menus
2167 this.mouseHandled = false;
2168 this.element
2169 .uniqueId()
2170 .addClass( "ui-menu ui-widget ui-widget-content" )
2171 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
2172 .attr({
2173 role: this.options.role,
2174 tabIndex: 0
2175 });
2176
2177 if ( this.options.disabled ) {
2178 this.element
2179 .addClass( "ui-state-disabled" )
2180 .attr( "aria-disabled", "true" );
2181 }
2182
2183 this._on({
2184 // Prevent focus from sticking to links inside menu after clicking
2185 // them (focus should always stay on UL during navigation).
2186 "mousedown .ui-menu-item": function( event ) {
2187 event.preventDefault();
2188 },
2189 "click .ui-menu-item": function( event ) {
2190 var target = $( event.target );
2191 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
2192 this.select( event );
2193
2194 // Only set the mouseHandled flag if the event will bubble, see #9469.
2195 if ( !event.isPropagationStopped() ) {
2196 this.mouseHandled = true;
2197 }
2198
2199 // Open submenu on click
2200 if ( target.has( ".ui-menu" ).length ) {
2201 this.expand( event );
2202 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
2203
2204 // Redirect focus to the menu
2205 this.element.trigger( "focus", [ true ] );
2206
2207 // If the active item is on the top level, let it stay active.
2208 // Otherwise, blur the active item since it is no longer visible.
2209 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
2210 clearTimeout( this.timer );
2211 }
2212 }
2213 }
2214 },
2215 "mouseenter .ui-menu-item": function( event ) {
2216 // Ignore mouse events while typeahead is active, see #10458.
2217 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
2218 // is over an item in the menu
2219 if ( this.previousFilter ) {
2220 return;
2221 }
2222 var target = $( event.currentTarget );
2223 // Remove ui-state-active class from siblings of the newly focused menu item
2224 // to avoid a jump caused by adjacent elements both having a class with a border
2225 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
2226 this.focus( event, target );
2227 },
2228 mouseleave: "collapseAll",
2229 "mouseleave .ui-menu": "collapseAll",
2230 focus: function( event, keepActiveItem ) {
2231 // If there's already an active item, keep it active
2232 // If not, activate the first item
2233 var item = this.active || this.element.find( this.options.items ).eq( 0 );
2234
2235 if ( !keepActiveItem ) {
2236 this.focus( event, item );
2237 }
2238 },
2239 blur: function( event ) {
2240 this._delay(function() {
2241 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
2242 this.collapseAll( event );
2243 }
2244 });
2245 },
2246 keydown: "_keydown"
2247 });
2248
2249 this.refresh();
2250
2251 // Clicks outside of a menu collapse any open menus
2252 this._on( this.document, {
2253 click: function( event ) {
2254 if ( this._closeOnDocumentClick( event ) ) {
2255 this.collapseAll( event );
2256 }
2257
2258 // Reset the mouseHandled flag
2259 this.mouseHandled = false;
2260 }
2261 });
2262 },
2263
2264 _destroy: function() {
2265 // Destroy (sub)menus
2266 this.element
2267 .removeAttr( "aria-activedescendant" )
2268 .find( ".ui-menu" ).addBack()
2269 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
2270 .removeAttr( "role" )
2271 .removeAttr( "tabIndex" )
2272 .removeAttr( "aria-labelledby" )
2273 .removeAttr( "aria-expanded" )
2274 .removeAttr( "aria-hidden" )
2275 .removeAttr( "aria-disabled" )
2276 .removeUniqueId()
2277 .show();
2278
2279 // Destroy menu items
2280 this.element.find( ".ui-menu-item" )
2281 .removeClass( "ui-menu-item" )
2282 .removeAttr( "role" )
2283 .removeAttr( "aria-disabled" )
2284 .removeUniqueId()
2285 .removeClass( "ui-state-hover" )
2286 .removeAttr( "tabIndex" )
2287 .removeAttr( "role" )
2288 .removeAttr( "aria-haspopup" )
2289 .children().each( function() {
2290 var elem = $( this );
2291 if ( elem.data( "ui-menu-submenu-carat" ) ) {
2292 elem.remove();
2293 }
2294 });
2295
2296 // Destroy menu dividers
2297 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
2298 },
2299
2300 _keydown: function( event ) {
2301 var match, prev, character, skip,
2302 preventDefault = true;
2303
2304 switch ( event.keyCode ) {
2305 case $.ui.keyCode.PAGE_UP:
2306 this.previousPage( event );
2307 break;
2308 case $.ui.keyCode.PAGE_DOWN:
2309 this.nextPage( event );
2310 break;
2311 case $.ui.keyCode.HOME:
2312 this._move( "first", "first", event );
2313 break;
2314 case $.ui.keyCode.END:
2315 this._move( "last", "last", event );
2316 break;
2317 case $.ui.keyCode.UP:
2318 this.previous( event );
2319 break;
2320 case $.ui.keyCode.DOWN:
2321 this.next( event );
2322 break;
2323 case $.ui.keyCode.LEFT:
2324 this.collapse( event );
2325 break;
2326 case $.ui.keyCode.RIGHT:
2327 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
2328 this.expand( event );
2329 }
2330 break;
2331 case $.ui.keyCode.ENTER:
2332 case $.ui.keyCode.SPACE:
2333 this._activate( event );
2334 break;
2335 case $.ui.keyCode.ESCAPE:
2336 this.collapse( event );
2337 break;
2338 default:
2339 preventDefault = false;
2340 prev = this.previousFilter || "";
2341 character = String.fromCharCode( event.keyCode );
2342 skip = false;
2343
2344 clearTimeout( this.filterTimer );
2345
2346 if ( character === prev ) {
2347 skip = true;
2348 } else {
2349 character = prev + character;
2350 }
2351
2352 match = this._filterMenuItems( character );
2353 match = skip && match.index( this.active.next() ) !== -1 ?
2354 this.active.nextAll( ".ui-menu-item" ) :
2355 match;
2356
2357 // If no matches on the current filter, reset to the last character pressed
2358 // to move down the menu to the first item that starts with that character
2359 if ( !match.length ) {
2360 character = String.fromCharCode( event.keyCode );
2361 match = this._filterMenuItems( character );
2362 }
2363
2364 if ( match.length ) {
2365 this.focus( event, match );
2366 this.previousFilter = character;
2367 this.filterTimer = this._delay(function() {
2368 delete this.previousFilter;
2369 }, 1000 );
2370 } else {
2371 delete this.previousFilter;
2372 }
2373 }
2374
2375 if ( preventDefault ) {
2376 event.preventDefault();
2377 }
2378 },
2379
2380 _activate: function( event ) {
2381 if ( !this.active.is( ".ui-state-disabled" ) ) {
2382 if ( this.active.is( "[aria-haspopup='true']" ) ) {
2383 this.expand( event );
2384 } else {
2385 this.select( event );
2386 }
2387 }
2388 },
2389
2390 refresh: function() {
2391 var menus, items,
2392 that = this,
2393 icon = this.options.icons.submenu,
2394 submenus = this.element.find( this.options.menus );
2395
2396 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
2397
2398 // Initialize nested menus
2399 submenus.filter( ":not(.ui-menu)" )
2400 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
2401 .hide()
2402 .attr({
2403 role: this.options.role,
2404 "aria-hidden": "true",
2405 "aria-expanded": "false"
2406 })
2407 .each(function() {
2408 var menu = $( this ),
2409 item = menu.parent(),
2410 submenuCarat = $( "<span>" )
2411 .addClass( "ui-menu-icon ui-icon " + icon )
2412 .data( "ui-menu-submenu-carat", true );
2413
2414 item
2415 .attr( "aria-haspopup", "true" )
2416 .prepend( submenuCarat );
2417 menu.attr( "aria-labelledby", item.attr( "id" ) );
2418 });
2419
2420 menus = submenus.add( this.element );
2421 items = menus.find( this.options.items );
2422
2423 // Initialize menu-items containing spaces and/or dashes only as dividers
2424 items.not( ".ui-menu-item" ).each(function() {
2425 var item = $( this );
2426 if ( that._isDivider( item ) ) {
2427 item.addClass( "ui-widget-content ui-menu-divider" );
2428 }
2429 });
2430
2431 // Don't refresh list items that are already adapted
2432 items.not( ".ui-menu-item, .ui-menu-divider" )
2433 .addClass( "ui-menu-item" )
2434 .uniqueId()
2435 .attr({
2436 tabIndex: -1,
2437 role: this._itemRole()
2438 });
2439
2440 // Add aria-disabled attribute to any disabled menu item
2441 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
2442
2443 // If the active item has been removed, blur the menu
2444 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
2445 this.blur();
2446 }
2447 },
2448
2449 _itemRole: function() {
2450 return {
2451 menu: "menuitem",
2452 listbox: "option"
2453 }[ this.options.role ];
2454 },
2455
2456 _setOption: function( key, value ) {
2457 if ( key === "icons" ) {
2458 this.element.find( ".ui-menu-icon" )
2459 .removeClass( this.options.icons.submenu )
2460 .addClass( value.submenu );
2461 }
2462 if ( key === "disabled" ) {
2463 this.element
2464 .toggleClass( "ui-state-disabled", !!value )
2465 .attr( "aria-disabled", value );
2466 }
2467 this._super( key, value );
2468 },
2469
2470 focus: function( event, item ) {
2471 var nested, focused;
2472 this.blur( event, event && event.type === "focus" );
2473
2474 this._scrollIntoView( item );
2475
2476 this.active = item.first();
2477 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
2478 // Only update aria-activedescendant if there's a role
2479 // otherwise we assume focus is managed elsewhere
2480 if ( this.options.role ) {
2481 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
2482 }
2483
2484 // Highlight active parent menu item, if any
2485 this.active
2486 .parent()
2487 .closest( ".ui-menu-item" )
2488 .addClass( "ui-state-active" );
2489
2490 if ( event && event.type === "keydown" ) {
2491 this._close();
2492 } else {
2493 this.timer = this._delay(function() {
2494 this._close();
2495 }, this.delay );
2496 }
2497
2498 nested = item.children( ".ui-menu" );
2499 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
2500 this._startOpening(nested);
2501 }
2502 this.activeMenu = item.parent();
2503
2504 this._trigger( "focus", event, { item: item } );
2505 },
2506
2507 _scrollIntoView: function( item ) {
2508 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
2509 if ( this._hasScroll() ) {
2510 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
2511 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
2512 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
2513 scroll = this.activeMenu.scrollTop();
2514 elementHeight = this.activeMenu.height();
2515 itemHeight = item.outerHeight();
2516
2517 if ( offset < 0 ) {
2518 this.activeMenu.scrollTop( scroll + offset );
2519 } else if ( offset + itemHeight > elementHeight ) {
2520 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
2521 }
2522 }
2523 },
2524
2525 blur: function( event, fromFocus ) {
2526 if ( !fromFocus ) {
2527 clearTimeout( this.timer );
2528 }
2529
2530 if ( !this.active ) {
2531 return;
2532 }
2533
2534 this.active.removeClass( "ui-state-focus" );
2535 this.active = null;
2536
2537 this._trigger( "blur", event, { item: this.active } );
2538 },
2539
2540 _startOpening: function( submenu ) {
2541 clearTimeout( this.timer );
2542
2543 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
2544 // shift in the submenu position when mousing over the carat icon
2545 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
2546 return;
2547 }
2548
2549 this.timer = this._delay(function() {
2550 this._close();
2551 this._open( submenu );
2552 }, this.delay );
2553 },
2554
2555 _open: function( submenu ) {
2556 var position = $.extend({
2557 of: this.active
2558 }, this.options.position );
2559
2560 clearTimeout( this.timer );
2561 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
2562 .hide()
2563 .attr( "aria-hidden", "true" );
2564
2565 submenu
2566 .show()
2567 .removeAttr( "aria-hidden" )
2568 .attr( "aria-expanded", "true" )
2569 .position( position );
2570 },
2571
2572 collapseAll: function( event, all ) {
2573 clearTimeout( this.timer );
2574 this.timer = this._delay(function() {
2575 // If we were passed an event, look for the submenu that contains the event
2576 var currentMenu = all ? this.element :
2577 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
2578
2579 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
2580 if ( !currentMenu.length ) {
2581 currentMenu = this.element;
2582 }
2583
2584 this._close( currentMenu );
2585
2586 this.blur( event );
2587 this.activeMenu = currentMenu;
2588 }, this.delay );
2589 },
2590
2591 // With no arguments, closes the currently active menu - if nothing is active
2592 // it closes all menus. If passed an argument, it will search for menus BELOW
2593 _close: function( startMenu ) {
2594 if ( !startMenu ) {
2595 startMenu = this.active ? this.active.parent() : this.element;
2596 }
2597
2598 startMenu
2599 .find( ".ui-menu" )
2600 .hide()
2601 .attr( "aria-hidden", "true" )
2602 .attr( "aria-expanded", "false" )
2603 .end()
2604 .find( ".ui-state-active" ).not( ".ui-state-focus" )
2605 .removeClass( "ui-state-active" );
2606 },
2607
2608 _closeOnDocumentClick: function( event ) {
2609 return !$( event.target ).closest( ".ui-menu" ).length;
2610 },
2611
2612 _isDivider: function( item ) {
2613
2614 // Match hyphen, em dash, en dash
2615 return !/[^\-\u2014\u2013\s]/.test( item.text() );
2616 },
2617
2618 collapse: function( event ) {
2619 var newItem = this.active &&
2620 this.active.parent().closest( ".ui-menu-item", this.element );
2621 if ( newItem && newItem.length ) {
2622 this._close();
2623 this.focus( event, newItem );
2624 }
2625 },
2626
2627 expand: function( event ) {
2628 var newItem = this.active &&
2629 this.active
2630 .children( ".ui-menu " )
2631 .find( this.options.items )
2632 .first();
2633
2634 if ( newItem && newItem.length ) {
2635 this._open( newItem.parent() );
2636
2637 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
2638 this._delay(function() {
2639 this.focus( event, newItem );
2640 });
2641 }
2642 },
2643
2644 next: function( event ) {
2645 this._move( "next", "first", event );
2646 },
2647
2648 previous: function( event ) {
2649 this._move( "prev", "last", event );
2650 },
2651
2652 isFirstItem: function() {
2653 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
2654 },
2655
2656 isLastItem: function() {
2657 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
2658 },
2659
2660 _move: function( direction, filter, event ) {
2661 var next;
2662 if ( this.active ) {
2663 if ( direction === "first" || direction === "last" ) {
2664 next = this.active
2665 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
2666 .eq( -1 );
2667 } else {
2668 next = this.active
2669 [ direction + "All" ]( ".ui-menu-item" )
2670 .eq( 0 );
2671 }
2672 }
2673 if ( !next || !next.length || !this.active ) {
2674 next = this.activeMenu.find( this.options.items )[ filter ]();
2675 }
2676
2677 this.focus( event, next );
2678 },
2679
2680 nextPage: function( event ) {
2681 var item, base, height;
2682
2683 if ( !this.active ) {
2684 this.next( event );
2685 return;
2686 }
2687 if ( this.isLastItem() ) {
2688 return;
2689 }
2690 if ( this._hasScroll() ) {
2691 base = this.active.offset().top;
2692 height = this.element.height();
2693 this.active.nextAll( ".ui-menu-item" ).each(function() {
2694 item = $( this );
2695 return item.offset().top - base - height < 0;
2696 });
2697
2698 this.focus( event, item );
2699 } else {
2700 this.focus( event, this.activeMenu.find( this.options.items )
2701 [ !this.active ? "first" : "last" ]() );
2702 }
2703 },
2704
2705 previousPage: function( event ) {
2706 var item, base, height;
2707 if ( !this.active ) {
2708 this.next( event );
2709 return;
2710 }
2711 if ( this.isFirstItem() ) {
2712 return;
2713 }
2714 if ( this._hasScroll() ) {
2715 base = this.active.offset().top;
2716 height = this.element.height();
2717 this.active.prevAll( ".ui-menu-item" ).each(function() {
2718 item = $( this );
2719 return item.offset().top - base + height > 0;
2720 });
2721
2722 this.focus( event, item );
2723 } else {
2724 this.focus( event, this.activeMenu.find( this.options.items ).first() );
2725 }
2726 },
2727
2728 _hasScroll: function() {
2729 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
2730 },
2731
2732 select: function( event ) {
2733 // TODO: It should never be possible to not have an active item at this
2734 // point, but the tests don't trigger mouseenter before click.
2735 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
2736 var ui = { item: this.active };
2737 if ( !this.active.has( ".ui-menu" ).length ) {
2738 this.collapseAll( event, true );
2739 }
2740 this._trigger( "select", event, ui );
2741 },
2742
2743 _filterMenuItems: function(character) {
2744 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
2745 regex = new RegExp( "^" + escapedCharacter, "i" );
2746
2747 return this.activeMenu
2748 .find( this.options.items )
2749
2750 // Only match on items, not dividers or other content (#10571)
2751 .filter( ".ui-menu-item" )
2752 .filter(function() {
2753 return regex.test( $.trim( $( this ).text() ) );
2754 });
2755 }
2756 });
2757
2758
2759 /*!
2760 * jQuery UI Autocomplete 1.11.4
2761 * http://jqueryui.com
2762 *
2763 * Copyright jQuery Foundation and other contributors
2764 * Released under the MIT license.
2765 * http://jquery.org/license
2766 *
2767 * http://api.jqueryui.com/autocomplete/
2768 */
2769
2770
2771 $.widget( "ui.autocomplete", {
2772 version: "1.11.4",
2773 defaultElement: "<input>",
2774 options: {
2775 appendTo: null,
2776 autoFocus: false,
2777 delay: 300,
2778 minLength: 1,
2779 position: {
2780 my: "left top",
2781 at: "left bottom",
2782 collision: "none"
2783 },
2784 source: null,
2785
2786 // callbacks
2787 change: null,
2788 close: null,
2789 focus: null,
2790 open: null,
2791 response: null,
2792 search: null,
2793 select: null
2794 },
2795
2796 requestIndex: 0,
2797 pending: 0,
2798
2799 _create: function() {
2800 // Some browsers only repeat keydown events, not keypress events,
2801 // so we use the suppressKeyPress flag to determine if we've already
2802 // handled the keydown event. #7269
2803 // Unfortunately the code for & in keypress is the same as the up arrow,
2804 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
2805 // events when we know the keydown event was used to modify the
2806 // search term. #7799
2807 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
2808 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
2809 isTextarea = nodeName === "textarea",
2810 isInput = nodeName === "input";
2811
2812 this.isMultiLine =
2813 // Textareas are always multi-line
2814 isTextarea ? true :
2815 // Inputs are always single-line, even if inside a contentEditable element
2816 // IE also treats inputs as contentEditable
2817 isInput ? false :
2818 // All other element types are determined by whether or not they're contentEditable
2819 this.element.prop( "isContentEditable" );
2820
2821 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
2822 this.isNewMenu = true;
2823
2824 this.element
2825 .addClass( "ui-autocomplete-input" )
2826 .attr( "autocomplete", "off" );
2827
2828 this._on( this.element, {
2829 keydown: function( event ) {
2830 if ( this.element.prop( "readOnly" ) ) {
2831 suppressKeyPress = true;
2832 suppressInput = true;
2833 suppressKeyPressRepeat = true;
2834 return;
2835 }
2836
2837 suppressKeyPress = false;
2838 suppressInput = false;
2839 suppressKeyPressRepeat = false;
2840 var keyCode = $.ui.keyCode;
2841 switch ( event.keyCode ) {
2842 case keyCode.PAGE_UP:
2843 suppressKeyPress = true;
2844 this._move( "previousPage", event );
2845 break;
2846 case keyCode.PAGE_DOWN:
2847 suppressKeyPress = true;
2848 this._move( "nextPage", event );
2849 break;
2850 case keyCode.UP:
2851 suppressKeyPress = true;
2852 this._keyEvent( "previous", event );
2853 break;
2854 case keyCode.DOWN:
2855 suppressKeyPress = true;
2856 this._keyEvent( "next", event );
2857 break;
2858 case keyCode.ENTER:
2859 // when menu is open and has focus
2860 if ( this.menu.active ) {
2861 // #6055 - Opera still allows the keypress to occur
2862 // which causes forms to submit
2863 suppressKeyPress = true;
2864 event.preventDefault();
2865 this.menu.select( event );
2866 }
2867 break;
2868 case keyCode.TAB:
2869 if ( this.menu.active ) {
2870 this.menu.select( event );
2871 }
2872 break;
2873 case keyCode.ESCAPE:
2874 if ( this.menu.element.is( ":visible" ) ) {
2875 if ( !this.isMultiLine ) {
2876 this._value( this.term );
2877 }
2878 this.close( event );
2879 // Different browsers have different default behavior for escape
2880 // Single press can mean undo or clear
2881 // Double press in IE means clear the whole form
2882 event.preventDefault();
2883 }
2884 break;
2885 default:
2886 suppressKeyPressRepeat = true;
2887 // search timeout should be triggered before the input value is changed
2888 this._searchTimeout( event );
2889 break;
2890 }
2891 },
2892 keypress: function( event ) {
2893 if ( suppressKeyPress ) {
2894 suppressKeyPress = false;
2895 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
2896 event.preventDefault();
2897 }
2898 return;
2899 }
2900 if ( suppressKeyPressRepeat ) {
2901 return;
2902 }
2903
2904 // replicate some key handlers to allow them to repeat in Firefox and Opera
2905 var keyCode = $.ui.keyCode;
2906 switch ( event.keyCode ) {
2907 case keyCode.PAGE_UP:
2908 this._move( "previousPage", event );
2909 break;
2910 case keyCode.PAGE_DOWN:
2911 this._move( "nextPage", event );
2912 break;
2913 case keyCode.UP:
2914 this._keyEvent( "previous", event );
2915 break;
2916 case keyCode.DOWN:
2917 this._keyEvent( "next", event );
2918 break;
2919 }
2920 },
2921 input: function( event ) {
2922 if ( suppressInput ) {
2923 suppressInput = false;
2924 event.preventDefault();
2925 return;
2926 }
2927 this._searchTimeout( event );
2928 },
2929 focus: function() {
2930 this.selectedItem = null;
2931 this.previous = this._value();
2932 },
2933 blur: function( event ) {
2934 if ( this.cancelBlur ) {
2935 delete this.cancelBlur;
2936 return;
2937 }
2938
2939 clearTimeout( this.searching );
2940 this.close( event );
2941 this._change( event );
2942 }
2943 });
2944
2945 this._initSource();
2946 this.menu = $( "<ul>" )
2947 .addClass( "ui-autocomplete ui-front" )
2948 .appendTo( this._appendTo() )
2949 .menu({
2950 // disable ARIA support, the live region takes care of that
2951 role: null
2952 })
2953 .hide()
2954 .menu( "instance" );
2955
2956 this._on( this.menu.element, {
2957 mousedown: function( event ) {
2958 // prevent moving focus out of the text field
2959 event.preventDefault();
2960
2961 // IE doesn't prevent moving focus even with event.preventDefault()
2962 // so we set a flag to know when we should ignore the blur event
2963 this.cancelBlur = true;
2964 this._delay(function() {
2965 delete this.cancelBlur;
2966 });
2967
2968 // clicking on the scrollbar causes focus to shift to the body
2969 // but we can't detect a mouseup or a click immediately afterward
2970 // so we have to track the next mousedown and close the menu if
2971 // the user clicks somewhere outside of the autocomplete
2972 var menuElement = this.menu.element[ 0 ];
2973 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
2974 this._delay(function() {
2975 var that = this;
2976 this.document.one( "mousedown", function( event ) {
2977 if ( event.target !== that.element[ 0 ] &&
2978 event.target !== menuElement &&
2979 !$.contains( menuElement, event.target ) ) {
2980 that.close();
2981 }
2982 });
2983 });
2984 }
2985 },
2986 menufocus: function( event, ui ) {
2987 var label, item;
2988 // support: Firefox
2989 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
2990 if ( this.isNewMenu ) {
2991 this.isNewMenu = false;
2992 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
2993 this.menu.blur();
2994
2995 this.document.one( "mousemove", function() {
2996 $( event.target ).trigger( event.originalEvent );
2997 });
2998
2999 return;
3000 }
3001 }
3002
3003 item = ui.item.data( "ui-autocomplete-item" );
3004 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
3005 // use value to match what will end up in the input, if it was a key event
3006 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
3007 this._value( item.value );
3008 }
3009 }
3010
3011 // Announce the value in the liveRegion
3012 label = ui.item.attr( "aria-label" ) || item.value;
3013 if ( label && $.trim( label ).length ) {
3014 this.liveRegion.children().hide();
3015 $( "<div>" ).text( label ).appendTo( this.liveRegion );
3016 }
3017 },
3018 menuselect: function( event, ui ) {
3019 var item = ui.item.data( "ui-autocomplete-item" ),
3020 previous = this.previous;
3021
3022 // only trigger when focus was lost (click on menu)
3023 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
3024 this.element.focus();
3025 this.previous = previous;
3026 // #6109 - IE triggers two focus events and the second
3027 // is asynchronous, so we need to reset the previous
3028 // term synchronously and asynchronously :-(
3029 this._delay(function() {
3030 this.previous = previous;
3031 this.selectedItem = item;
3032 });
3033 }
3034
3035 if ( false !== this._trigger( "select", event, { item: item } ) ) {
3036 this._value( item.value );
3037 }
3038 // reset the term after the select event
3039 // this allows custom select handling to work properly
3040 this.term = this._value();
3041
3042 this.close( event );
3043 this.selectedItem = item;
3044 }
3045 });
3046
3047 this.liveRegion = $( "<span>", {
3048 role: "status",
3049 "aria-live": "assertive",
3050 "aria-relevant": "additions"
3051 })
3052 .addClass( "ui-helper-hidden-accessible" )
3053 .appendTo( this.document[ 0 ].body );
3054
3055 // turning off autocomplete prevents the browser from remembering the
3056 // value when navigating through history, so we re-enable autocomplete
3057 // if the page is unloaded before the widget is destroyed. #7790
3058 this._on( this.window, {
3059 beforeunload: function() {
3060 this.element.removeAttr( "autocomplete" );
3061 }
3062 });
3063 },
3064
3065 _destroy: function() {
3066 clearTimeout( this.searching );
3067 this.element
3068 .removeClass( "ui-autocomplete-input" )
3069 .removeAttr( "autocomplete" );
3070 this.menu.element.remove();
3071 this.liveRegion.remove();
3072 },
3073
3074 _setOption: function( key, value ) {
3075 this._super( key, value );
3076 if ( key === "source" ) {
3077 this._initSource();
3078 }
3079 if ( key === "appendTo" ) {
3080 this.menu.element.appendTo( this._appendTo() );
3081 }
3082 if ( key === "disabled" && value && this.xhr ) {
3083 this.xhr.abort();
3084 }
3085 },
3086
3087 _appendTo: function() {
3088 var element = this.options.appendTo;
3089
3090 if ( element ) {
3091 element = element.jquery || element.nodeType ?
3092 $( element ) :
3093 this.document.find( element ).eq( 0 );
3094 }
3095
3096 if ( !element || !element[ 0 ] ) {
3097 element = this.element.closest( ".ui-front" );
3098 }
3099
3100 if ( !element.length ) {
3101 element = this.document[ 0 ].body;
3102 }
3103
3104 return element;
3105 },
3106
3107 _initSource: function() {
3108 var array, url,
3109 that = this;
3110 if ( $.isArray( this.options.source ) ) {
3111 array = this.options.source;
3112 this.source = function( request, response ) {
3113 response( $.ui.autocomplete.filter( array, request.term ) );
3114 };
3115 } else if ( typeof this.options.source === "string" ) {
3116 url = this.options.source;
3117 this.source = function( request, response ) {
3118 if ( that.xhr ) {
3119 that.xhr.abort();
3120 }
3121 that.xhr = $.ajax({
3122 url: url,
3123 data: request,
3124 dataType: "json",
3125 success: function( data ) {
3126 response( data );
3127 },
3128 error: function() {
3129 response([]);
3130 }
3131 });
3132 };
3133 } else {
3134 this.source = this.options.source;
3135 }
3136 },
3137
3138 _searchTimeout: function( event ) {
3139 clearTimeout( this.searching );
3140 this.searching = this._delay(function() {
3141
3142 // Search if the value has changed, or if the user retypes the same value (see #7434)
3143 var equalValues = this.term === this._value(),
3144 menuVisible = this.menu.element.is( ":visible" ),
3145 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
3146
3147 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
3148 this.selectedItem = null;
3149 this.search( null, event );
3150 }
3151 }, this.options.delay );
3152 },
3153
3154 search: function( value, event ) {
3155 value = value != null ? value : this._value();
3156
3157 // always save the actual value, not the one passed as an argument
3158 this.term = this._value();
3159
3160 if ( value.length < this.options.minLength ) {
3161 return this.close( event );
3162 }
3163
3164 if ( this._trigger( "search", event ) === false ) {
3165 return;
3166 }
3167
3168 return this._search( value );
3169 },
3170
3171 _search: function( value ) {
3172 this.pending++;
3173 this.element.addClass( "ui-autocomplete-loading" );
3174 this.cancelSearch = false;
3175
3176 this.source( { term: value }, this._response() );
3177 },
3178
3179 _response: function() {
3180 var index = ++this.requestIndex;
3181
3182 return $.proxy(function( content ) {
3183 if ( index === this.requestIndex ) {
3184 this.__response( content );
3185 }
3186
3187 this.pending--;
3188 if ( !this.pending ) {
3189 this.element.removeClass( "ui-autocomplete-loading" );
3190 }
3191 }, this );
3192 },
3193
3194 __response: function( content ) {
3195 if ( content ) {
3196 content = this._normalize( content );
3197 }
3198 this._trigger( "response", null, { content: content } );
3199 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
3200 this._suggest( content );
3201 this._trigger( "open" );
3202 } else {
3203 // use ._close() instead of .close() so we don't cancel future searches
3204 this._close();
3205 }
3206 },
3207
3208 close: function( event ) {
3209 this.cancelSearch = true;
3210 this._close( event );
3211 },
3212
3213 _close: function( event ) {
3214 if ( this.menu.element.is( ":visible" ) ) {
3215 this.menu.element.hide();
3216 this.menu.blur();
3217 this.isNewMenu = true;
3218 this._trigger( "close", event );
3219 }
3220 },
3221
3222 _change: function( event ) {
3223 if ( this.previous !== this._value() ) {
3224 this._trigger( "change", event, { item: this.selectedItem } );
3225 }
3226 },
3227
3228 _normalize: function( items ) {
3229 // assume all items have the right format when the first item is complete
3230 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
3231 return items;
3232 }
3233 return $.map( items, function( item ) {
3234 if ( typeof item === "string" ) {
3235 return {
3236 label: item,
3237 value: item
3238 };
3239 }
3240 return $.extend( {}, item, {
3241 label: item.label || item.value,
3242 value: item.value || item.label
3243 });
3244 });
3245 },
3246
3247 _suggest: function( items ) {
3248 var ul = this.menu.element.empty();
3249 this._renderMenu( ul, items );
3250 this.isNewMenu = true;
3251 this.menu.refresh();
3252
3253 // size and position menu
3254 ul.show();
3255 this._resizeMenu();
3256 ul.position( $.extend({
3257 of: this.element
3258 }, this.options.position ) );
3259
3260 if ( this.options.autoFocus ) {
3261 this.menu.next();
3262 }
3263 },
3264
3265 _resizeMenu: function() {
3266 var ul = this.menu.element;
3267 ul.outerWidth( Math.max(
3268 // Firefox wraps long text (possibly a rounding bug)
3269 // so we add 1px to avoid the wrapping (#7513)
3270 ul.width( "" ).outerWidth() + 1,
3271 this.element.outerWidth()
3272 ) );
3273 },
3274
3275 _renderMenu: function( ul, items ) {
3276 var that = this;
3277 $.each( items, function( index, item ) {
3278 that._renderItemData( ul, item );
3279 });
3280 },
3281
3282 _renderItemData: function( ul, item ) {
3283 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
3284 },
3285
3286 _renderItem: function( ul, item ) {
3287 return $( "<li>" ).text( item.label ).appendTo( ul );
3288 },
3289
3290 _move: function( direction, event ) {
3291 if ( !this.menu.element.is( ":visible" ) ) {
3292 this.search( null, event );
3293 return;
3294 }
3295 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
3296 this.menu.isLastItem() && /^next/.test( direction ) ) {
3297
3298 if ( !this.isMultiLine ) {
3299 this._value( this.term );
3300 }
3301
3302 this.menu.blur();
3303 return;
3304 }
3305 this.menu[ direction ]( event );
3306 },
3307
3308 widget: function() {
3309 return this.menu.element;
3310 },
3311
3312 _value: function() {
3313 return this.valueMethod.apply( this.element, arguments );
3314 },
3315
3316 _keyEvent: function( keyEvent, event ) {
3317 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
3318 this._move( keyEvent, event );
3319
3320 // prevents moving cursor to beginning/end of the text field in some browsers
3321 event.preventDefault();
3322 }
3323 }
3324 });
3325
3326 $.extend( $.ui.autocomplete, {
3327 escapeRegex: function( value ) {
3328 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
3329 },
3330 filter: function( array, term ) {
3331 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
3332 return $.grep( array, function( value ) {
3333 return matcher.test( value.label || value.value || value );
3334 });
3335 }
3336 });
3337
3338 // live region extension, adding a `messages` option
3339 // NOTE: This is an experimental API. We are still investigating
3340 // a full solution for string manipulation and internationalization.
3341 $.widget( "ui.autocomplete", $.ui.autocomplete, {
3342 options: {
3343 messages: {
3344 noResults: "No search results.",
3345 results: function( amount ) {
3346 return amount + ( amount > 1 ? " results are" : " result is" ) +
3347 " available, use up and down arrow keys to navigate.";
3348 }
3349 }
3350 },
3351
3352 __response: function( content ) {
3353 var message;
3354 this._superApply( arguments );
3355 if ( this.options.disabled || this.cancelSearch ) {
3356 return;
3357 }
3358 if ( content && content.length ) {
3359 message = this.options.messages.results( content.length );
3360 } else {
3361 message = this.options.messages.noResults;
3362 }
3363 this.liveRegion.children().hide();
3364 $( "<div>" ).text( message ).appendTo( this.liveRegion );
3365 }
3366 });
3367
3368 var autocomplete = $.ui.autocomplete;
3369
3370
3371 /*!
3372 * jQuery UI Button 1.11.4
3373 * http://jqueryui.com
3374 *
3375 * Copyright jQuery Foundation and other contributors
3376 * Released under the MIT license.
3377 * http://jquery.org/license
3378 *
3379 * http://api.jqueryui.com/button/
3380 */
3381
3382
3383 var lastActive,
3384 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
3385 typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
3386 formResetHandler = function() {
3387 var form = $( this );
3388 setTimeout(function() {
3389 form.find( ":ui-button" ).button( "refresh" );
3390 }, 1 );
3391 },
3392 radioGroup = function( radio ) {
3393 var name = radio.name,
3394 form = radio.form,
3395 radios = $( [] );
3396 if ( name ) {
3397 name = name.replace( /'/g, "\\'" );
3398 if ( form ) {
3399 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
3400 } else {
3401 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
3402 .filter(function() {
3403 return !this.form;
3404 });
3405 }
3406 }
3407 return radios;
3408 };
3409
3410 $.widget( "ui.button", {
3411 version: "1.11.4",
3412 defaultElement: "<button>",
3413 options: {
3414 disabled: null,
3415 text: true,
3416 label: null,
3417 icons: {
3418 primary: null,
3419 secondary: null
3420 }
3421 },
3422 _create: function() {
3423 this.element.closest( "form" )
3424 .unbind( "reset" + this.eventNamespace )
3425 .bind( "reset" + this.eventNamespace, formResetHandler );
3426
3427 if ( typeof this.options.disabled !== "boolean" ) {
3428 this.options.disabled = !!this.element.prop( "disabled" );
3429 } else {
3430 this.element.prop( "disabled", this.options.disabled );
3431 }
3432
3433 this._determineButtonType();
3434 this.hasTitle = !!this.buttonElement.attr( "title" );
3435
3436 var that = this,
3437 options = this.options,
3438 toggleButton = this.type === "checkbox" || this.type === "radio",
3439 activeClass = !toggleButton ? "ui-state-active" : "";
3440
3441 if ( options.label === null ) {
3442 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
3443 }
3444
3445 this._hoverable( this.buttonElement );
3446
3447 this.buttonElement
3448 .addClass( baseClasses )
3449 .attr( "role", "button" )
3450 .bind( "mouseenter" + this.eventNamespace, function() {
3451 if ( options.disabled ) {
3452 return;
3453 }
3454 if ( this === lastActive ) {
3455 $( this ).addClass( "ui-state-active" );
3456 }
3457 })
3458 .bind( "mouseleave" + this.eventNamespace, function() {
3459 if ( options.disabled ) {
3460 return;
3461 }
3462 $( this ).removeClass( activeClass );
3463 })
3464 .bind( "click" + this.eventNamespace, function( event ) {
3465 if ( options.disabled ) {
3466 event.preventDefault();
3467 event.stopImmediatePropagation();
3468 }
3469 });
3470
3471 // Can't use _focusable() because the element that receives focus
3472 // and the element that gets the ui-state-focus class are different
3473 this._on({
3474 focus: function() {
3475 this.buttonElement.addClass( "ui-state-focus" );
3476 },
3477 blur: function() {
3478 this.buttonElement.removeClass( "ui-state-focus" );
3479 }
3480 });
3481
3482 if ( toggleButton ) {
3483 this.element.bind( "change" + this.eventNamespace, function() {
3484 that.refresh();
3485 });
3486 }
3487
3488 if ( this.type === "checkbox" ) {
3489 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3490 if ( options.disabled ) {
3491 return false;
3492 }
3493 });
3494 } else if ( this.type === "radio" ) {
3495 this.buttonElement.bind( "click" + this.eventNamespace, function() {
3496 if ( options.disabled ) {
3497 return false;
3498 }
3499 $( this ).addClass( "ui-state-active" );
3500 that.buttonElement.attr( "aria-pressed", "true" );
3501
3502 var radio = that.element[ 0 ];
3503 radioGroup( radio )
3504 .not( radio )
3505 .map(function() {
3506 return $( this ).button( "widget" )[ 0 ];
3507 })
3508 .removeClass( "ui-state-active" )
3509 .attr( "aria-pressed", "false" );
3510 });
3511 } else {
3512 this.buttonElement
3513 .bind( "mousedown" + this.eventNamespace, function() {
3514 if ( options.disabled ) {
3515 return false;
3516 }
3517 $( this ).addClass( "ui-state-active" );
3518 lastActive = this;
3519 that.document.one( "mouseup", function() {
3520 lastActive = null;
3521 });
3522 })
3523 .bind( "mouseup" + this.eventNamespace, function() {
3524 if ( options.disabled ) {
3525 return false;
3526 }
3527 $( this ).removeClass( "ui-state-active" );
3528 })
3529 .bind( "keydown" + this.eventNamespace, function(event) {
3530 if ( options.disabled ) {
3531 return false;
3532 }
3533 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
3534 $( this ).addClass( "ui-state-active" );
3535 }
3536 })
3537 // see #8559, we bind to blur here in case the button element loses
3538 // focus between keydown and keyup, it would be left in an "active" state
3539 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
3540 $( this ).removeClass( "ui-state-active" );
3541 });
3542
3543 if ( this.buttonElement.is("a") ) {
3544 this.buttonElement.keyup(function(event) {
3545 if ( event.keyCode === $.ui.keyCode.SPACE ) {
3546 // TODO pass through original event correctly (just as 2nd argument doesn't work)
3547 $( this ).click();
3548 }
3549 });
3550 }
3551 }
3552
3553 this._setOption( "disabled", options.disabled );
3554 this._resetButton();
3555 },
3556
3557 _determineButtonType: function() {
3558 var ancestor, labelSelector, checked;
3559
3560 if ( this.element.is("[type=checkbox]") ) {
3561 this.type = "checkbox";
3562 } else if ( this.element.is("[type=radio]") ) {
3563 this.type = "radio";
3564 } else if ( this.element.is("input") ) {
3565 this.type = "input";
3566 } else {
3567 this.type = "button";
3568 }
3569
3570 if ( this.type === "checkbox" || this.type === "radio" ) {
3571 // we don't search against the document in case the element
3572 // is disconnected from the DOM
3573 ancestor = this.element.parents().last();
3574 labelSelector = "label[for='" + this.element.attr("id") + "']";
3575 this.buttonElement = ancestor.find( labelSelector );
3576 if ( !this.buttonElement.length ) {
3577 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
3578 this.buttonElement = ancestor.filter( labelSelector );
3579 if ( !this.buttonElement.length ) {
3580 this.buttonElement = ancestor.find( labelSelector );
3581 }
3582 }
3583 this.element.addClass( "ui-helper-hidden-accessible" );
3584
3585 checked = this.element.is( ":checked" );
3586 if ( checked ) {
3587 this.buttonElement.addClass( "ui-state-active" );
3588 }
3589 this.buttonElement.prop( "aria-pressed", checked );
3590 } else {
3591 this.buttonElement = this.element;
3592 }
3593 },
3594
3595 widget: function() {
3596 return this.buttonElement;
3597 },
3598
3599 _destroy: function() {
3600 this.element
3601 .removeClass( "ui-helper-hidden-accessible" );
3602 this.buttonElement
3603 .removeClass( baseClasses + " ui-state-active " + typeClasses )
3604 .removeAttr( "role" )
3605 .removeAttr( "aria-pressed" )
3606 .html( this.buttonElement.find(".ui-button-text").html() );
3607
3608 if ( !this.hasTitle ) {
3609 this.buttonElement.removeAttr( "title" );
3610 }
3611 },
3612
3613 _setOption: function( key, value ) {
3614 this._super( key, value );
3615 if ( key === "disabled" ) {
3616 this.widget().toggleClass( "ui-state-disabled", !!value );
3617 this.element.prop( "disabled", !!value );
3618 if ( value ) {
3619 if ( this.type === "checkbox" || this.type === "radio" ) {
3620 this.buttonElement.removeClass( "ui-state-focus" );
3621 } else {
3622 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
3623 }
3624 }
3625 return;
3626 }
3627 this._resetButton();
3628 },
3629
3630 refresh: function() {
3631 //See #8237 & #8828
3632 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
3633
3634 if ( isDisabled !== this.options.disabled ) {
3635 this._setOption( "disabled", isDisabled );
3636 }
3637 if ( this.type === "radio" ) {
3638 radioGroup( this.element[0] ).each(function() {
3639 if ( $( this ).is( ":checked" ) ) {
3640 $( this ).button( "widget" )
3641 .addClass( "ui-state-active" )
3642 .attr( "aria-pressed", "true" );
3643 } else {
3644 $( this ).button( "widget" )
3645 .removeClass( "ui-state-active" )
3646 .attr( "aria-pressed", "false" );
3647 }
3648 });
3649 } else if ( this.type === "checkbox" ) {
3650 if ( this.element.is( ":checked" ) ) {
3651 this.buttonElement
3652 .addClass( "ui-state-active" )
3653 .attr( "aria-pressed", "true" );
3654 } else {
3655 this.buttonElement
3656 .removeClass( "ui-state-active" )
3657 .attr( "aria-pressed", "false" );
3658 }
3659 }
3660 },
3661
3662 _resetButton: function() {
3663 if ( this.type === "input" ) {
3664 if ( this.options.label ) {
3665 this.element.val( this.options.label );
3666 }
3667 return;
3668 }
3669 var buttonElement = this.buttonElement.removeClass( typeClasses ),
3670 buttonText = $( "<span></span>", this.document[0] )
3671 .addClass( "ui-button-text" )
3672 .html( this.options.label )
3673 .appendTo( buttonElement.empty() )
3674 .text(),
3675 icons = this.options.icons,
3676 multipleIcons = icons.primary && icons.secondary,
3677 buttonClasses = [];
3678
3679 if ( icons.primary || icons.secondary ) {
3680 if ( this.options.text ) {
3681 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
3682 }
3683
3684 if ( icons.primary ) {
3685 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
3686 }
3687
3688 if ( icons.secondary ) {
3689 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
3690 }
3691
3692 if ( !this.options.text ) {
3693 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
3694
3695 if ( !this.hasTitle ) {
3696 buttonElement.attr( "title", $.trim( buttonText ) );
3697 }
3698 }
3699 } else {
3700 buttonClasses.push( "ui-button-text-only" );
3701 }
3702 buttonElement.addClass( buttonClasses.join( " " ) );
3703 }
3704 });
3705
3706 $.widget( "ui.buttonset", {
3707 version: "1.11.4",
3708 options: {
3709 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
3710 },
3711
3712 _create: function() {
3713 this.element.addClass( "ui-buttonset" );
3714 },
3715
3716 _init: function() {
3717 this.refresh();
3718 },
3719
3720 _setOption: function( key, value ) {
3721 if ( key === "disabled" ) {
3722 this.buttons.button( "option", key, value );
3723 }
3724
3725 this._super( key, value );
3726 },
3727
3728 refresh: function() {
3729 var rtl = this.element.css( "direction" ) === "rtl",
3730 allButtons = this.element.find( this.options.items ),
3731 existingButtons = allButtons.filter( ":ui-button" );
3732
3733 // Initialize new buttons
3734 allButtons.not( ":ui-button" ).button();
3735
3736 // Refresh existing buttons
3737 existingButtons.button( "refresh" );
3738
3739 this.buttons = allButtons
3740 .map(function() {
3741 return $( this ).button( "widget" )[ 0 ];
3742 })
3743 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
3744 .filter( ":first" )
3745 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
3746 .end()
3747 .filter( ":last" )
3748 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
3749 .end()
3750 .end();
3751 },
3752
3753 _destroy: function() {
3754 this.element.removeClass( "ui-buttonset" );
3755 this.buttons
3756 .map(function() {
3757 return $( this ).button( "widget" )[ 0 ];
3758 })
3759 .removeClass( "ui-corner-left ui-corner-right" )
3760 .end()
3761 .button( "destroy" );
3762 }
3763 });
3764
3765 var button = $.ui.button;
3766
3767
3768 /*!
3769 * jQuery UI Datepicker 1.11.4
3770 * http://jqueryui.com
3771 *
3772 * Copyright jQuery Foundation and other contributors
3773 * Released under the MIT license.
3774 * http://jquery.org/license
3775 *
3776 * http://api.jqueryui.com/datepicker/
3777 */
3778
3779
3780 $.extend($.ui, { datepicker: { version: "1.11.4" } });
3781
3782 var datepicker_instActive;
3783
3784 function datepicker_getZindex( elem ) {
3785 var position, value;
3786 while ( elem.length && elem[ 0 ] !== document ) {
3787 // Ignore z-index if position is set to a value where z-index is ignored by the browser
3788 // This makes behavior of this function consistent across browsers
3789 // WebKit always returns auto if the element is positioned
3790 position = elem.css( "position" );
3791 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
3792 // IE returns 0 when zIndex is not specified
3793 // other browsers return a string
3794 // we ignore the case of nested elements with an explicit value of 0
3795 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
3796 value = parseInt( elem.css( "zIndex" ), 10 );
3797 if ( !isNaN( value ) && value !== 0 ) {
3798 return value;
3799 }
3800 }
3801 elem = elem.parent();
3802 }
3803
3804 return 0;
3805 }
3806 /* Date picker manager.
3807 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
3808 Settings for (groups of) date pickers are maintained in an instance object,
3809 allowing multiple different settings on the same page. */
3810
3811 function Datepicker() {
3812 this._curInst = null; // The current instance in use
3813 this._keyEvent = false; // If the last event was a key event
3814 this._disabledInputs = []; // List of date picker inputs that have been disabled
3815 this._datepickerShowing = false; // True if the popup picker is showing , false if not
3816 this._inDialog = false; // True if showing within a "dialog", false if not
3817 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
3818 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
3819 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
3820 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
3821 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
3822 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
3823 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
3824 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
3825 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
3826 this.regional = []; // Available regional settings, indexed by language code
3827 this.regional[""] = { // Default regional settings
3828 closeText: "Done", // Display text for close link
3829 prevText: "Prev", // Display text for previous month link
3830 nextText: "Next", // Display text for next month link
3831 currentText: "Today", // Display text for current month link
3832 monthNames: ["January","February","March","April","May","June",
3833 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
3834 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
3835 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
3836 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
3837 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
3838 weekHeader: "Wk", // Column header for week of the year
3839 dateFormat: "mm/dd/yy", // See format options on parseDate
3840 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
3841 isRTL: false, // True if right-to-left language, false if left-to-right
3842 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
3843 yearSuffix: "" // Additional text to append to the year in the month headers
3844 };
3845 this._defaults = { // Global defaults for all the date picker instances
3846 showOn: "focus", // "focus" for popup on focus,
3847 // "button" for trigger button, or "both" for either
3848 showAnim: "fadeIn", // Name of jQuery animation for popup
3849 showOptions: {}, // Options for enhanced animations
3850 defaultDate: null, // Used when field is blank: actual date,
3851 // +/-number for offset from today, null for today
3852 appendText: "", // Display text following the input box, e.g. showing the format
3853 buttonText: "...", // Text for trigger button
3854 buttonImage: "", // URL for trigger button image
3855 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
3856 hideIfNoPrevNext: false, // True to hide next/previous month links
3857 // if not applicable, false to just disable them
3858 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
3859 gotoCurrent: false, // True if today link goes back to current selection instead
3860 changeMonth: false, // True if month can be selected directly, false if only prev/next
3861 changeYear: false, // True if year can be selected directly, false if only prev/next
3862 yearRange: "c-10:c+10", // Range of years to display in drop-down,
3863 // either relative to today's year (-nn:+nn), relative to currently displayed year
3864 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
3865 showOtherMonths: false, // True to show dates in other months, false to leave blank
3866 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
3867 showWeek: false, // True to show week of the year, false to not show it
3868 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
3869 // takes a Date and returns the number of the week for it
3870 shortYearCutoff: "+10", // Short year values < this are in the current century,
3871 // > this are in the previous century,
3872 // string value starting with "+" for current year + value
3873 minDate: null, // The earliest selectable date, or null for no limit
3874 maxDate: null, // The latest selectable date, or null for no limit
3875 duration: "fast", // Duration of display/closure
3876 beforeShowDay: null, // Function that takes a date and returns an array with
3877 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
3878 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
3879 beforeShow: null, // Function that takes an input field and
3880 // returns a set of custom settings for the date picker
3881 onSelect: null, // Define a callback function when a date is selected
3882 onChangeMonthYear: null, // Define a callback function when the month or year is changed
3883 onClose: null, // Define a callback function when the datepicker is closed
3884 numberOfMonths: 1, // Number of months to show at a time
3885 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
3886 stepMonths: 1, // Number of months to step back/forward
3887 stepBigMonths: 12, // Number of months to step back/forward for the big links
3888 altField: "", // Selector for an alternate field to store selected dates into
3889 altFormat: "", // The date format to use for the alternate field
3890 constrainInput: true, // The input is constrained by the current date format
3891 showButtonPanel: false, // True to show button panel, false to not show it
3892 autoSize: false, // True to size the input for the date format, false to leave as is
3893 disabled: false // The initial disabled state
3894 };
3895 $.extend(this._defaults, this.regional[""]);
3896 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
3897 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
3898 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
3899 }
3900
3901 $.extend(Datepicker.prototype, {
3902 /* Class name added to elements to indicate already configured with a date picker. */
3903 markerClassName: "hasDatepicker",
3904
3905 //Keep track of the maximum number of rows displayed (see #7043)
3906 maxRows: 4,
3907
3908 // TODO rename to "widget" when switching to widget factory
3909 _widgetDatepicker: function() {
3910 return this.dpDiv;
3911 },
3912
3913 /* Override the default settings for all instances of the date picker.
3914 * @param settings object - the new settings to use as defaults (anonymous object)
3915 * @return the manager object
3916 */
3917 setDefaults: function(settings) {
3918 datepicker_extendRemove(this._defaults, settings || {});
3919 return this;
3920 },
3921
3922 /* Attach the date picker to a jQuery selection.
3923 * @param target element - the target input field or division or span
3924 * @param settings object - the new settings to use for this date picker instance (anonymous)
3925 */
3926 _attachDatepicker: function(target, settings) {
3927 var nodeName, inline, inst;
3928 nodeName = target.nodeName.toLowerCase();
3929 inline = (nodeName === "div" || nodeName === "span");
3930 if (!target.id) {
3931 this.uuid += 1;
3932 target.id = "dp" + this.uuid;
3933 }
3934 inst = this._newInst($(target), inline);
3935 inst.settings = $.extend({}, settings || {});
3936 if (nodeName === "input") {
3937 this._connectDatepicker(target, inst);
3938 } else if (inline) {
3939 this._inlineDatepicker(target, inst);
3940 }
3941 },
3942
3943 /* Create a new instance object. */
3944 _newInst: function(target, inline) {
3945 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
3946 return {id: id, input: target, // associated target
3947 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
3948 drawMonth: 0, drawYear: 0, // month being drawn
3949 inline: inline, // is datepicker inline or not
3950 dpDiv: (!inline ? this.dpDiv : // presentation div
3951 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
3952 },
3953
3954 /* Attach the date picker to an input field. */
3955 _connectDatepicker: function(target, inst) {
3956 var input = $(target);
3957 inst.append = $([]);
3958 inst.trigger = $([]);
3959 if (input.hasClass(this.markerClassName)) {
3960 return;
3961 }
3962 this._attachments(input, inst);
3963 input.addClass(this.markerClassName).keydown(this._doKeyDown).
3964 keypress(this._doKeyPress).keyup(this._doKeyUp);
3965 this._autoSize(inst);
3966 $.data(target, "datepicker", inst);
3967 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
3968 if( inst.settings.disabled ) {
3969 this._disableDatepicker( target );
3970 }
3971 },
3972
3973 /* Make attachments based on settings. */
3974 _attachments: function(input, inst) {
3975 var showOn, buttonText, buttonImage,
3976 appendText = this._get(inst, "appendText"),
3977 isRTL = this._get(inst, "isRTL");
3978
3979 if (inst.append) {
3980 inst.append.remove();
3981 }
3982 if (appendText) {
3983 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
3984 input[isRTL ? "before" : "after"](inst.append);
3985 }
3986
3987 input.unbind("focus", this._showDatepicker);
3988
3989 if (inst.trigger) {
3990 inst.trigger.remove();
3991 }
3992
3993 showOn = this._get(inst, "showOn");
3994 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
3995 input.focus(this._showDatepicker);
3996 }
3997 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
3998 buttonText = this._get(inst, "buttonText");
3999 buttonImage = this._get(inst, "buttonImage");
4000 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
4001 $("<img/>").addClass(this._triggerClass).
4002 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
4003 $("<button type='button'></button>").addClass(this._triggerClass).
4004 html(!buttonImage ? buttonText : $("<img/>").attr(
4005 { src:buttonImage, alt:buttonText, title:buttonText })));
4006 input[isRTL ? "before" : "after"](inst.trigger);
4007 inst.trigger.click(function() {
4008 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
4009 $.datepicker._hideDatepicker();
4010 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
4011 $.datepicker._hideDatepicker();
4012 $.datepicker._showDatepicker(input[0]);
4013 } else {
4014 $.datepicker._showDatepicker(input[0]);
4015 }
4016 return false;
4017 });
4018 }
4019 },
4020
4021 /* Apply the maximum length for the date format. */
4022 _autoSize: function(inst) {
4023 if (this._get(inst, "autoSize") && !inst.inline) {
4024 var findMax, max, maxI, i,
4025 date = new Date(2009, 12 - 1, 20), // Ensure double digits
4026 dateFormat = this._get(inst, "dateFormat");
4027
4028 if (dateFormat.match(/[DM]/)) {
4029 findMax = function(names) {
4030 max = 0;
4031 maxI = 0;
4032 for (i = 0; i < names.length; i++) {
4033 if (names[i].length > max) {
4034 max = names[i].length;
4035 maxI = i;
4036 }
4037 }
4038 return maxI;
4039 };
4040 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
4041 "monthNames" : "monthNamesShort"))));
4042 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
4043 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
4044 }
4045 inst.input.attr("size", this._formatDate(inst, date).length);
4046 }
4047 },
4048
4049 /* Attach an inline date picker to a div. */
4050 _inlineDatepicker: function(target, inst) {
4051 var divSpan = $(target);
4052 if (divSpan.hasClass(this.markerClassName)) {
4053 return;
4054 }
4055 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
4056 $.data(target, "datepicker", inst);
4057 this._setDate(inst, this._getDefaultDate(inst), true);
4058 this._updateDatepicker(inst);
4059 this._updateAlternate(inst);
4060 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
4061 if( inst.settings.disabled ) {
4062 this._disableDatepicker( target );
4063 }
4064 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
4065 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
4066 inst.dpDiv.css( "display", "block" );
4067 },
4068
4069 /* Pop-up the date picker in a "dialog" box.
4070 * @param input element - ignored
4071 * @param date string or Date - the initial date to display
4072 * @param onSelect function - the function to call when a date is selected
4073 * @param settings object - update the dialog date picker instance's settings (anonymous object)
4074 * @param pos int[2] - coordinates for the dialog's position within the screen or
4075 * event - with x/y coordinates or
4076 * leave empty for default (screen centre)
4077 * @return the manager object
4078 */
4079 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
4080 var id, browserWidth, browserHeight, scrollX, scrollY,
4081 inst = this._dialogInst; // internal instance
4082
4083 if (!inst) {
4084 this.uuid += 1;
4085 id = "dp" + this.uuid;
4086 this._dialogInput = $("<input type='text' id='" + id +
4087 "' style='position: absolute; top: -100px; width: 0px;'/>");
4088 this._dialogInput.keydown(this._doKeyDown);
4089 $("body").append(this._dialogInput);
4090 inst = this._dialogInst = this._newInst(this._dialogInput, false);
4091 inst.settings = {};
4092 $.data(this._dialogInput[0], "datepicker", inst);
4093 }
4094 datepicker_extendRemove(inst.settings, settings || {});
4095 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
4096 this._dialogInput.val(date);
4097
4098 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
4099 if (!this._pos) {
4100 browserWidth = document.documentElement.clientWidth;
4101 browserHeight = document.documentElement.clientHeight;
4102 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
4103 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
4104 this._pos = // should use actual width/height below
4105 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
4106 }
4107
4108 // move input on screen for focus, but hidden behind dialog
4109 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
4110 inst.settings.onSelect = onSelect;
4111 this._inDialog = true;
4112 this.dpDiv.addClass(this._dialogClass);
4113 this._showDatepicker(this._dialogInput[0]);
4114 if ($.blockUI) {
4115 $.blockUI(this.dpDiv);
4116 }
4117 $.data(this._dialogInput[0], "datepicker", inst);
4118 return this;
4119 },
4120
4121 /* Detach a datepicker from its control.
4122 * @param target element - the target input field or division or span
4123 */
4124 _destroyDatepicker: function(target) {
4125 var nodeName,
4126 $target = $(target),
4127 inst = $.data(target, "datepicker");
4128
4129 if (!$target.hasClass(this.markerClassName)) {
4130 return;
4131 }
4132
4133 nodeName = target.nodeName.toLowerCase();
4134 $.removeData(target, "datepicker");
4135 if (nodeName === "input") {
4136 inst.append.remove();
4137 inst.trigger.remove();
4138 $target.removeClass(this.markerClassName).
4139 unbind("focus", this._showDatepicker).
4140 unbind("keydown", this._doKeyDown).
4141 unbind("keypress", this._doKeyPress).
4142 unbind("keyup", this._doKeyUp);
4143 } else if (nodeName === "div" || nodeName === "span") {
4144 $target.removeClass(this.markerClassName).empty();
4145 }
4146
4147 if ( datepicker_instActive === inst ) {
4148 datepicker_instActive = null;
4149 }
4150 },
4151
4152 /* Enable the date picker to a jQuery selection.
4153 * @param target element - the target input field or division or span
4154 */
4155 _enableDatepicker: function(target) {
4156 var nodeName, inline,
4157 $target = $(target),
4158 inst = $.data(target, "datepicker");
4159
4160 if (!$target.hasClass(this.markerClassName)) {
4161 return;
4162 }
4163
4164 nodeName = target.nodeName.toLowerCase();
4165 if (nodeName === "input") {
4166 target.disabled = false;
4167 inst.trigger.filter("button").
4168 each(function() { this.disabled = false; }).end().
4169 filter("img").css({opacity: "1.0", cursor: ""});
4170 } else if (nodeName === "div" || nodeName === "span") {
4171 inline = $target.children("." + this._inlineClass);
4172 inline.children().removeClass("ui-state-disabled");
4173 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4174 prop("disabled", false);
4175 }
4176 this._disabledInputs = $.map(this._disabledInputs,
4177 function(value) { return (value === target ? null : value); }); // delete entry
4178 },
4179
4180 /* Disable the date picker to a jQuery selection.
4181 * @param target element - the target input field or division or span
4182 */
4183 _disableDatepicker: function(target) {
4184 var nodeName, inline,
4185 $target = $(target),
4186 inst = $.data(target, "datepicker");
4187
4188 if (!$target.hasClass(this.markerClassName)) {
4189 return;
4190 }
4191
4192 nodeName = target.nodeName.toLowerCase();
4193 if (nodeName === "input") {
4194 target.disabled = true;
4195 inst.trigger.filter("button").
4196 each(function() { this.disabled = true; }).end().
4197 filter("img").css({opacity: "0.5", cursor: "default"});
4198 } else if (nodeName === "div" || nodeName === "span") {
4199 inline = $target.children("." + this._inlineClass);
4200 inline.children().addClass("ui-state-disabled");
4201 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
4202 prop("disabled", true);
4203 }
4204 this._disabledInputs = $.map(this._disabledInputs,
4205 function(value) { return (value === target ? null : value); }); // delete entry
4206 this._disabledInputs[this._disabledInputs.length] = target;
4207 },
4208
4209 /* Is the first field in a jQuery collection disabled as a datepicker?
4210 * @param target element - the target input field or division or span
4211 * @return boolean - true if disabled, false if enabled
4212 */
4213 _isDisabledDatepicker: function(target) {
4214 if (!target) {
4215 return false;
4216 }
4217 for (var i = 0; i < this._disabledInputs.length; i++) {
4218 if (this._disabledInputs[i] === target) {
4219 return true;
4220 }
4221 }
4222 return false;
4223 },
4224
4225 /* Retrieve the instance data for the target control.
4226 * @param target element - the target input field or division or span
4227 * @return object - the associated instance data
4228 * @throws error if a jQuery problem getting data
4229 */
4230 _getInst: function(target) {
4231 try {
4232 return $.data(target, "datepicker");
4233 }
4234 catch (err) {
4235 throw "Missing instance data for this datepicker";
4236 }
4237 },
4238
4239 /* Update or retrieve the settings for a date picker attached to an input field or division.
4240 * @param target element - the target input field or division or span
4241 * @param name object - the new settings to update or
4242 * string - the name of the setting to change or retrieve,
4243 * when retrieving also "all" for all instance settings or
4244 * "defaults" for all global defaults
4245 * @param value any - the new value for the setting
4246 * (omit if above is an object or to retrieve a value)
4247 */
4248 _optionDatepicker: function(target, name, value) {
4249 var settings, date, minDate, maxDate,
4250 inst = this._getInst(target);
4251
4252 if (arguments.length === 2 && typeof name === "string") {
4253 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
4254 (inst ? (name === "all" ? $.extend({}, inst.settings) :
4255 this._get(inst, name)) : null));
4256 }
4257
4258 settings = name || {};
4259 if (typeof name === "string") {
4260 settings = {};
4261 settings[name] = value;
4262 }
4263
4264 if (inst) {
4265 if (this._curInst === inst) {
4266 this._hideDatepicker();
4267 }
4268
4269 date = this._getDateDatepicker(target, true);
4270 minDate = this._getMinMaxDate(inst, "min");
4271 maxDate = this._getMinMaxDate(inst, "max");
4272 datepicker_extendRemove(inst.settings, settings);
4273 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
4274 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
4275 inst.settings.minDate = this._formatDate(inst, minDate);
4276 }
4277 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
4278 inst.settings.maxDate = this._formatDate(inst, maxDate);
4279 }
4280 if ( "disabled" in settings ) {
4281 if ( settings.disabled ) {
4282 this._disableDatepicker(target);
4283 } else {
4284 this._enableDatepicker(target);
4285 }
4286 }
4287 this._attachments($(target), inst);
4288 this._autoSize(inst);
4289 this._setDate(inst, date);
4290 this._updateAlternate(inst);
4291 this._updateDatepicker(inst);
4292 }
4293 },
4294
4295 // change method deprecated
4296 _changeDatepicker: function(target, name, value) {
4297 this._optionDatepicker(target, name, value);
4298 },
4299
4300 /* Redraw the date picker attached to an input field or division.
4301 * @param target element - the target input field or division or span
4302 */
4303 _refreshDatepicker: function(target) {
4304 var inst = this._getInst(target);
4305 if (inst) {
4306 this._updateDatepicker(inst);
4307 }
4308 },
4309
4310 /* Set the dates for a jQuery selection.
4311 * @param target element - the target input field or division or span
4312 * @param date Date - the new date
4313 */
4314 _setDateDatepicker: function(target, date) {
4315 var inst = this._getInst(target);
4316 if (inst) {
4317 this._setDate(inst, date);
4318 this._updateDatepicker(inst);
4319 this._updateAlternate(inst);
4320 }
4321 },
4322
4323 /* Get the date(s) for the first entry in a jQuery selection.
4324 * @param target element - the target input field or division or span
4325 * @param noDefault boolean - true if no default date is to be used
4326 * @return Date - the current date
4327 */
4328 _getDateDatepicker: function(target, noDefault) {
4329 var inst = this._getInst(target);
4330 if (inst && !inst.inline) {
4331 this._setDateFromField(inst, noDefault);
4332 }
4333 return (inst ? this._getDate(inst) : null);
4334 },
4335
4336 /* Handle keystrokes. */
4337 _doKeyDown: function(event) {
4338 var onSelect, dateStr, sel,
4339 inst = $.datepicker._getInst(event.target),
4340 handled = true,
4341 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
4342
4343 inst._keyEvent = true;
4344 if ($.datepicker._datepickerShowing) {
4345 switch (event.keyCode) {
4346 case 9: $.datepicker._hideDatepicker();
4347 handled = false;
4348 break; // hide on tab out
4349 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
4350 $.datepicker._currentClass + ")", inst.dpDiv);
4351 if (sel[0]) {
4352 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
4353 }
4354
4355 onSelect = $.datepicker._get(inst, "onSelect");
4356 if (onSelect) {
4357 dateStr = $.datepicker._formatDate(inst);
4358
4359 // trigger custom callback
4360 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
4361 } else {
4362 $.datepicker._hideDatepicker();
4363 }
4364
4365 return false; // don't submit the form
4366 case 27: $.datepicker._hideDatepicker();
4367 break; // hide on escape
4368 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4369 -$.datepicker._get(inst, "stepBigMonths") :
4370 -$.datepicker._get(inst, "stepMonths")), "M");
4371 break; // previous month/year on page up/+ ctrl
4372 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4373 +$.datepicker._get(inst, "stepBigMonths") :
4374 +$.datepicker._get(inst, "stepMonths")), "M");
4375 break; // next month/year on page down/+ ctrl
4376 case 35: if (event.ctrlKey || event.metaKey) {
4377 $.datepicker._clearDate(event.target);
4378 }
4379 handled = event.ctrlKey || event.metaKey;
4380 break; // clear on ctrl or command +end
4381 case 36: if (event.ctrlKey || event.metaKey) {
4382 $.datepicker._gotoToday(event.target);
4383 }
4384 handled = event.ctrlKey || event.metaKey;
4385 break; // current on ctrl or command +home
4386 case 37: if (event.ctrlKey || event.metaKey) {
4387 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
4388 }
4389 handled = event.ctrlKey || event.metaKey;
4390 // -1 day on ctrl or command +left
4391 if (event.originalEvent.altKey) {
4392 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4393 -$.datepicker._get(inst, "stepBigMonths") :
4394 -$.datepicker._get(inst, "stepMonths")), "M");
4395 }
4396 // next month/year on alt +left on Mac
4397 break;
4398 case 38: if (event.ctrlKey || event.metaKey) {
4399 $.datepicker._adjustDate(event.target, -7, "D");
4400 }
4401 handled = event.ctrlKey || event.metaKey;
4402 break; // -1 week on ctrl or command +up
4403 case 39: if (event.ctrlKey || event.metaKey) {
4404 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
4405 }
4406 handled = event.ctrlKey || event.metaKey;
4407 // +1 day on ctrl or command +right
4408 if (event.originalEvent.altKey) {
4409 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
4410 +$.datepicker._get(inst, "stepBigMonths") :
4411 +$.datepicker._get(inst, "stepMonths")), "M");
4412 }
4413 // next month/year on alt +right
4414 break;
4415 case 40: if (event.ctrlKey || event.metaKey) {
4416 $.datepicker._adjustDate(event.target, +7, "D");
4417 }
4418 handled = event.ctrlKey || event.metaKey;
4419 break; // +1 week on ctrl or command +down
4420 default: handled = false;
4421 }
4422 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
4423 $.datepicker._showDatepicker(this);
4424 } else {
4425 handled = false;
4426 }
4427
4428 if (handled) {
4429 event.preventDefault();
4430 event.stopPropagation();
4431 }
4432 },
4433
4434 /* Filter entered characters - based on date format. */
4435 _doKeyPress: function(event) {
4436 var chars, chr,
4437 inst = $.datepicker._getInst(event.target);
4438
4439 if ($.datepicker._get(inst, "constrainInput")) {
4440 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
4441 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
4442 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
4443 }
4444 },
4445
4446 /* Synchronise manual entry and field/alternate field. */
4447 _doKeyUp: function(event) {
4448 var date,
4449 inst = $.datepicker._getInst(event.target);
4450
4451 if (inst.input.val() !== inst.lastVal) {
4452 try {
4453 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
4454 (inst.input ? inst.input.val() : null),
4455 $.datepicker._getFormatConfig(inst));
4456
4457 if (date) { // only if valid
4458 $.datepicker._setDateFromField(inst);
4459 $.datepicker._updateAlternate(inst);
4460 $.datepicker._updateDatepicker(inst);
4461 }
4462 }
4463 catch (err) {
4464 }
4465 }
4466 return true;
4467 },
4468
4469 /* Pop-up the date picker for a given input field.
4470 * If false returned from beforeShow event handler do not show.
4471 * @param input element - the input field attached to the date picker or
4472 * event - if triggered by focus
4473 */
4474 _showDatepicker: function(input) {
4475 input = input.target || input;
4476 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
4477 input = $("input", input.parentNode)[0];
4478 }
4479
4480 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
4481 return;
4482 }
4483
4484 var inst, beforeShow, beforeShowSettings, isFixed,
4485 offset, showAnim, duration;
4486
4487 inst = $.datepicker._getInst(input);
4488 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
4489 $.datepicker._curInst.dpDiv.stop(true, true);
4490 if ( inst && $.datepicker._datepickerShowing ) {
4491 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
4492 }
4493 }
4494
4495 beforeShow = $.datepicker._get(inst, "beforeShow");
4496 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
4497 if(beforeShowSettings === false){
4498 return;
4499 }
4500 datepicker_extendRemove(inst.settings, beforeShowSettings);
4501
4502 inst.lastVal = null;
4503 $.datepicker._lastInput = input;
4504 $.datepicker._setDateFromField(inst);
4505
4506 if ($.datepicker._inDialog) { // hide cursor
4507 input.value = "";
4508 }
4509 if (!$.datepicker._pos) { // position below input
4510 $.datepicker._pos = $.datepicker._findPos(input);
4511 $.datepicker._pos[1] += input.offsetHeight; // add the height
4512 }
4513
4514 isFixed = false;
4515 $(input).parents().each(function() {
4516 isFixed |= $(this).css("position") === "fixed";
4517 return !isFixed;
4518 });
4519
4520 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
4521 $.datepicker._pos = null;
4522 //to avoid flashes on Firefox
4523 inst.dpDiv.empty();
4524 // determine sizing offscreen
4525 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
4526 $.datepicker._updateDatepicker(inst);
4527 // fix width for dynamic number of date pickers
4528 // and adjust position before showing
4529 offset = $.datepicker._checkOffset(inst, offset, isFixed);
4530 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
4531 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
4532 left: offset.left + "px", top: offset.top + "px"});
4533
4534 if (!inst.inline) {
4535 showAnim = $.datepicker._get(inst, "showAnim");
4536 duration = $.datepicker._get(inst, "duration");
4537 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
4538 $.datepicker._datepickerShowing = true;
4539
4540 if ( $.effects && $.effects.effect[ showAnim ] ) {
4541 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
4542 } else {
4543 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
4544 }
4545
4546 if ( $.datepicker._shouldFocusInput( inst ) ) {
4547 inst.input.focus();
4548 }
4549
4550 $.datepicker._curInst = inst;
4551 }
4552 },
4553
4554 /* Generate the date picker content. */
4555 _updateDatepicker: function(inst) {
4556 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
4557 datepicker_instActive = inst; // for delegate hover events
4558 inst.dpDiv.empty().append(this._generateHTML(inst));
4559 this._attachHandlers(inst);
4560
4561 var origyearshtml,
4562 numMonths = this._getNumberOfMonths(inst),
4563 cols = numMonths[1],
4564 width = 17,
4565 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
4566
4567 if ( activeCell.length > 0 ) {
4568 datepicker_handleMouseover.apply( activeCell.get( 0 ) );
4569 }
4570
4571 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
4572 if (cols > 1) {
4573 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
4574 }
4575 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
4576 "Class"]("ui-datepicker-multi");
4577 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
4578 "Class"]("ui-datepicker-rtl");
4579
4580 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
4581 inst.input.focus();
4582 }
4583
4584 // deffered render of the years select (to avoid flashes on Firefox)
4585 if( inst.yearshtml ){
4586 origyearshtml = inst.yearshtml;
4587 setTimeout(function(){
4588 //assure that inst.yearshtml didn't change.
4589 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
4590 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
4591 }
4592 origyearshtml = inst.yearshtml = null;
4593 }, 0);
4594 }
4595 },
4596
4597 // #6694 - don't focus the input if it's already focused
4598 // this breaks the change event in IE
4599 // Support: IE and jQuery <1.9
4600 _shouldFocusInput: function( inst ) {
4601 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
4602 },
4603
4604 /* Check positioning to remain on screen. */
4605 _checkOffset: function(inst, offset, isFixed) {
4606 var dpWidth = inst.dpDiv.outerWidth(),
4607 dpHeight = inst.dpDiv.outerHeight(),
4608 inputWidth = inst.input ? inst.input.outerWidth() : 0,
4609 inputHeight = inst.input ? inst.input.outerHeight() : 0,
4610 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
4611 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
4612
4613 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
4614 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
4615 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
4616
4617 // now check if datepicker is showing outside window viewport - move to a better place if so.
4618 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
4619 Math.abs(offset.left + dpWidth - viewWidth) : 0);
4620 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
4621 Math.abs(dpHeight + inputHeight) : 0);
4622
4623 return offset;
4624 },
4625
4626 /* Find an object's position on the screen. */
4627 _findPos: function(obj) {
4628 var position,
4629 inst = this._getInst(obj),
4630 isRTL = this._get(inst, "isRTL");
4631
4632 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
4633 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
4634 }
4635
4636 position = $(obj).offset();
4637 return [position.left, position.top];
4638 },
4639
4640 /* Hide the date picker from view.
4641 * @param input element - the input field attached to the date picker
4642 */
4643 _hideDatepicker: function(input) {
4644 var showAnim, duration, postProcess, onClose,
4645 inst = this._curInst;
4646
4647 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
4648 return;
4649 }
4650
4651 if (this._datepickerShowing) {
4652 showAnim = this._get(inst, "showAnim");
4653 duration = this._get(inst, "duration");
4654 postProcess = function() {
4655 $.datepicker._tidyDialog(inst);
4656 };
4657
4658 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
4659 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
4660 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
4661 } else {
4662 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
4663 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
4664 }
4665
4666 if (!showAnim) {
4667 postProcess();
4668 }
4669 this._datepickerShowing = false;
4670
4671 onClose = this._get(inst, "onClose");
4672 if (onClose) {
4673 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
4674 }
4675
4676 this._lastInput = null;
4677 if (this._inDialog) {
4678 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
4679 if ($.blockUI) {
4680 $.unblockUI();
4681 $("body").append(this.dpDiv);
4682 }
4683 }
4684 this._inDialog = false;
4685 }
4686 },
4687
4688 /* Tidy up after a dialog display. */
4689 _tidyDialog: function(inst) {
4690 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
4691 },
4692
4693 /* Close date picker if clicked elsewhere. */
4694 _checkExternalClick: function(event) {
4695 if (!$.datepicker._curInst) {
4696 return;
4697 }
4698
4699 var $target = $(event.target),
4700 inst = $.datepicker._getInst($target[0]);
4701
4702 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
4703 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
4704 !$target.hasClass($.datepicker.markerClassName) &&
4705 !$target.closest("." + $.datepicker._triggerClass).length &&
4706 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
4707 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
4708 $.datepicker._hideDatepicker();
4709 }
4710 },
4711
4712 /* Adjust one of the date sub-fields. */
4713 _adjustDate: function(id, offset, period) {
4714 var target = $(id),
4715 inst = this._getInst(target[0]);
4716
4717 if (this._isDisabledDatepicker(target[0])) {
4718 return;
4719 }
4720 this._adjustInstDate(inst, offset +
4721 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
4722 period);
4723 this._updateDatepicker(inst);
4724 },
4725
4726 /* Action for current link. */
4727 _gotoToday: function(id) {
4728 var date,
4729 target = $(id),
4730 inst = this._getInst(target[0]);
4731
4732 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
4733 inst.selectedDay = inst.currentDay;
4734 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
4735 inst.drawYear = inst.selectedYear = inst.currentYear;
4736 } else {
4737 date = new Date();
4738 inst.selectedDay = date.getDate();
4739 inst.drawMonth = inst.selectedMonth = date.getMonth();
4740 inst.drawYear = inst.selectedYear = date.getFullYear();
4741 }
4742 this._notifyChange(inst);
4743 this._adjustDate(target);
4744 },
4745
4746 /* Action for selecting a new month/year. */
4747 _selectMonthYear: function(id, select, period) {
4748 var target = $(id),
4749 inst = this._getInst(target[0]);
4750
4751 inst["selected" + (period === "M" ? "Month" : "Year")] =
4752 inst["draw" + (period === "M" ? "Month" : "Year")] =
4753 parseInt(select.options[select.selectedIndex].value,10);
4754
4755 this._notifyChange(inst);
4756 this._adjustDate(target);
4757 },
4758
4759 /* Action for selecting a day. */
4760 _selectDay: function(id, month, year, td) {
4761 var inst,
4762 target = $(id);
4763
4764 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
4765 return;
4766 }
4767
4768 inst = this._getInst(target[0]);
4769 inst.selectedDay = inst.currentDay = $("a", td).html();
4770 inst.selectedMonth = inst.currentMonth = month;
4771 inst.selectedYear = inst.currentYear = year;
4772 this._selectDate(id, this._formatDate(inst,
4773 inst.currentDay, inst.currentMonth, inst.currentYear));
4774 },
4775
4776 /* Erase the input field and hide the date picker. */
4777 _clearDate: function(id) {
4778 var target = $(id);
4779 this._selectDate(target, "");
4780 },
4781
4782 /* Update the input field with the selected date. */
4783 _selectDate: function(id, dateStr) {
4784 var onSelect,
4785 target = $(id),
4786 inst = this._getInst(target[0]);
4787
4788 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
4789 if (inst.input) {
4790 inst.input.val(dateStr);
4791 }
4792 this._updateAlternate(inst);
4793
4794 onSelect = this._get(inst, "onSelect");
4795 if (onSelect) {
4796 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
4797 } else if (inst.input) {
4798 inst.input.trigger("change"); // fire the change event
4799 }
4800
4801 if (inst.inline){
4802 this._updateDatepicker(inst);
4803 } else {
4804 this._hideDatepicker();
4805 this._lastInput = inst.input[0];
4806 if (typeof(inst.input[0]) !== "object") {
4807 inst.input.focus(); // restore focus
4808 }
4809 this._lastInput = null;
4810 }
4811 },
4812
4813 /* Update any alternate field to synchronise with the main field. */
4814 _updateAlternate: function(inst) {
4815 var altFormat, date, dateStr,
4816 altField = this._get(inst, "altField");
4817
4818 if (altField) { // update alternate field too
4819 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
4820 date = this._getDate(inst);
4821 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
4822 $(altField).each(function() { $(this).val(dateStr); });
4823 }
4824 },
4825
4826 /* Set as beforeShowDay function to prevent selection of weekends.
4827 * @param date Date - the date to customise
4828 * @return [boolean, string] - is this date selectable?, what is its CSS class?
4829 */
4830 noWeekends: function(date) {
4831 var day = date.getDay();
4832 return [(day > 0 && day < 6), ""];
4833 },
4834
4835 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
4836 * @param date Date - the date to get the week for
4837 * @return number - the number of the week within the year that contains this date
4838 */
4839 iso8601Week: function(date) {
4840 var time,
4841 checkDate = new Date(date.getTime());
4842
4843 // Find Thursday of this week starting on Monday
4844 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
4845
4846 time = checkDate.getTime();
4847 checkDate.setMonth(0); // Compare with Jan 1
4848 checkDate.setDate(1);
4849 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
4850 },
4851
4852 /* Parse a string value into a date object.
4853 * See formatDate below for the possible formats.
4854 *
4855 * @param format string - the expected format of the date
4856 * @param value string - the date in the above format
4857 * @param settings Object - attributes include:
4858 * shortYearCutoff number - the cutoff year for determining the century (optional)
4859 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
4860 * dayNames string[7] - names of the days from Sunday (optional)
4861 * monthNamesShort string[12] - abbreviated names of the months (optional)
4862 * monthNames string[12] - names of the months (optional)
4863 * @return Date - the extracted date value or null if value is blank
4864 */
4865 parseDate: function (format, value, settings) {
4866 if (format == null || value == null) {
4867 throw "Invalid arguments";
4868 }
4869
4870 value = (typeof value === "object" ? value.toString() : value + "");
4871 if (value === "") {
4872 return null;
4873 }
4874
4875 var iFormat, dim, extra,
4876 iValue = 0,
4877 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
4878 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
4879 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
4880 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
4881 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
4882 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
4883 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
4884 year = -1,
4885 month = -1,
4886 day = -1,
4887 doy = -1,
4888 literal = false,
4889 date,
4890 // Check whether a format character is doubled
4891 lookAhead = function(match) {
4892 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
4893 if (matches) {
4894 iFormat++;
4895 }
4896 return matches;
4897 },
4898 // Extract a number from the string value
4899 getNumber = function(match) {
4900 var isDoubled = lookAhead(match),
4901 size = (match === "@" ? 14 : (match === "!" ? 20 :
4902 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
4903 minSize = (match === "y" ? size : 1),
4904 digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
4905 num = value.substring(iValue).match(digits);
4906 if (!num) {
4907 throw "Missing number at position " + iValue;
4908 }
4909 iValue += num[0].length;
4910 return parseInt(num[0], 10);
4911 },
4912 // Extract a name from the string value and convert to an index
4913 getName = function(match, shortNames, longNames) {
4914 var index = -1,
4915 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
4916 return [ [k, v] ];
4917 }).sort(function (a, b) {
4918 return -(a[1].length - b[1].length);
4919 });
4920
4921 $.each(names, function (i, pair) {
4922 var name = pair[1];
4923 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
4924 index = pair[0];
4925 iValue += name.length;
4926 return false;
4927 }
4928 });
4929 if (index !== -1) {
4930 return index + 1;
4931 } else {
4932 throw "Unknown name at position " + iValue;
4933 }
4934 },
4935 // Confirm that a literal character matches the string value
4936 checkLiteral = function() {
4937 if (value.charAt(iValue) !== format.charAt(iFormat)) {
4938 throw "Unexpected literal at position " + iValue;
4939 }
4940 iValue++;
4941 };
4942
4943 for (iFormat = 0; iFormat < format.length; iFormat++) {
4944 if (literal) {
4945 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
4946 literal = false;
4947 } else {
4948 checkLiteral();
4949 }
4950 } else {
4951 switch (format.charAt(iFormat)) {
4952 case "d":
4953 day = getNumber("d");
4954 break;
4955 case "D":
4956 getName("D", dayNamesShort, dayNames);
4957 break;
4958 case "o":
4959 doy = getNumber("o");
4960 break;
4961 case "m":
4962 month = getNumber("m");
4963 break;
4964 case "M":
4965 month = getName("M", monthNamesShort, monthNames);
4966 break;
4967 case "y":
4968 year = getNumber("y");
4969 break;
4970 case "@":
4971 date = new Date(getNumber("@"));
4972 year = date.getFullYear();
4973 month = date.getMonth() + 1;
4974 day = date.getDate();
4975 break;
4976 case "!":
4977 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
4978 year = date.getFullYear();
4979 month = date.getMonth() + 1;
4980 day = date.getDate();
4981 break;
4982 case "'":
4983 if (lookAhead("'")){
4984 checkLiteral();
4985 } else {
4986 literal = true;
4987 }
4988 break;
4989 default:
4990 checkLiteral();
4991 }
4992 }
4993 }
4994
4995 if (iValue < value.length){
4996 extra = value.substr(iValue);
4997 if (!/^\s+/.test(extra)) {
4998 throw "Extra/unparsed characters found in date: " + extra;
4999 }
5000 }
5001
5002 if (year === -1) {
5003 year = new Date().getFullYear();
5004 } else if (year < 100) {
5005 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
5006 (year <= shortYearCutoff ? 0 : -100);
5007 }
5008
5009 if (doy > -1) {
5010 month = 1;
5011 day = doy;
5012 do {
5013 dim = this._getDaysInMonth(year, month - 1);
5014 if (day <= dim) {
5015 break;
5016 }
5017 month++;
5018 day -= dim;
5019 } while (true);
5020 }
5021
5022 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
5023 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
5024 throw "Invalid date"; // E.g. 31/02/00
5025 }
5026 return date;
5027 },
5028
5029 /* Standard date formats. */
5030 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
5031 COOKIE: "D, dd M yy",
5032 ISO_8601: "yy-mm-dd",
5033 RFC_822: "D, d M y",
5034 RFC_850: "DD, dd-M-y",
5035 RFC_1036: "D, d M y",
5036 RFC_1123: "D, d M yy",
5037 RFC_2822: "D, d M yy",
5038 RSS: "D, d M y", // RFC 822
5039 TICKS: "!",
5040 TIMESTAMP: "@",
5041 W3C: "yy-mm-dd", // ISO 8601
5042
5043 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
5044 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
5045
5046 /* Format a date object into a string value.
5047 * The format can be combinations of the following:
5048 * d - day of month (no leading zero)
5049 * dd - day of month (two digit)
5050 * o - day of year (no leading zeros)
5051 * oo - day of year (three digit)
5052 * D - day name short
5053 * DD - day name long
5054 * m - month of year (no leading zero)
5055 * mm - month of year (two digit)
5056 * M - month name short
5057 * MM - month name long
5058 * y - year (two digit)
5059 * yy - year (four digit)
5060 * @ - Unix timestamp (ms since 01/01/1970)
5061 * ! - Windows ticks (100ns since 01/01/0001)
5062 * "..." - literal text
5063 * '' - single quote
5064 *
5065 * @param format string - the desired format of the date
5066 * @param date Date - the date value to format
5067 * @param settings Object - attributes include:
5068 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
5069 * dayNames string[7] - names of the days from Sunday (optional)
5070 * monthNamesShort string[12] - abbreviated names of the months (optional)
5071 * monthNames string[12] - names of the months (optional)
5072 * @return string - the date in the above format
5073 */
5074 formatDate: function (format, date, settings) {
5075 if (!date) {
5076 return "";
5077 }
5078
5079 var iFormat,
5080 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
5081 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
5082 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
5083 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
5084 // Check whether a format character is doubled
5085 lookAhead = function(match) {
5086 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5087 if (matches) {
5088 iFormat++;
5089 }
5090 return matches;
5091 },
5092 // Format a number, with leading zero if necessary
5093 formatNumber = function(match, value, len) {
5094 var num = "" + value;
5095 if (lookAhead(match)) {
5096 while (num.length < len) {
5097 num = "0" + num;
5098 }
5099 }
5100 return num;
5101 },
5102 // Format a name, short or long as requested
5103 formatName = function(match, value, shortNames, longNames) {
5104 return (lookAhead(match) ? longNames[value] : shortNames[value]);
5105 },
5106 output = "",
5107 literal = false;
5108
5109 if (date) {
5110 for (iFormat = 0; iFormat < format.length; iFormat++) {
5111 if (literal) {
5112 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5113 literal = false;
5114 } else {
5115 output += format.charAt(iFormat);
5116 }
5117 } else {
5118 switch (format.charAt(iFormat)) {
5119 case "d":
5120 output += formatNumber("d", date.getDate(), 2);
5121 break;
5122 case "D":
5123 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
5124 break;
5125 case "o":
5126 output += formatNumber("o",
5127 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
5128 break;
5129 case "m":
5130 output += formatNumber("m", date.getMonth() + 1, 2);
5131 break;
5132 case "M":
5133 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
5134 break;
5135 case "y":
5136 output += (lookAhead("y") ? date.getFullYear() :
5137 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
5138 break;
5139 case "@":
5140 output += date.getTime();
5141 break;
5142 case "!":
5143 output += date.getTime() * 10000 + this._ticksTo1970;
5144 break;
5145 case "'":
5146 if (lookAhead("'")) {
5147 output += "'";
5148 } else {
5149 literal = true;
5150 }
5151 break;
5152 default:
5153 output += format.charAt(iFormat);
5154 }
5155 }
5156 }
5157 }
5158 return output;
5159 },
5160
5161 /* Extract all possible characters from the date format. */
5162 _possibleChars: function (format) {
5163 var iFormat,
5164 chars = "",
5165 literal = false,
5166 // Check whether a format character is doubled
5167 lookAhead = function(match) {
5168 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
5169 if (matches) {
5170 iFormat++;
5171 }
5172 return matches;
5173 };
5174
5175 for (iFormat = 0; iFormat < format.length; iFormat++) {
5176 if (literal) {
5177 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
5178 literal = false;
5179 } else {
5180 chars += format.charAt(iFormat);
5181 }
5182 } else {
5183 switch (format.charAt(iFormat)) {
5184 case "d": case "m": case "y": case "@":
5185 chars += "0123456789";
5186 break;
5187 case "D": case "M":
5188 return null; // Accept anything
5189 case "'":
5190 if (lookAhead("'")) {
5191 chars += "'";
5192 } else {
5193 literal = true;
5194 }
5195 break;
5196 default:
5197 chars += format.charAt(iFormat);
5198 }
5199 }
5200 }
5201 return chars;
5202 },
5203
5204 /* Get a setting value, defaulting if necessary. */
5205 _get: function(inst, name) {
5206 return inst.settings[name] !== undefined ?
5207 inst.settings[name] : this._defaults[name];
5208 },
5209
5210 /* Parse existing date and initialise date picker. */
5211 _setDateFromField: function(inst, noDefault) {
5212 if (inst.input.val() === inst.lastVal) {
5213 return;
5214 }
5215
5216 var dateFormat = this._get(inst, "dateFormat"),
5217 dates = inst.lastVal = inst.input ? inst.input.val() : null,
5218 defaultDate = this._getDefaultDate(inst),
5219 date = defaultDate,
5220 settings = this._getFormatConfig(inst);
5221
5222 try {
5223 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
5224 } catch (event) {
5225 dates = (noDefault ? "" : dates);
5226 }
5227 inst.selectedDay = date.getDate();
5228 inst.drawMonth = inst.selectedMonth = date.getMonth();
5229 inst.drawYear = inst.selectedYear = date.getFullYear();
5230 inst.currentDay = (dates ? date.getDate() : 0);
5231 inst.currentMonth = (dates ? date.getMonth() : 0);
5232 inst.currentYear = (dates ? date.getFullYear() : 0);
5233 this._adjustInstDate(inst);
5234 },
5235
5236 /* Retrieve the default date shown on opening. */
5237 _getDefaultDate: function(inst) {
5238 return this._restrictMinMax(inst,
5239 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
5240 },
5241
5242 /* A date may be specified as an exact value or a relative one. */
5243 _determineDate: function(inst, date, defaultDate) {
5244 var offsetNumeric = function(offset) {
5245 var date = new Date();
5246 date.setDate(date.getDate() + offset);
5247 return date;
5248 },
5249 offsetString = function(offset) {
5250 try {
5251 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
5252 offset, $.datepicker._getFormatConfig(inst));
5253 }
5254 catch (e) {
5255 // Ignore
5256 }
5257
5258 var date = (offset.toLowerCase().match(/^c/) ?
5259 $.datepicker._getDate(inst) : null) || new Date(),
5260 year = date.getFullYear(),
5261 month = date.getMonth(),
5262 day = date.getDate(),
5263 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
5264 matches = pattern.exec(offset);
5265
5266 while (matches) {
5267 switch (matches[2] || "d") {
5268 case "d" : case "D" :
5269 day += parseInt(matches[1],10); break;
5270 case "w" : case "W" :
5271 day += parseInt(matches[1],10) * 7; break;
5272 case "m" : case "M" :
5273 month += parseInt(matches[1],10);
5274 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5275 break;
5276 case "y": case "Y" :
5277 year += parseInt(matches[1],10);
5278 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
5279 break;
5280 }
5281 matches = pattern.exec(offset);
5282 }
5283 return new Date(year, month, day);
5284 },
5285 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
5286 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
5287
5288 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
5289 if (newDate) {
5290 newDate.setHours(0);
5291 newDate.setMinutes(0);
5292 newDate.setSeconds(0);
5293 newDate.setMilliseconds(0);
5294 }
5295 return this._daylightSavingAdjust(newDate);
5296 },
5297
5298 /* Handle switch to/from daylight saving.
5299 * Hours may be non-zero on daylight saving cut-over:
5300 * > 12 when midnight changeover, but then cannot generate
5301 * midnight datetime, so jump to 1AM, otherwise reset.
5302 * @param date (Date) the date to check
5303 * @return (Date) the corrected date
5304 */
5305 _daylightSavingAdjust: function(date) {
5306 if (!date) {
5307 return null;
5308 }
5309 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
5310 return date;
5311 },
5312
5313 /* Set the date(s) directly. */
5314 _setDate: function(inst, date, noChange) {
5315 var clear = !date,
5316 origMonth = inst.selectedMonth,
5317 origYear = inst.selectedYear,
5318 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
5319
5320 inst.selectedDay = inst.currentDay = newDate.getDate();
5321 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
5322 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
5323 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
5324 this._notifyChange(inst);
5325 }
5326 this._adjustInstDate(inst);
5327 if (inst.input) {
5328 inst.input.val(clear ? "" : this._formatDate(inst));
5329 }
5330 },
5331
5332 /* Retrieve the date(s) directly. */
5333 _getDate: function(inst) {
5334 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
5335 this._daylightSavingAdjust(new Date(
5336 inst.currentYear, inst.currentMonth, inst.currentDay)));
5337 return startDate;
5338 },
5339
5340 /* Attach the onxxx handlers. These are declared statically so
5341 * they work with static code transformers like Caja.
5342 */
5343 _attachHandlers: function(inst) {
5344 var stepMonths = this._get(inst, "stepMonths"),
5345 id = "#" + inst.id.replace( /\\\\/g, "\\" );
5346 inst.dpDiv.find("[data-handler]").map(function () {
5347 var handler = {
5348 prev: function () {
5349 $.datepicker._adjustDate(id, -stepMonths, "M");
5350 },
5351 next: function () {
5352 $.datepicker._adjustDate(id, +stepMonths, "M");
5353 },
5354 hide: function () {
5355 $.datepicker._hideDatepicker();
5356 },
5357 today: function () {
5358 $.datepicker._gotoToday(id);
5359 },
5360 selectDay: function () {
5361 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
5362 return false;
5363 },
5364 selectMonth: function () {
5365 $.datepicker._selectMonthYear(id, this, "M");
5366 return false;
5367 },
5368 selectYear: function () {
5369 $.datepicker._selectMonthYear(id, this, "Y");
5370 return false;
5371 }
5372 };
5373 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
5374 });
5375 },
5376
5377 /* Generate the HTML for the current state of the date picker. */
5378 _generateHTML: function(inst) {
5379 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
5380 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
5381 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
5382 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
5383 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
5384 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
5385 tempDate = new Date(),
5386 today = this._daylightSavingAdjust(
5387 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
5388 isRTL = this._get(inst, "isRTL"),
5389 showButtonPanel = this._get(inst, "showButtonPanel"),
5390 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
5391 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
5392 numMonths = this._getNumberOfMonths(inst),
5393 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
5394 stepMonths = this._get(inst, "stepMonths"),
5395 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
5396 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
5397 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
5398 minDate = this._getMinMaxDate(inst, "min"),
5399 maxDate = this._getMinMaxDate(inst, "max"),
5400 drawMonth = inst.drawMonth - showCurrentAtPos,
5401 drawYear = inst.drawYear;
5402
5403 if (drawMonth < 0) {
5404 drawMonth += 12;
5405 drawYear--;
5406 }
5407 if (maxDate) {
5408 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
5409 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
5410 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
5411 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
5412 drawMonth--;
5413 if (drawMonth < 0) {
5414 drawMonth = 11;
5415 drawYear--;
5416 }
5417 }
5418 }
5419 inst.drawMonth = drawMonth;
5420 inst.drawYear = drawYear;
5421
5422 prevText = this._get(inst, "prevText");
5423 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
5424 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
5425 this._getFormatConfig(inst)));
5426
5427 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
5428 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
5429 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
5430 (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>"));
5431
5432 nextText = this._get(inst, "nextText");
5433 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
5434 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
5435 this._getFormatConfig(inst)));
5436
5437 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
5438 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
5439 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
5440 (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>"));
5441
5442 currentText = this._get(inst, "currentText");
5443 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
5444 currentText = (!navigationAsDateFormat ? currentText :
5445 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
5446
5447 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'>" +
5448 this._get(inst, "closeText") + "</button>" : "");
5449
5450 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
5451 (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'" +
5452 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
5453
5454 firstDay = parseInt(this._get(inst, "firstDay"),10);
5455 firstDay = (isNaN(firstDay) ? 0 : firstDay);
5456
5457 showWeek = this._get(inst, "showWeek");
5458 dayNames = this._get(inst, "dayNames");
5459 dayNamesMin = this._get(inst, "dayNamesMin");
5460 monthNames = this._get(inst, "monthNames");
5461 monthNamesShort = this._get(inst, "monthNamesShort");
5462 beforeShowDay = this._get(inst, "beforeShowDay");
5463 showOtherMonths = this._get(inst, "showOtherMonths");
5464 selectOtherMonths = this._get(inst, "selectOtherMonths");
5465 defaultDate = this._getDefaultDate(inst);
5466 html = "";
5467 dow;
5468 for (row = 0; row < numMonths[0]; row++) {
5469 group = "";
5470 this.maxRows = 4;
5471 for (col = 0; col < numMonths[1]; col++) {
5472 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
5473 cornerClass = " ui-corner-all";
5474 calender = "";
5475 if (isMultiMonth) {
5476 calender += "<div class='ui-datepicker-group";
5477 if (numMonths[1] > 1) {
5478 switch (col) {
5479 case 0: calender += " ui-datepicker-group-first";
5480 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
5481 case numMonths[1]-1: calender += " ui-datepicker-group-last";
5482 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
5483 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
5484 }
5485 }
5486 calender += "'>";
5487 }
5488 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
5489 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
5490 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
5491 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
5492 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
5493 "</div><table class='ui-datepicker-calendar'><thead>" +
5494 "<tr>";
5495 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
5496 for (dow = 0; dow < 7; dow++) { // days of the week
5497 day = (dow + firstDay) % 7;
5498 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
5499 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
5500 }
5501 calender += thead + "</tr></thead><tbody>";
5502 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
5503 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
5504 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
5505 }
5506 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
5507 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
5508 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
5509 this.maxRows = numRows;
5510 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
5511 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
5512 calender += "<tr>";
5513 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
5514 this._get(inst, "calculateWeek")(printDate) + "</td>");
5515 for (dow = 0; dow < 7; dow++) { // create date picker days
5516 daySettings = (beforeShowDay ?
5517 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
5518 otherMonth = (printDate.getMonth() !== drawMonth);
5519 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
5520 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
5521 tbody += "<td class='" +
5522 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
5523 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
5524 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
5525 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
5526 // or defaultDate is current printedDate and defaultDate is selectedDate
5527 " " + this._dayOverClass : "") + // highlight selected day
5528 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
5529 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
5530 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
5531 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
5532 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
5533 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
5534 (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
5535 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
5536 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
5537 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
5538 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
5539 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
5540 printDate.setDate(printDate.getDate() + 1);
5541 printDate = this._daylightSavingAdjust(printDate);
5542 }
5543 calender += tbody + "</tr>";
5544 }
5545 drawMonth++;
5546 if (drawMonth > 11) {
5547 drawMonth = 0;
5548 drawYear++;
5549 }
5550 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
5551 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
5552 group += calender;
5553 }
5554 html += group;
5555 }
5556 html += buttonPanel;
5557 inst._keyEvent = false;
5558 return html;
5559 },
5560
5561 /* Generate the month and year header. */
5562 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
5563 secondary, monthNames, monthNamesShort) {
5564
5565 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
5566 changeMonth = this._get(inst, "changeMonth"),
5567 changeYear = this._get(inst, "changeYear"),
5568 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
5569 html = "<div class='ui-datepicker-title'>",
5570 monthHtml = "";
5571
5572 // month selection
5573 if (secondary || !changeMonth) {
5574 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
5575 } else {
5576 inMinYear = (minDate && minDate.getFullYear() === drawYear);
5577 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
5578 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
5579 for ( month = 0; month < 12; month++) {
5580 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
5581 monthHtml += "<option value='" + month + "'" +
5582 (month === drawMonth ? " selected='selected'" : "") +
5583 ">" + monthNamesShort[month] + "</option>";
5584 }
5585 }
5586 monthHtml += "</select>";
5587 }
5588
5589 if (!showMonthAfterYear) {
5590 html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
5591 }
5592
5593 // year selection
5594 if ( !inst.yearshtml ) {
5595 inst.yearshtml = "";
5596 if (secondary || !changeYear) {
5597 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
5598 } else {
5599 // determine range of years to display
5600 years = this._get(inst, "yearRange").split(":");
5601 thisYear = new Date().getFullYear();
5602 determineYear = function(value) {
5603 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
5604 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
5605 parseInt(value, 10)));
5606 return (isNaN(year) ? thisYear : year);
5607 };
5608 year = determineYear(years[0]);
5609 endYear = Math.max(year, determineYear(years[1] || ""));
5610 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
5611 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
5612 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
5613 for (; year <= endYear; year++) {
5614 inst.yearshtml += "<option value='" + year + "'" +
5615 (year === drawYear ? " selected='selected'" : "") +
5616 ">" + year + "</option>";
5617 }
5618 inst.yearshtml += "</select>";
5619
5620 html += inst.yearshtml;
5621 inst.yearshtml = null;
5622 }
5623 }
5624
5625 html += this._get(inst, "yearSuffix");
5626 if (showMonthAfterYear) {
5627 html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
5628 }
5629 html += "</div>"; // Close datepicker_header
5630 return html;
5631 },
5632
5633 /* Adjust one of the date sub-fields. */
5634 _adjustInstDate: function(inst, offset, period) {
5635 var year = inst.drawYear + (period === "Y" ? offset : 0),
5636 month = inst.drawMonth + (period === "M" ? offset : 0),
5637 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
5638 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
5639
5640 inst.selectedDay = date.getDate();
5641 inst.drawMonth = inst.selectedMonth = date.getMonth();
5642 inst.drawYear = inst.selectedYear = date.getFullYear();
5643 if (period === "M" || period === "Y") {
5644 this._notifyChange(inst);
5645 }
5646 },
5647
5648 /* Ensure a date is within any min/max bounds. */
5649 _restrictMinMax: function(inst, date) {
5650 var minDate = this._getMinMaxDate(inst, "min"),
5651 maxDate = this._getMinMaxDate(inst, "max"),
5652 newDate = (minDate && date < minDate ? minDate : date);
5653 return (maxDate && newDate > maxDate ? maxDate : newDate);
5654 },
5655
5656 /* Notify change of month/year. */
5657 _notifyChange: function(inst) {
5658 var onChange = this._get(inst, "onChangeMonthYear");
5659 if (onChange) {
5660 onChange.apply((inst.input ? inst.input[0] : null),
5661 [inst.selectedYear, inst.selectedMonth + 1, inst]);
5662 }
5663 },
5664
5665 /* Determine the number of months to show. */
5666 _getNumberOfMonths: function(inst) {
5667 var numMonths = this._get(inst, "numberOfMonths");
5668 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
5669 },
5670
5671 /* Determine the current maximum date - ensure no time components are set. */
5672 _getMinMaxDate: function(inst, minMax) {
5673 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
5674 },
5675
5676 /* Find the number of days in a given month. */
5677 _getDaysInMonth: function(year, month) {
5678 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
5679 },
5680
5681 /* Find the day of the week of the first of a month. */
5682 _getFirstDayOfMonth: function(year, month) {
5683 return new Date(year, month, 1).getDay();
5684 },
5685
5686 /* Determines if we should allow a "next/prev" month display change. */
5687 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
5688 var numMonths = this._getNumberOfMonths(inst),
5689 date = this._daylightSavingAdjust(new Date(curYear,
5690 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
5691
5692 if (offset < 0) {
5693 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
5694 }
5695 return this._isInRange(inst, date);
5696 },
5697
5698 /* Is the given date in the accepted range? */
5699 _isInRange: function(inst, date) {
5700 var yearSplit, currentYear,
5701 minDate = this._getMinMaxDate(inst, "min"),
5702 maxDate = this._getMinMaxDate(inst, "max"),
5703 minYear = null,
5704 maxYear = null,
5705 years = this._get(inst, "yearRange");
5706 if (years){
5707 yearSplit = years.split(":");
5708 currentYear = new Date().getFullYear();
5709 minYear = parseInt(yearSplit[0], 10);
5710 maxYear = parseInt(yearSplit[1], 10);
5711 if ( yearSplit[0].match(/[+\-].*/) ) {
5712 minYear += currentYear;
5713 }
5714 if ( yearSplit[1].match(/[+\-].*/) ) {
5715 maxYear += currentYear;
5716 }
5717 }
5718
5719 return ((!minDate || date.getTime() >= minDate.getTime()) &&
5720 (!maxDate || date.getTime() <= maxDate.getTime()) &&
5721 (!minYear || date.getFullYear() >= minYear) &&
5722 (!maxYear || date.getFullYear() <= maxYear));
5723 },
5724
5725 /* Provide the configuration settings for formatting/parsing. */
5726 _getFormatConfig: function(inst) {
5727 var shortYearCutoff = this._get(inst, "shortYearCutoff");
5728 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
5729 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
5730 return {shortYearCutoff: shortYearCutoff,
5731 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
5732 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
5733 },
5734
5735 /* Format the given date for display. */
5736 _formatDate: function(inst, day, month, year) {
5737 if (!day) {
5738 inst.currentDay = inst.selectedDay;
5739 inst.currentMonth = inst.selectedMonth;
5740 inst.currentYear = inst.selectedYear;
5741 }
5742 var date = (day ? (typeof day === "object" ? day :
5743 this._daylightSavingAdjust(new Date(year, month, day))) :
5744 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
5745 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
5746 }
5747 });
5748
5749 /*
5750 * Bind hover events for datepicker elements.
5751 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
5752 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
5753 */
5754 function datepicker_bindHover(dpDiv) {
5755 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
5756 return dpDiv.delegate(selector, "mouseout", function() {
5757 $(this).removeClass("ui-state-hover");
5758 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5759 $(this).removeClass("ui-datepicker-prev-hover");
5760 }
5761 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5762 $(this).removeClass("ui-datepicker-next-hover");
5763 }
5764 })
5765 .delegate( selector, "mouseover", datepicker_handleMouseover );
5766 }
5767
5768 function datepicker_handleMouseover() {
5769 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
5770 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
5771 $(this).addClass("ui-state-hover");
5772 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
5773 $(this).addClass("ui-datepicker-prev-hover");
5774 }
5775 if (this.className.indexOf("ui-datepicker-next") !== -1) {
5776 $(this).addClass("ui-datepicker-next-hover");
5777 }
5778 }
5779 }
5780
5781 /* jQuery extend now ignores nulls! */
5782 function datepicker_extendRemove(target, props) {
5783 $.extend(target, props);
5784 for (var name in props) {
5785 if (props[name] == null) {
5786 target[name] = props[name];
5787 }
5788 }
5789 return target;
5790 }
5791
5792 /* Invoke the datepicker functionality.
5793 @param options string - a command, optionally followed by additional parameters or
5794 Object - settings for attaching new datepicker functionality
5795 @return jQuery object */
5796 $.fn.datepicker = function(options){
5797
5798 /* Verify an empty collection wasn't passed - Fixes #6976 */
5799 if ( !this.length ) {
5800 return this;
5801 }
5802
5803 /* Initialise the date picker. */
5804 if (!$.datepicker.initialized) {
5805 $(document).mousedown($.datepicker._checkExternalClick);
5806 $.datepicker.initialized = true;
5807 }
5808
5809 /* Append datepicker main container to body if not exist. */
5810 if ($("#"+$.datepicker._mainDivId).length === 0) {
5811 $("body").append($.datepicker.dpDiv);
5812 }
5813
5814 var otherArgs = Array.prototype.slice.call(arguments, 1);
5815 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
5816 return $.datepicker["_" + options + "Datepicker"].
5817 apply($.datepicker, [this[0]].concat(otherArgs));
5818 }
5819 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
5820 return $.datepicker["_" + options + "Datepicker"].
5821 apply($.datepicker, [this[0]].concat(otherArgs));
5822 }
5823 return this.each(function() {
5824 typeof options === "string" ?
5825 $.datepicker["_" + options + "Datepicker"].
5826 apply($.datepicker, [this].concat(otherArgs)) :
5827 $.datepicker._attachDatepicker(this, options);
5828 });
5829 };
5830
5831 $.datepicker = new Datepicker(); // singleton instance
5832 $.datepicker.initialized = false;
5833 $.datepicker.uuid = new Date().getTime();
5834 $.datepicker.version = "1.11.4";
5835
5836 var datepicker = $.datepicker;
5837
5838
5839 /*!
5840 * jQuery UI Draggable 1.11.4
5841 * http://jqueryui.com
5842 *
5843 * Copyright jQuery Foundation and other contributors
5844 * Released under the MIT license.
5845 * http://jquery.org/license
5846 *
5847 * http://api.jqueryui.com/draggable/
5848 */
5849
5850
5851 $.widget("ui.draggable", $.ui.mouse, {
5852 version: "1.11.4",
5853 widgetEventPrefix: "drag",
5854 options: {
5855 addClasses: true,
5856 appendTo: "parent",
5857 axis: false,
5858 connectToSortable: false,
5859 containment: false,
5860 cursor: "auto",
5861 cursorAt: false,
5862 grid: false,
5863 handle: false,
5864 helper: "original",
5865 iframeFix: false,
5866 opacity: false,
5867 refreshPositions: false,
5868 revert: false,
5869 revertDuration: 500,
5870 scope: "default",
5871 scroll: true,
5872 scrollSensitivity: 20,
5873 scrollSpeed: 20,
5874 snap: false,
5875 snapMode: "both",
5876 snapTolerance: 20,
5877 stack: false,
5878 zIndex: false,
5879
5880 // callbacks
5881 drag: null,
5882 start: null,
5883 stop: null
5884 },
5885 _create: function() {
5886
5887 if ( this.options.helper === "original" ) {
5888 this._setPositionRelative();
5889 }
5890 if (this.options.addClasses){
5891 this.element.addClass("ui-draggable");
5892 }
5893 if (this.options.disabled){
5894 this.element.addClass("ui-draggable-disabled");
5895 }
5896 this._setHandleClassName();
5897
5898 this._mouseInit();
5899 },
5900
5901 _setOption: function( key, value ) {
5902 this._super( key, value );
5903 if ( key === "handle" ) {
5904 this._removeHandleClassName();
5905 this._setHandleClassName();
5906 }
5907 },
5908
5909 _destroy: function() {
5910 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
5911 this.destroyOnClear = true;
5912 return;
5913 }
5914 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
5915 this._removeHandleClassName();
5916 this._mouseDestroy();
5917 },
5918
5919 _mouseCapture: function(event) {
5920 var o = this.options;
5921
5922 this._blurActiveElement( event );
5923
5924 // among others, prevent a drag on a resizable-handle
5925 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
5926 return false;
5927 }
5928
5929 //Quit if we're not on a valid handle
5930 this.handle = this._getHandle(event);
5931 if (!this.handle) {
5932 return false;
5933 }
5934
5935 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
5936
5937 return true;
5938
5939 },
5940
5941 _blockFrames: function( selector ) {
5942 this.iframeBlocks = this.document.find( selector ).map(function() {
5943 var iframe = $( this );
5944
5945 return $( "<div>" )
5946 .css( "position", "absolute" )
5947 .appendTo( iframe.parent() )
5948 .outerWidth( iframe.outerWidth() )
5949 .outerHeight( iframe.outerHeight() )
5950 .offset( iframe.offset() )[ 0 ];
5951 });
5952 },
5953
5954 _unblockFrames: function() {
5955 if ( this.iframeBlocks ) {
5956 this.iframeBlocks.remove();
5957 delete this.iframeBlocks;
5958 }
5959 },
5960
5961 _blurActiveElement: function( event ) {
5962 var document = this.document[ 0 ];
5963
5964 // Only need to blur if the event occurred on the draggable itself, see #10527
5965 if ( !this.handleElement.is( event.target ) ) {
5966 return;
5967 }
5968
5969 // support: IE9
5970 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
5971 try {
5972
5973 // Support: IE9, IE10
5974 // If the <body> is blurred, IE will switch windows, see #9520
5975 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
5976
5977 // Blur any element that currently has focus, see #4261
5978 $( document.activeElement ).blur();
5979 }
5980 } catch ( error ) {}
5981 },
5982
5983 _mouseStart: function(event) {
5984
5985 var o = this.options;
5986
5987 //Create and append the visible helper
5988 this.helper = this._createHelper(event);
5989
5990 this.helper.addClass("ui-draggable-dragging");
5991
5992 //Cache the helper size
5993 this._cacheHelperProportions();
5994
5995 //If ddmanager is used for droppables, set the global draggable
5996 if ($.ui.ddmanager) {
5997 $.ui.ddmanager.current = this;
5998 }
5999
6000 /*
6001 * - Position generation -
6002 * This block generates everything position related - it's the core of draggables.
6003 */
6004
6005 //Cache the margins of the original element
6006 this._cacheMargins();
6007
6008 //Store the helper's css position
6009 this.cssPosition = this.helper.css( "position" );
6010 this.scrollParent = this.helper.scrollParent( true );
6011 this.offsetParent = this.helper.offsetParent();
6012 this.hasFixedAncestor = this.helper.parents().filter(function() {
6013 return $( this ).css( "position" ) === "fixed";
6014 }).length > 0;
6015
6016 //The element's absolute position on the page minus margins
6017 this.positionAbs = this.element.offset();
6018 this._refreshOffsets( event );
6019
6020 //Generate the original position
6021 this.originalPosition = this.position = this._generatePosition( event, false );
6022 this.originalPageX = event.pageX;
6023 this.originalPageY = event.pageY;
6024
6025 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
6026 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
6027
6028 //Set a containment if given in the options
6029 this._setContainment();
6030
6031 //Trigger event + callbacks
6032 if (this._trigger("start", event) === false) {
6033 this._clear();
6034 return false;
6035 }
6036
6037 //Recache the helper size
6038 this._cacheHelperProportions();
6039
6040 //Prepare the droppable offsets
6041 if ($.ui.ddmanager && !o.dropBehaviour) {
6042 $.ui.ddmanager.prepareOffsets(this, event);
6043 }
6044
6045 // Reset helper's right/bottom css if they're set and set explicit width/height instead
6046 // as this prevents resizing of elements with right/bottom set (see #7772)
6047 this._normalizeRightBottom();
6048
6049 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
6050
6051 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
6052 if ( $.ui.ddmanager ) {
6053 $.ui.ddmanager.dragStart(this, event);
6054 }
6055
6056 return true;
6057 },
6058
6059 _refreshOffsets: function( event ) {
6060 this.offset = {
6061 top: this.positionAbs.top - this.margins.top,
6062 left: this.positionAbs.left - this.margins.left,
6063 scroll: false,
6064 parent: this._getParentOffset(),
6065 relative: this._getRelativeOffset()
6066 };
6067
6068 this.offset.click = {
6069 left: event.pageX - this.offset.left,
6070 top: event.pageY - this.offset.top
6071 };
6072 },
6073
6074 _mouseDrag: function(event, noPropagation) {
6075 // reset any necessary cached properties (see #5009)
6076 if ( this.hasFixedAncestor ) {
6077 this.offset.parent = this._getParentOffset();
6078 }
6079
6080 //Compute the helpers position
6081 this.position = this._generatePosition( event, true );
6082 this.positionAbs = this._convertPositionTo("absolute");
6083
6084 //Call plugins and callbacks and use the resulting position if something is returned
6085 if (!noPropagation) {
6086 var ui = this._uiHash();
6087 if (this._trigger("drag", event, ui) === false) {
6088 this._mouseUp({});
6089 return false;
6090 }
6091 this.position = ui.position;
6092 }
6093
6094 this.helper[ 0 ].style.left = this.position.left + "px";
6095 this.helper[ 0 ].style.top = this.position.top + "px";
6096
6097 if ($.ui.ddmanager) {
6098 $.ui.ddmanager.drag(this, event);
6099 }
6100
6101 return false;
6102 },
6103
6104 _mouseStop: function(event) {
6105
6106 //If we are using droppables, inform the manager about the drop
6107 var that = this,
6108 dropped = false;
6109 if ($.ui.ddmanager && !this.options.dropBehaviour) {
6110 dropped = $.ui.ddmanager.drop(this, event);
6111 }
6112
6113 //if a drop comes from outside (a sortable)
6114 if (this.dropped) {
6115 dropped = this.dropped;
6116 this.dropped = false;
6117 }
6118
6119 if ((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
6120 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
6121 if (that._trigger("stop", event) !== false) {
6122 that._clear();
6123 }
6124 });
6125 } else {
6126 if (this._trigger("stop", event) !== false) {
6127 this._clear();
6128 }
6129 }
6130
6131 return false;
6132 },
6133
6134 _mouseUp: function( event ) {
6135 this._unblockFrames();
6136
6137 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
6138 if ( $.ui.ddmanager ) {
6139 $.ui.ddmanager.dragStop(this, event);
6140 }
6141
6142 // Only need to focus if the event occurred on the draggable itself, see #10527
6143 if ( this.handleElement.is( event.target ) ) {
6144 // The interaction is over; whether or not the click resulted in a drag, focus the element
6145 this.element.focus();
6146 }
6147
6148 return $.ui.mouse.prototype._mouseUp.call(this, event);
6149 },
6150
6151 cancel: function() {
6152
6153 if (this.helper.is(".ui-draggable-dragging")) {
6154 this._mouseUp({});
6155 } else {
6156 this._clear();
6157 }
6158
6159 return this;
6160
6161 },
6162
6163 _getHandle: function(event) {
6164 return this.options.handle ?
6165 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
6166 true;
6167 },
6168
6169 _setHandleClassName: function() {
6170 this.handleElement = this.options.handle ?
6171 this.element.find( this.options.handle ) : this.element;
6172 this.handleElement.addClass( "ui-draggable-handle" );
6173 },
6174
6175 _removeHandleClassName: function() {
6176 this.handleElement.removeClass( "ui-draggable-handle" );
6177 },
6178
6179 _createHelper: function(event) {
6180
6181 var o = this.options,
6182 helperIsFunction = $.isFunction( o.helper ),
6183 helper = helperIsFunction ?
6184 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
6185 ( o.helper === "clone" ?
6186 this.element.clone().removeAttr( "id" ) :
6187 this.element );
6188
6189 if (!helper.parents("body").length) {
6190 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
6191 }
6192
6193 // http://bugs.jqueryui.com/ticket/9446
6194 // a helper function can return the original element
6195 // which wouldn't have been set to relative in _create
6196 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
6197 this._setPositionRelative();
6198 }
6199
6200 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
6201 helper.css("position", "absolute");
6202 }
6203
6204 return helper;
6205
6206 },
6207
6208 _setPositionRelative: function() {
6209 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
6210 this.element[ 0 ].style.position = "relative";
6211 }
6212 },
6213
6214 _adjustOffsetFromHelper: function(obj) {
6215 if (typeof obj === "string") {
6216 obj = obj.split(" ");
6217 }
6218 if ($.isArray(obj)) {
6219 obj = { left: +obj[0], top: +obj[1] || 0 };
6220 }
6221 if ("left" in obj) {
6222 this.offset.click.left = obj.left + this.margins.left;
6223 }
6224 if ("right" in obj) {
6225 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
6226 }
6227 if ("top" in obj) {
6228 this.offset.click.top = obj.top + this.margins.top;
6229 }
6230 if ("bottom" in obj) {
6231 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
6232 }
6233 },
6234
6235 _isRootNode: function( element ) {
6236 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
6237 },
6238
6239 _getParentOffset: function() {
6240
6241 //Get the offsetParent and cache its position
6242 var po = this.offsetParent.offset(),
6243 document = this.document[ 0 ];
6244
6245 // This is a special case where we need to modify a offset calculated on start, since the following happened:
6246 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
6247 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
6248 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
6249 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
6250 po.left += this.scrollParent.scrollLeft();
6251 po.top += this.scrollParent.scrollTop();
6252 }
6253
6254 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
6255 po = { top: 0, left: 0 };
6256 }
6257
6258 return {
6259 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
6260 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
6261 };
6262
6263 },
6264
6265 _getRelativeOffset: function() {
6266 if ( this.cssPosition !== "relative" ) {
6267 return { top: 0, left: 0 };
6268 }
6269
6270 var p = this.element.position(),
6271 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6272
6273 return {
6274 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
6275 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
6276 };
6277
6278 },
6279
6280 _cacheMargins: function() {
6281 this.margins = {
6282 left: (parseInt(this.element.css("marginLeft"), 10) || 0),
6283 top: (parseInt(this.element.css("marginTop"), 10) || 0),
6284 right: (parseInt(this.element.css("marginRight"), 10) || 0),
6285 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
6286 };
6287 },
6288
6289 _cacheHelperProportions: function() {
6290 this.helperProportions = {
6291 width: this.helper.outerWidth(),
6292 height: this.helper.outerHeight()
6293 };
6294 },
6295
6296 _setContainment: function() {
6297
6298 var isUserScrollable, c, ce,
6299 o = this.options,
6300 document = this.document[ 0 ];
6301
6302 this.relativeContainer = null;
6303
6304 if ( !o.containment ) {
6305 this.containment = null;
6306 return;
6307 }
6308
6309 if ( o.containment === "window" ) {
6310 this.containment = [
6311 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
6312 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
6313 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
6314 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6315 ];
6316 return;
6317 }
6318
6319 if ( o.containment === "document") {
6320 this.containment = [
6321 0,
6322 0,
6323 $( document ).width() - this.helperProportions.width - this.margins.left,
6324 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
6325 ];
6326 return;
6327 }
6328
6329 if ( o.containment.constructor === Array ) {
6330 this.containment = o.containment;
6331 return;
6332 }
6333
6334 if ( o.containment === "parent" ) {
6335 o.containment = this.helper[ 0 ].parentNode;
6336 }
6337
6338 c = $( o.containment );
6339 ce = c[ 0 ];
6340
6341 if ( !ce ) {
6342 return;
6343 }
6344
6345 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
6346
6347 this.containment = [
6348 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
6349 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
6350 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
6351 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
6352 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
6353 this.helperProportions.width -
6354 this.margins.left -
6355 this.margins.right,
6356 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
6357 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
6358 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
6359 this.helperProportions.height -
6360 this.margins.top -
6361 this.margins.bottom
6362 ];
6363 this.relativeContainer = c;
6364 },
6365
6366 _convertPositionTo: function(d, pos) {
6367
6368 if (!pos) {
6369 pos = this.position;
6370 }
6371
6372 var mod = d === "absolute" ? 1 : -1,
6373 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
6374
6375 return {
6376 top: (
6377 pos.top + // The absolute mouse position
6378 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6379 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
6380 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
6381 ),
6382 left: (
6383 pos.left + // The absolute mouse position
6384 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
6385 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
6386 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
6387 )
6388 };
6389
6390 },
6391
6392 _generatePosition: function( event, constrainPosition ) {
6393
6394 var containment, co, top, left,
6395 o = this.options,
6396 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
6397 pageX = event.pageX,
6398 pageY = event.pageY;
6399
6400 // Cache the scroll
6401 if ( !scrollIsRootNode || !this.offset.scroll ) {
6402 this.offset.scroll = {
6403 top: this.scrollParent.scrollTop(),
6404 left: this.scrollParent.scrollLeft()
6405 };
6406 }
6407
6408 /*
6409 * - Position constraining -
6410 * Constrain the position to a mix of grid, containment.
6411 */
6412
6413 // If we are not dragging yet, we won't check for options
6414 if ( constrainPosition ) {
6415 if ( this.containment ) {
6416 if ( this.relativeContainer ){
6417 co = this.relativeContainer.offset();
6418 containment = [
6419 this.containment[ 0 ] + co.left,
6420 this.containment[ 1 ] + co.top,
6421 this.containment[ 2 ] + co.left,
6422 this.containment[ 3 ] + co.top
6423 ];
6424 } else {
6425 containment = this.containment;
6426 }
6427
6428 if (event.pageX - this.offset.click.left < containment[0]) {
6429 pageX = containment[0] + this.offset.click.left;
6430 }
6431 if (event.pageY - this.offset.click.top < containment[1]) {
6432 pageY = containment[1] + this.offset.click.top;
6433 }
6434 if (event.pageX - this.offset.click.left > containment[2]) {
6435 pageX = containment[2] + this.offset.click.left;
6436 }
6437 if (event.pageY - this.offset.click.top > containment[3]) {
6438 pageY = containment[3] + this.offset.click.top;
6439 }
6440 }
6441
6442 if (o.grid) {
6443 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
6444 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
6445 pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
6446
6447 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
6448 pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
6449 }
6450
6451 if ( o.axis === "y" ) {
6452 pageX = this.originalPageX;
6453 }
6454
6455 if ( o.axis === "x" ) {
6456 pageY = this.originalPageY;
6457 }
6458 }
6459
6460 return {
6461 top: (
6462 pageY - // The absolute mouse position
6463 this.offset.click.top - // Click offset (relative to the element)
6464 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
6465 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
6466 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
6467 ),
6468 left: (
6469 pageX - // The absolute mouse position
6470 this.offset.click.left - // Click offset (relative to the element)
6471 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
6472 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
6473 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
6474 )
6475 };
6476
6477 },
6478
6479 _clear: function() {
6480 this.helper.removeClass("ui-draggable-dragging");
6481 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
6482 this.helper.remove();
6483 }
6484 this.helper = null;
6485 this.cancelHelperRemoval = false;
6486 if ( this.destroyOnClear ) {
6487 this.destroy();
6488 }
6489 },
6490
6491 _normalizeRightBottom: function() {
6492 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
6493 this.helper.width( this.helper.width() );
6494 this.helper.css( "right", "auto" );
6495 }
6496 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
6497 this.helper.height( this.helper.height() );
6498 this.helper.css( "bottom", "auto" );
6499 }
6500 },
6501
6502 // From now on bulk stuff - mainly helpers
6503
6504 _trigger: function( type, event, ui ) {
6505 ui = ui || this._uiHash();
6506 $.ui.plugin.call( this, type, [ event, ui, this ], true );
6507
6508 // Absolute position and offset (see #6884 ) have to be recalculated after plugins
6509 if ( /^(drag|start|stop)/.test( type ) ) {
6510 this.positionAbs = this._convertPositionTo( "absolute" );
6511 ui.offset = this.positionAbs;
6512 }
6513 return $.Widget.prototype._trigger.call( this, type, event, ui );
6514 },
6515
6516 plugins: {},
6517
6518 _uiHash: function() {
6519 return {
6520 helper: this.helper,
6521 position: this.position,
6522 originalPosition: this.originalPosition,
6523 offset: this.positionAbs
6524 };
6525 }
6526
6527 });
6528
6529 $.ui.plugin.add( "draggable", "connectToSortable", {
6530 start: function( event, ui, draggable ) {
6531 var uiSortable = $.extend( {}, ui, {
6532 item: draggable.element
6533 });
6534
6535 draggable.sortables = [];
6536 $( draggable.options.connectToSortable ).each(function() {
6537 var sortable = $( this ).sortable( "instance" );
6538
6539 if ( sortable && !sortable.options.disabled ) {
6540 draggable.sortables.push( sortable );
6541
6542 // refreshPositions is called at drag start to refresh the containerCache
6543 // which is used in drag. This ensures it's initialized and synchronized
6544 // with any changes that might have happened on the page since initialization.
6545 sortable.refreshPositions();
6546 sortable._trigger("activate", event, uiSortable);
6547 }
6548 });
6549 },
6550 stop: function( event, ui, draggable ) {
6551 var uiSortable = $.extend( {}, ui, {
6552 item: draggable.element
6553 });
6554
6555 draggable.cancelHelperRemoval = false;
6556
6557 $.each( draggable.sortables, function() {
6558 var sortable = this;
6559
6560 if ( sortable.isOver ) {
6561 sortable.isOver = 0;
6562
6563 // Allow this sortable to handle removing the helper
6564 draggable.cancelHelperRemoval = true;
6565 sortable.cancelHelperRemoval = false;
6566
6567 // Use _storedCSS To restore properties in the sortable,
6568 // as this also handles revert (#9675) since the draggable
6569 // may have modified them in unexpected ways (#8809)
6570 sortable._storedCSS = {
6571 position: sortable.placeholder.css( "position" ),
6572 top: sortable.placeholder.css( "top" ),
6573 left: sortable.placeholder.css( "left" )
6574 };
6575
6576 sortable._mouseStop(event);
6577
6578 // Once drag has ended, the sortable should return to using
6579 // its original helper, not the shared helper from draggable
6580 sortable.options.helper = sortable.options._helper;
6581 } else {
6582 // Prevent this Sortable from removing the helper.
6583 // However, don't set the draggable to remove the helper
6584 // either as another connected Sortable may yet handle the removal.
6585 sortable.cancelHelperRemoval = true;
6586
6587 sortable._trigger( "deactivate", event, uiSortable );
6588 }
6589 });
6590 },
6591 drag: function( event, ui, draggable ) {
6592 $.each( draggable.sortables, function() {
6593 var innermostIntersecting = false,
6594 sortable = this;
6595
6596 // Copy over variables that sortable's _intersectsWith uses
6597 sortable.positionAbs = draggable.positionAbs;
6598 sortable.helperProportions = draggable.helperProportions;
6599 sortable.offset.click = draggable.offset.click;
6600
6601 if ( sortable._intersectsWith( sortable.containerCache ) ) {
6602 innermostIntersecting = true;
6603
6604 $.each( draggable.sortables, function() {
6605 // Copy over variables that sortable's _intersectsWith uses
6606 this.positionAbs = draggable.positionAbs;
6607 this.helperProportions = draggable.helperProportions;
6608 this.offset.click = draggable.offset.click;
6609
6610 if ( this !== sortable &&
6611 this._intersectsWith( this.containerCache ) &&
6612 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
6613 innermostIntersecting = false;
6614 }
6615
6616 return innermostIntersecting;
6617 });
6618 }
6619
6620 if ( innermostIntersecting ) {
6621 // If it intersects, we use a little isOver variable and set it once,
6622 // so that the move-in stuff gets fired only once.
6623 if ( !sortable.isOver ) {
6624 sortable.isOver = 1;
6625
6626 // Store draggable's parent in case we need to reappend to it later.
6627 draggable._parent = ui.helper.parent();
6628
6629 sortable.currentItem = ui.helper
6630 .appendTo( sortable.element )
6631 .data( "ui-sortable-item", true );
6632
6633 // Store helper option to later restore it
6634 sortable.options._helper = sortable.options.helper;
6635
6636 sortable.options.helper = function() {
6637 return ui.helper[ 0 ];
6638 };
6639
6640 // Fire the start events of the sortable with our passed browser event,
6641 // and our own helper (so it doesn't create a new one)
6642 event.target = sortable.currentItem[ 0 ];
6643 sortable._mouseCapture( event, true );
6644 sortable._mouseStart( event, true, true );
6645
6646 // Because the browser event is way off the new appended portlet,
6647 // modify necessary variables to reflect the changes
6648 sortable.offset.click.top = draggable.offset.click.top;
6649 sortable.offset.click.left = draggable.offset.click.left;
6650 sortable.offset.parent.left -= draggable.offset.parent.left -
6651 sortable.offset.parent.left;
6652 sortable.offset.parent.top -= draggable.offset.parent.top -
6653 sortable.offset.parent.top;
6654
6655 draggable._trigger( "toSortable", event );
6656
6657 // Inform draggable that the helper is in a valid drop zone,
6658 // used solely in the revert option to handle "valid/invalid".
6659 draggable.dropped = sortable.element;
6660
6661 // Need to refreshPositions of all sortables in the case that
6662 // adding to one sortable changes the location of the other sortables (#9675)
6663 $.each( draggable.sortables, function() {
6664 this.refreshPositions();
6665 });
6666
6667 // hack so receive/update callbacks work (mostly)
6668 draggable.currentItem = draggable.element;
6669 sortable.fromOutside = draggable;
6670 }
6671
6672 if ( sortable.currentItem ) {
6673 sortable._mouseDrag( event );
6674 // Copy the sortable's position because the draggable's can potentially reflect
6675 // a relative position, while sortable is always absolute, which the dragged
6676 // element has now become. (#8809)
6677 ui.position = sortable.position;
6678 }
6679 } else {
6680 // If it doesn't intersect with the sortable, and it intersected before,
6681 // we fake the drag stop of the sortable, but make sure it doesn't remove
6682 // the helper by using cancelHelperRemoval.
6683 if ( sortable.isOver ) {
6684
6685 sortable.isOver = 0;
6686 sortable.cancelHelperRemoval = true;
6687
6688 // Calling sortable's mouseStop would trigger a revert,
6689 // so revert must be temporarily false until after mouseStop is called.
6690 sortable.options._revert = sortable.options.revert;
6691 sortable.options.revert = false;
6692
6693 sortable._trigger( "out", event, sortable._uiHash( sortable ) );
6694 sortable._mouseStop( event, true );
6695
6696 // restore sortable behaviors that were modfied
6697 // when the draggable entered the sortable area (#9481)
6698 sortable.options.revert = sortable.options._revert;
6699 sortable.options.helper = sortable.options._helper;
6700
6701 if ( sortable.placeholder ) {
6702 sortable.placeholder.remove();
6703 }
6704
6705 // Restore and recalculate the draggable's offset considering the sortable
6706 // may have modified them in unexpected ways. (#8809, #10669)
6707 ui.helper.appendTo( draggable._parent );
6708 draggable._refreshOffsets( event );
6709 ui.position = draggable._generatePosition( event, true );
6710
6711 draggable._trigger( "fromSortable", event );
6712
6713 // Inform draggable that the helper is no longer in a valid drop zone
6714 draggable.dropped = false;
6715
6716 // Need to refreshPositions of all sortables just in case removing
6717 // from one sortable changes the location of other sortables (#9675)
6718 $.each( draggable.sortables, function() {
6719 this.refreshPositions();
6720 });
6721 }
6722 }
6723 });
6724 }
6725 });
6726
6727 $.ui.plugin.add("draggable", "cursor", {
6728 start: function( event, ui, instance ) {
6729 var t = $( "body" ),
6730 o = instance.options;
6731
6732 if (t.css("cursor")) {
6733 o._cursor = t.css("cursor");
6734 }
6735 t.css("cursor", o.cursor);
6736 },
6737 stop: function( event, ui, instance ) {
6738 var o = instance.options;
6739 if (o._cursor) {
6740 $("body").css("cursor", o._cursor);
6741 }
6742 }
6743 });
6744
6745 $.ui.plugin.add("draggable", "opacity", {
6746 start: function( event, ui, instance ) {
6747 var t = $( ui.helper ),
6748 o = instance.options;
6749 if (t.css("opacity")) {
6750 o._opacity = t.css("opacity");
6751 }
6752 t.css("opacity", o.opacity);
6753 },
6754 stop: function( event, ui, instance ) {
6755 var o = instance.options;
6756 if (o._opacity) {
6757 $(ui.helper).css("opacity", o._opacity);
6758 }
6759 }
6760 });
6761
6762 $.ui.plugin.add("draggable", "scroll", {
6763 start: function( event, ui, i ) {
6764 if ( !i.scrollParentNotHidden ) {
6765 i.scrollParentNotHidden = i.helper.scrollParent( false );
6766 }
6767
6768 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
6769 i.overflowOffset = i.scrollParentNotHidden.offset();
6770 }
6771 },
6772 drag: function( event, ui, i ) {
6773
6774 var o = i.options,
6775 scrolled = false,
6776 scrollParent = i.scrollParentNotHidden[ 0 ],
6777 document = i.document[ 0 ];
6778
6779 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
6780 if ( !o.axis || o.axis !== "x" ) {
6781 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
6782 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
6783 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
6784 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
6785 }
6786 }
6787
6788 if ( !o.axis || o.axis !== "y" ) {
6789 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
6790 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
6791 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
6792 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
6793 }
6794 }
6795
6796 } else {
6797
6798 if (!o.axis || o.axis !== "x") {
6799 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
6800 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
6801 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
6802 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
6803 }
6804 }
6805
6806 if (!o.axis || o.axis !== "y") {
6807 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
6808 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
6809 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
6810 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
6811 }
6812 }
6813
6814 }
6815
6816 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
6817 $.ui.ddmanager.prepareOffsets(i, event);
6818 }
6819
6820 }
6821 });
6822
6823 $.ui.plugin.add("draggable", "snap", {
6824 start: function( event, ui, i ) {
6825
6826 var o = i.options;
6827
6828 i.snapElements = [];
6829
6830 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
6831 var $t = $(this),
6832 $o = $t.offset();
6833 if (this !== i.element[0]) {
6834 i.snapElements.push({
6835 item: this,
6836 width: $t.outerWidth(), height: $t.outerHeight(),
6837 top: $o.top, left: $o.left
6838 });
6839 }
6840 });
6841
6842 },
6843 drag: function( event, ui, inst ) {
6844
6845 var ts, bs, ls, rs, l, r, t, b, i, first,
6846 o = inst.options,
6847 d = o.snapTolerance,
6848 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
6849 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
6850
6851 for (i = inst.snapElements.length - 1; i >= 0; i--){
6852
6853 l = inst.snapElements[i].left - inst.margins.left;
6854 r = l + inst.snapElements[i].width;
6855 t = inst.snapElements[i].top - inst.margins.top;
6856 b = t + inst.snapElements[i].height;
6857
6858 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
6859 if (inst.snapElements[i].snapping) {
6860 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6861 }
6862 inst.snapElements[i].snapping = false;
6863 continue;
6864 }
6865
6866 if (o.snapMode !== "inner") {
6867 ts = Math.abs(t - y2) <= d;
6868 bs = Math.abs(b - y1) <= d;
6869 ls = Math.abs(l - x2) <= d;
6870 rs = Math.abs(r - x1) <= d;
6871 if (ts) {
6872 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
6873 }
6874 if (bs) {
6875 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
6876 }
6877 if (ls) {
6878 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
6879 }
6880 if (rs) {
6881 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
6882 }
6883 }
6884
6885 first = (ts || bs || ls || rs);
6886
6887 if (o.snapMode !== "outer") {
6888 ts = Math.abs(t - y1) <= d;
6889 bs = Math.abs(b - y2) <= d;
6890 ls = Math.abs(l - x1) <= d;
6891 rs = Math.abs(r - x2) <= d;
6892 if (ts) {
6893 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
6894 }
6895 if (bs) {
6896 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
6897 }
6898 if (ls) {
6899 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
6900 }
6901 if (rs) {
6902 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
6903 }
6904 }
6905
6906 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
6907 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
6908 }
6909 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
6910
6911 }
6912
6913 }
6914 });
6915
6916 $.ui.plugin.add("draggable", "stack", {
6917 start: function( event, ui, instance ) {
6918 var min,
6919 o = instance.options,
6920 group = $.makeArray($(o.stack)).sort(function(a, b) {
6921 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
6922 });
6923
6924 if (!group.length) { return; }
6925
6926 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
6927 $(group).each(function(i) {
6928 $(this).css("zIndex", min + i);
6929 });
6930 this.css("zIndex", (min + group.length));
6931 }
6932 });
6933
6934 $.ui.plugin.add("draggable", "zIndex", {
6935 start: function( event, ui, instance ) {
6936 var t = $( ui.helper ),
6937 o = instance.options;
6938
6939 if (t.css("zIndex")) {
6940 o._zIndex = t.css("zIndex");
6941 }
6942 t.css("zIndex", o.zIndex);
6943 },
6944 stop: function( event, ui, instance ) {
6945 var o = instance.options;
6946
6947 if (o._zIndex) {
6948 $(ui.helper).css("zIndex", o._zIndex);
6949 }
6950 }
6951 });
6952
6953 var draggable = $.ui.draggable;
6954
6955
6956 /*!
6957 * jQuery UI Resizable 1.11.4
6958 * http://jqueryui.com
6959 *
6960 * Copyright jQuery Foundation and other contributors
6961 * Released under the MIT license.
6962 * http://jquery.org/license
6963 *
6964 * http://api.jqueryui.com/resizable/
6965 */
6966
6967
6968 $.widget("ui.resizable", $.ui.mouse, {
6969 version: "1.11.4",
6970 widgetEventPrefix: "resize",
6971 options: {
6972 alsoResize: false,
6973 animate: false,
6974 animateDuration: "slow",
6975 animateEasing: "swing",
6976 aspectRatio: false,
6977 autoHide: false,
6978 containment: false,
6979 ghost: false,
6980 grid: false,
6981 handles: "e,s,se",
6982 helper: false,
6983 maxHeight: null,
6984 maxWidth: null,
6985 minHeight: 10,
6986 minWidth: 10,
6987 // See #7960
6988 zIndex: 90,
6989
6990 // callbacks
6991 resize: null,
6992 start: null,
6993 stop: null
6994 },
6995
6996 _num: function( value ) {
6997 return parseInt( value, 10 ) || 0;
6998 },
6999
7000 _isNumber: function( value ) {
7001 return !isNaN( parseInt( value, 10 ) );
7002 },
7003
7004 _hasScroll: function( el, a ) {
7005
7006 if ( $( el ).css( "overflow" ) === "hidden") {
7007 return false;
7008 }
7009
7010 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
7011 has = false;
7012
7013 if ( el[ scroll ] > 0 ) {
7014 return true;
7015 }
7016
7017 // TODO: determine which cases actually cause this to happen
7018 // if the element doesn't have the scroll set, see if it's possible to
7019 // set the scroll
7020 el[ scroll ] = 1;
7021 has = ( el[ scroll ] > 0 );
7022 el[ scroll ] = 0;
7023 return has;
7024 },
7025
7026 _create: function() {
7027
7028 var n, i, handle, axis, hname,
7029 that = this,
7030 o = this.options;
7031 this.element.addClass("ui-resizable");
7032
7033 $.extend(this, {
7034 _aspectRatio: !!(o.aspectRatio),
7035 aspectRatio: o.aspectRatio,
7036 originalElement: this.element,
7037 _proportionallyResizeElements: [],
7038 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
7039 });
7040
7041 // Wrap the element if it cannot hold child nodes
7042 if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) {
7043
7044 this.element.wrap(
7045 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
7046 position: this.element.css("position"),
7047 width: this.element.outerWidth(),
7048 height: this.element.outerHeight(),
7049 top: this.element.css("top"),
7050 left: this.element.css("left")
7051 })
7052 );
7053
7054 this.element = this.element.parent().data(
7055 "ui-resizable", this.element.resizable( "instance" )
7056 );
7057
7058 this.elementIsWrapper = true;
7059
7060 this.element.css({
7061 marginLeft: this.originalElement.css("marginLeft"),
7062 marginTop: this.originalElement.css("marginTop"),
7063 marginRight: this.originalElement.css("marginRight"),
7064 marginBottom: this.originalElement.css("marginBottom")
7065 });
7066 this.originalElement.css({
7067 marginLeft: 0,
7068 marginTop: 0,
7069 marginRight: 0,
7070 marginBottom: 0
7071 });
7072 // support: Safari
7073 // Prevent Safari textarea resize
7074 this.originalResizeStyle = this.originalElement.css("resize");
7075 this.originalElement.css("resize", "none");
7076
7077 this._proportionallyResizeElements.push( this.originalElement.css({
7078 position: "static",
7079 zoom: 1,
7080 display: "block"
7081 }) );
7082
7083 // support: IE9
7084 // avoid IE jump (hard set the margin)
7085 this.originalElement.css({ margin: this.originalElement.css("margin") });
7086
7087 this._proportionallyResize();
7088 }
7089
7090 this.handles = o.handles ||
7091 ( !$(".ui-resizable-handle", this.element).length ?
7092 "e,s,se" : {
7093 n: ".ui-resizable-n",
7094 e: ".ui-resizable-e",
7095 s: ".ui-resizable-s",
7096 w: ".ui-resizable-w",
7097 se: ".ui-resizable-se",
7098 sw: ".ui-resizable-sw",
7099 ne: ".ui-resizable-ne",
7100 nw: ".ui-resizable-nw"
7101 } );
7102
7103 this._handles = $();
7104 if ( this.handles.constructor === String ) {
7105
7106 if ( this.handles === "all") {
7107 this.handles = "n,e,s,w,se,sw,ne,nw";
7108 }
7109
7110 n = this.handles.split(",");
7111 this.handles = {};
7112
7113 for (i = 0; i < n.length; i++) {
7114
7115 handle = $.trim(n[i]);
7116 hname = "ui-resizable-" + handle;
7117 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
7118
7119 axis.css({ zIndex: o.zIndex });
7120
7121 // TODO : What's going on here?
7122 if ("se" === handle) {
7123 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
7124 }
7125
7126 this.handles[handle] = ".ui-resizable-" + handle;
7127 this.element.append(axis);
7128 }
7129
7130 }
7131
7132 this._renderAxis = function(target) {
7133
7134 var i, axis, padPos, padWrapper;
7135
7136 target = target || this.element;
7137
7138 for (i in this.handles) {
7139
7140 if (this.handles[i].constructor === String) {
7141 this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
7142 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
7143 this.handles[ i ] = $( this.handles[ i ] );
7144 this._on( this.handles[ i ], { "mousedown": that._mouseDown });
7145 }
7146
7147 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) {
7148
7149 axis = $(this.handles[i], this.element);
7150
7151 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
7152
7153 padPos = [ "padding",
7154 /ne|nw|n/.test(i) ? "Top" :
7155 /se|sw|s/.test(i) ? "Bottom" :
7156 /^e$/.test(i) ? "Right" : "Left" ].join("");
7157
7158 target.css(padPos, padWrapper);
7159
7160 this._proportionallyResize();
7161 }
7162
7163 this._handles = this._handles.add( this.handles[ i ] );
7164 }
7165 };
7166
7167 // TODO: make renderAxis a prototype function
7168 this._renderAxis(this.element);
7169
7170 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
7171 this._handles.disableSelection();
7172
7173 this._handles.mouseover(function() {
7174 if (!that.resizing) {
7175 if (this.className) {
7176 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
7177 }
7178 that.axis = axis && axis[1] ? axis[1] : "se";
7179 }
7180 });
7181
7182 if (o.autoHide) {
7183 this._handles.hide();
7184 $(this.element)
7185 .addClass("ui-resizable-autohide")
7186 .mouseenter(function() {
7187 if (o.disabled) {
7188 return;
7189 }
7190 $(this).removeClass("ui-resizable-autohide");
7191 that._handles.show();
7192 })
7193 .mouseleave(function() {
7194 if (o.disabled) {
7195 return;
7196 }
7197 if (!that.resizing) {
7198 $(this).addClass("ui-resizable-autohide");
7199 that._handles.hide();
7200 }
7201 });
7202 }
7203
7204 this._mouseInit();
7205 },
7206
7207 _destroy: function() {
7208
7209 this._mouseDestroy();
7210
7211 var wrapper,
7212 _destroy = function(exp) {
7213 $(exp)
7214 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
7215 .removeData("resizable")
7216 .removeData("ui-resizable")
7217 .unbind(".resizable")
7218 .find(".ui-resizable-handle")
7219 .remove();
7220 };
7221
7222 // TODO: Unwrap at same DOM position
7223 if (this.elementIsWrapper) {
7224 _destroy(this.element);
7225 wrapper = this.element;
7226 this.originalElement.css({
7227 position: wrapper.css("position"),
7228 width: wrapper.outerWidth(),
7229 height: wrapper.outerHeight(),
7230 top: wrapper.css("top"),
7231 left: wrapper.css("left")
7232 }).insertAfter( wrapper );
7233 wrapper.remove();
7234 }
7235
7236 this.originalElement.css("resize", this.originalResizeStyle);
7237 _destroy(this.originalElement);
7238
7239 return this;
7240 },
7241
7242 _mouseCapture: function(event) {
7243 var i, handle,
7244 capture = false;
7245
7246 for (i in this.handles) {
7247 handle = $(this.handles[i])[0];
7248 if (handle === event.target || $.contains(handle, event.target)) {
7249 capture = true;
7250 }
7251 }
7252
7253 return !this.options.disabled && capture;
7254 },
7255
7256 _mouseStart: function(event) {
7257
7258 var curleft, curtop, cursor,
7259 o = this.options,
7260 el = this.element;
7261
7262 this.resizing = true;
7263
7264 this._renderProxy();
7265
7266 curleft = this._num(this.helper.css("left"));
7267 curtop = this._num(this.helper.css("top"));
7268
7269 if (o.containment) {
7270 curleft += $(o.containment).scrollLeft() || 0;
7271 curtop += $(o.containment).scrollTop() || 0;
7272 }
7273
7274 this.offset = this.helper.offset();
7275 this.position = { left: curleft, top: curtop };
7276
7277 this.size = this._helper ? {
7278 width: this.helper.width(),
7279 height: this.helper.height()
7280 } : {
7281 width: el.width(),
7282 height: el.height()
7283 };
7284
7285 this.originalSize = this._helper ? {
7286 width: el.outerWidth(),
7287 height: el.outerHeight()
7288 } : {
7289 width: el.width(),
7290 height: el.height()
7291 };
7292
7293 this.sizeDiff = {
7294 width: el.outerWidth() - el.width(),
7295 height: el.outerHeight() - el.height()
7296 };
7297
7298 this.originalPosition = { left: curleft, top: curtop };
7299 this.originalMousePosition = { left: event.pageX, top: event.pageY };
7300
7301 this.aspectRatio = (typeof o.aspectRatio === "number") ?
7302 o.aspectRatio :
7303 ((this.originalSize.width / this.originalSize.height) || 1);
7304
7305 cursor = $(".ui-resizable-" + this.axis).css("cursor");
7306 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
7307
7308 el.addClass("ui-resizable-resizing");
7309 this._propagate("start", event);
7310 return true;
7311 },
7312
7313 _mouseDrag: function(event) {
7314
7315 var data, props,
7316 smp = this.originalMousePosition,
7317 a = this.axis,
7318 dx = (event.pageX - smp.left) || 0,
7319 dy = (event.pageY - smp.top) || 0,
7320 trigger = this._change[a];
7321
7322 this._updatePrevProperties();
7323
7324 if (!trigger) {
7325 return false;
7326 }
7327
7328 data = trigger.apply(this, [ event, dx, dy ]);
7329
7330 this._updateVirtualBoundaries(event.shiftKey);
7331 if (this._aspectRatio || event.shiftKey) {
7332 data = this._updateRatio(data, event);
7333 }
7334
7335 data = this._respectSize(data, event);
7336
7337 this._updateCache(data);
7338
7339 this._propagate("resize", event);
7340
7341 props = this._applyChanges();
7342
7343 if ( !this._helper && this._proportionallyResizeElements.length ) {
7344 this._proportionallyResize();
7345 }
7346
7347 if ( !$.isEmptyObject( props ) ) {
7348 this._updatePrevProperties();
7349 this._trigger( "resize", event, this.ui() );
7350 this._applyChanges();
7351 }
7352
7353 return false;
7354 },
7355
7356 _mouseStop: function(event) {
7357
7358 this.resizing = false;
7359 var pr, ista, soffseth, soffsetw, s, left, top,
7360 o = this.options, that = this;
7361
7362 if (this._helper) {
7363
7364 pr = this._proportionallyResizeElements;
7365 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
7366 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
7367 soffsetw = ista ? 0 : that.sizeDiff.width;
7368
7369 s = {
7370 width: (that.helper.width() - soffsetw),
7371 height: (that.helper.height() - soffseth)
7372 };
7373 left = (parseInt(that.element.css("left"), 10) +
7374 (that.position.left - that.originalPosition.left)) || null;
7375 top = (parseInt(that.element.css("top"), 10) +
7376 (that.position.top - that.originalPosition.top)) || null;
7377
7378 if (!o.animate) {
7379 this.element.css($.extend(s, { top: top, left: left }));
7380 }
7381
7382 that.helper.height(that.size.height);
7383 that.helper.width(that.size.width);
7384
7385 if (this._helper && !o.animate) {
7386 this._proportionallyResize();
7387 }
7388 }
7389
7390 $("body").css("cursor", "auto");
7391
7392 this.element.removeClass("ui-resizable-resizing");
7393
7394 this._propagate("stop", event);
7395
7396 if (this._helper) {
7397 this.helper.remove();
7398 }
7399
7400 return false;
7401
7402 },
7403
7404 _updatePrevProperties: function() {
7405 this.prevPosition = {
7406 top: this.position.top,
7407 left: this.position.left
7408 };
7409 this.prevSize = {
7410 width: this.size.width,
7411 height: this.size.height
7412 };
7413 },
7414
7415 _applyChanges: function() {
7416 var props = {};
7417
7418 if ( this.position.top !== this.prevPosition.top ) {
7419 props.top = this.position.top + "px";
7420 }
7421 if ( this.position.left !== this.prevPosition.left ) {
7422 props.left = this.position.left + "px";
7423 }
7424 if ( this.size.width !== this.prevSize.width ) {
7425 props.width = this.size.width + "px";
7426 }
7427 if ( this.size.height !== this.prevSize.height ) {
7428 props.height = this.size.height + "px";
7429 }
7430
7431 this.helper.css( props );
7432
7433 return props;
7434 },
7435
7436 _updateVirtualBoundaries: function(forceAspectRatio) {
7437 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
7438 o = this.options;
7439
7440 b = {
7441 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
7442 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
7443 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
7444 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
7445 };
7446
7447 if (this._aspectRatio || forceAspectRatio) {
7448 pMinWidth = b.minHeight * this.aspectRatio;
7449 pMinHeight = b.minWidth / this.aspectRatio;
7450 pMaxWidth = b.maxHeight * this.aspectRatio;
7451 pMaxHeight = b.maxWidth / this.aspectRatio;
7452
7453 if (pMinWidth > b.minWidth) {
7454 b.minWidth = pMinWidth;
7455 }
7456 if (pMinHeight > b.minHeight) {
7457 b.minHeight = pMinHeight;
7458 }
7459 if (pMaxWidth < b.maxWidth) {
7460 b.maxWidth = pMaxWidth;
7461 }
7462 if (pMaxHeight < b.maxHeight) {
7463 b.maxHeight = pMaxHeight;
7464 }
7465 }
7466 this._vBoundaries = b;
7467 },
7468
7469 _updateCache: function(data) {
7470 this.offset = this.helper.offset();
7471 if (this._isNumber(data.left)) {
7472 this.position.left = data.left;
7473 }
7474 if (this._isNumber(data.top)) {
7475 this.position.top = data.top;
7476 }
7477 if (this._isNumber(data.height)) {
7478 this.size.height = data.height;
7479 }
7480 if (this._isNumber(data.width)) {
7481 this.size.width = data.width;
7482 }
7483 },
7484
7485 _updateRatio: function( data ) {
7486
7487 var cpos = this.position,
7488 csize = this.size,
7489 a = this.axis;
7490
7491 if (this._isNumber(data.height)) {
7492 data.width = (data.height * this.aspectRatio);
7493 } else if (this._isNumber(data.width)) {
7494 data.height = (data.width / this.aspectRatio);
7495 }
7496
7497 if (a === "sw") {
7498 data.left = cpos.left + (csize.width - data.width);
7499 data.top = null;
7500 }
7501 if (a === "nw") {
7502 data.top = cpos.top + (csize.height - data.height);
7503 data.left = cpos.left + (csize.width - data.width);
7504 }
7505
7506 return data;
7507 },
7508
7509 _respectSize: function( data ) {
7510
7511 var o = this._vBoundaries,
7512 a = this.axis,
7513 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
7514 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
7515 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
7516 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
7517 dw = this.originalPosition.left + this.originalSize.width,
7518 dh = this.position.top + this.size.height,
7519 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
7520 if (isminw) {
7521 data.width = o.minWidth;
7522 }
7523 if (isminh) {
7524 data.height = o.minHeight;
7525 }
7526 if (ismaxw) {
7527 data.width = o.maxWidth;
7528 }
7529 if (ismaxh) {
7530 data.height = o.maxHeight;
7531 }
7532
7533 if (isminw && cw) {
7534 data.left = dw - o.minWidth;
7535 }
7536 if (ismaxw && cw) {
7537 data.left = dw - o.maxWidth;
7538 }
7539 if (isminh && ch) {
7540 data.top = dh - o.minHeight;
7541 }
7542 if (ismaxh && ch) {
7543 data.top = dh - o.maxHeight;
7544 }
7545
7546 // Fixing jump error on top/left - bug #2330
7547 if (!data.width && !data.height && !data.left && data.top) {
7548 data.top = null;
7549 } else if (!data.width && !data.height && !data.top && data.left) {
7550 data.left = null;
7551 }
7552
7553 return data;
7554 },
7555
7556 _getPaddingPlusBorderDimensions: function( element ) {
7557 var i = 0,
7558 widths = [],
7559 borders = [
7560 element.css( "borderTopWidth" ),
7561 element.css( "borderRightWidth" ),
7562 element.css( "borderBottomWidth" ),
7563 element.css( "borderLeftWidth" )
7564 ],
7565 paddings = [
7566 element.css( "paddingTop" ),
7567 element.css( "paddingRight" ),
7568 element.css( "paddingBottom" ),
7569 element.css( "paddingLeft" )
7570 ];
7571
7572 for ( ; i < 4; i++ ) {
7573 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
7574 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
7575 }
7576
7577 return {
7578 height: widths[ 0 ] + widths[ 2 ],
7579 width: widths[ 1 ] + widths[ 3 ]
7580 };
7581 },
7582
7583 _proportionallyResize: function() {
7584
7585 if (!this._proportionallyResizeElements.length) {
7586 return;
7587 }
7588
7589 var prel,
7590 i = 0,
7591 element = this.helper || this.element;
7592
7593 for ( ; i < this._proportionallyResizeElements.length; i++) {
7594
7595 prel = this._proportionallyResizeElements[i];
7596
7597 // TODO: Seems like a bug to cache this.outerDimensions
7598 // considering that we are in a loop.
7599 if (!this.outerDimensions) {
7600 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
7601 }
7602
7603 prel.css({
7604 height: (element.height() - this.outerDimensions.height) || 0,
7605 width: (element.width() - this.outerDimensions.width) || 0
7606 });
7607
7608 }
7609
7610 },
7611
7612 _renderProxy: function() {
7613
7614 var el = this.element, o = this.options;
7615 this.elementOffset = el.offset();
7616
7617 if (this._helper) {
7618
7619 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
7620
7621 this.helper.addClass(this._helper).css({
7622 width: this.element.outerWidth() - 1,
7623 height: this.element.outerHeight() - 1,
7624 position: "absolute",
7625 left: this.elementOffset.left + "px",
7626 top: this.elementOffset.top + "px",
7627 zIndex: ++o.zIndex //TODO: Don't modify option
7628 });
7629
7630 this.helper
7631 .appendTo("body")
7632 .disableSelection();
7633
7634 } else {
7635 this.helper = this.element;
7636 }
7637
7638 },
7639
7640 _change: {
7641 e: function(event, dx) {
7642 return { width: this.originalSize.width + dx };
7643 },
7644 w: function(event, dx) {
7645 var cs = this.originalSize, sp = this.originalPosition;
7646 return { left: sp.left + dx, width: cs.width - dx };
7647 },
7648 n: function(event, dx, dy) {
7649 var cs = this.originalSize, sp = this.originalPosition;
7650 return { top: sp.top + dy, height: cs.height - dy };
7651 },
7652 s: function(event, dx, dy) {
7653 return { height: this.originalSize.height + dy };
7654 },
7655 se: function(event, dx, dy) {
7656 return $.extend(this._change.s.apply(this, arguments),
7657 this._change.e.apply(this, [ event, dx, dy ]));
7658 },
7659 sw: function(event, dx, dy) {
7660 return $.extend(this._change.s.apply(this, arguments),
7661 this._change.w.apply(this, [ event, dx, dy ]));
7662 },
7663 ne: function(event, dx, dy) {
7664 return $.extend(this._change.n.apply(this, arguments),
7665 this._change.e.apply(this, [ event, dx, dy ]));
7666 },
7667 nw: function(event, dx, dy) {
7668 return $.extend(this._change.n.apply(this, arguments),
7669 this._change.w.apply(this, [ event, dx, dy ]));
7670 }
7671 },
7672
7673 _propagate: function(n, event) {
7674 $.ui.plugin.call(this, n, [ event, this.ui() ]);
7675 (n !== "resize" && this._trigger(n, event, this.ui()));
7676 },
7677
7678 plugins: {},
7679
7680 ui: function() {
7681 return {
7682 originalElement: this.originalElement,
7683 element: this.element,
7684 helper: this.helper,
7685 position: this.position,
7686 size: this.size,
7687 originalSize: this.originalSize,
7688 originalPosition: this.originalPosition
7689 };
7690 }
7691
7692 });
7693
7694 /*
7695 * Resizable Extensions
7696 */
7697
7698 $.ui.plugin.add("resizable", "animate", {
7699
7700 stop: function( event ) {
7701 var that = $(this).resizable( "instance" ),
7702 o = that.options,
7703 pr = that._proportionallyResizeElements,
7704 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
7705 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
7706 soffsetw = ista ? 0 : that.sizeDiff.width,
7707 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
7708 left = (parseInt(that.element.css("left"), 10) +
7709 (that.position.left - that.originalPosition.left)) || null,
7710 top = (parseInt(that.element.css("top"), 10) +
7711 (that.position.top - that.originalPosition.top)) || null;
7712
7713 that.element.animate(
7714 $.extend(style, top && left ? { top: top, left: left } : {}), {
7715 duration: o.animateDuration,
7716 easing: o.animateEasing,
7717 step: function() {
7718
7719 var data = {
7720 width: parseInt(that.element.css("width"), 10),
7721 height: parseInt(that.element.css("height"), 10),
7722 top: parseInt(that.element.css("top"), 10),
7723 left: parseInt(that.element.css("left"), 10)
7724 };
7725
7726 if (pr && pr.length) {
7727 $(pr[0]).css({ width: data.width, height: data.height });
7728 }
7729
7730 // propagating resize, and updating values for each animation step
7731 that._updateCache(data);
7732 that._propagate("resize", event);
7733
7734 }
7735 }
7736 );
7737 }
7738
7739 });
7740
7741 $.ui.plugin.add( "resizable", "containment", {
7742
7743 start: function() {
7744 var element, p, co, ch, cw, width, height,
7745 that = $( this ).resizable( "instance" ),
7746 o = that.options,
7747 el = that.element,
7748 oc = o.containment,
7749 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
7750
7751 if ( !ce ) {
7752 return;
7753 }
7754
7755 that.containerElement = $( ce );
7756
7757 if ( /document/.test( oc ) || oc === document ) {
7758 that.containerOffset = {
7759 left: 0,
7760 top: 0
7761 };
7762 that.containerPosition = {
7763 left: 0,
7764 top: 0
7765 };
7766
7767 that.parentData = {
7768 element: $( document ),
7769 left: 0,
7770 top: 0,
7771 width: $( document ).width(),
7772 height: $( document ).height() || document.body.parentNode.scrollHeight
7773 };
7774 } else {
7775 element = $( ce );
7776 p = [];
7777 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
7778 p[ i ] = that._num( element.css( "padding" + name ) );
7779 });
7780
7781 that.containerOffset = element.offset();
7782 that.containerPosition = element.position();
7783 that.containerSize = {
7784 height: ( element.innerHeight() - p[ 3 ] ),
7785 width: ( element.innerWidth() - p[ 1 ] )
7786 };
7787
7788 co = that.containerOffset;
7789 ch = that.containerSize.height;
7790 cw = that.containerSize.width;
7791 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
7792 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
7793
7794 that.parentData = {
7795 element: ce,
7796 left: co.left,
7797 top: co.top,
7798 width: width,
7799 height: height
7800 };
7801 }
7802 },
7803
7804 resize: function( event ) {
7805 var woset, hoset, isParent, isOffsetRelative,
7806 that = $( this ).resizable( "instance" ),
7807 o = that.options,
7808 co = that.containerOffset,
7809 cp = that.position,
7810 pRatio = that._aspectRatio || event.shiftKey,
7811 cop = {
7812 top: 0,
7813 left: 0
7814 },
7815 ce = that.containerElement,
7816 continueResize = true;
7817
7818 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
7819 cop = co;
7820 }
7821
7822 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
7823 that.size.width = that.size.width +
7824 ( that._helper ?
7825 ( that.position.left - co.left ) :
7826 ( that.position.left - cop.left ) );
7827
7828 if ( pRatio ) {
7829 that.size.height = that.size.width / that.aspectRatio;
7830 continueResize = false;
7831 }
7832 that.position.left = o.helper ? co.left : 0;
7833 }
7834
7835 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
7836 that.size.height = that.size.height +
7837 ( that._helper ?
7838 ( that.position.top - co.top ) :
7839 that.position.top );
7840
7841 if ( pRatio ) {
7842 that.size.width = that.size.height * that.aspectRatio;
7843 continueResize = false;
7844 }
7845 that.position.top = that._helper ? co.top : 0;
7846 }
7847
7848 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
7849 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
7850
7851 if ( isParent && isOffsetRelative ) {
7852 that.offset.left = that.parentData.left + that.position.left;
7853 that.offset.top = that.parentData.top + that.position.top;
7854 } else {
7855 that.offset.left = that.element.offset().left;
7856 that.offset.top = that.element.offset().top;
7857 }
7858
7859 woset = Math.abs( that.sizeDiff.width +
7860 (that._helper ?
7861 that.offset.left - cop.left :
7862 (that.offset.left - co.left)) );
7863
7864 hoset = Math.abs( that.sizeDiff.height +
7865 (that._helper ?
7866 that.offset.top - cop.top :
7867 (that.offset.top - co.top)) );
7868
7869 if ( woset + that.size.width >= that.parentData.width ) {
7870 that.size.width = that.parentData.width - woset;
7871 if ( pRatio ) {
7872 that.size.height = that.size.width / that.aspectRatio;
7873 continueResize = false;
7874 }
7875 }
7876
7877 if ( hoset + that.size.height >= that.parentData.height ) {
7878 that.size.height = that.parentData.height - hoset;
7879 if ( pRatio ) {
7880 that.size.width = that.size.height * that.aspectRatio;
7881 continueResize = false;
7882 }
7883 }
7884
7885 if ( !continueResize ) {
7886 that.position.left = that.prevPosition.left;
7887 that.position.top = that.prevPosition.top;
7888 that.size.width = that.prevSize.width;
7889 that.size.height = that.prevSize.height;
7890 }
7891 },
7892
7893 stop: function() {
7894 var that = $( this ).resizable( "instance" ),
7895 o = that.options,
7896 co = that.containerOffset,
7897 cop = that.containerPosition,
7898 ce = that.containerElement,
7899 helper = $( that.helper ),
7900 ho = helper.offset(),
7901 w = helper.outerWidth() - that.sizeDiff.width,
7902 h = helper.outerHeight() - that.sizeDiff.height;
7903
7904 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
7905 $( this ).css({
7906 left: ho.left - cop.left - co.left,
7907 width: w,
7908 height: h
7909 });
7910 }
7911
7912 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
7913 $( this ).css({
7914 left: ho.left - cop.left - co.left,
7915 width: w,
7916 height: h
7917 });
7918 }
7919 }
7920 });
7921
7922 $.ui.plugin.add("resizable", "alsoResize", {
7923
7924 start: function() {
7925 var that = $(this).resizable( "instance" ),
7926 o = that.options;
7927
7928 $(o.alsoResize).each(function() {
7929 var el = $(this);
7930 el.data("ui-resizable-alsoresize", {
7931 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
7932 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
7933 });
7934 });
7935 },
7936
7937 resize: function(event, ui) {
7938 var that = $(this).resizable( "instance" ),
7939 o = that.options,
7940 os = that.originalSize,
7941 op = that.originalPosition,
7942 delta = {
7943 height: (that.size.height - os.height) || 0,
7944 width: (that.size.width - os.width) || 0,
7945 top: (that.position.top - op.top) || 0,
7946 left: (that.position.left - op.left) || 0
7947 };
7948
7949 $(o.alsoResize).each(function() {
7950 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
7951 css = el.parents(ui.originalElement[0]).length ?
7952 [ "width", "height" ] :
7953 [ "width", "height", "top", "left" ];
7954
7955 $.each(css, function(i, prop) {
7956 var sum = (start[prop] || 0) + (delta[prop] || 0);
7957 if (sum && sum >= 0) {
7958 style[prop] = sum || null;
7959 }
7960 });
7961
7962 el.css(style);
7963 });
7964 },
7965
7966 stop: function() {
7967 $(this).removeData("resizable-alsoresize");
7968 }
7969 });
7970
7971 $.ui.plugin.add("resizable", "ghost", {
7972
7973 start: function() {
7974
7975 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
7976
7977 that.ghost = that.originalElement.clone();
7978 that.ghost
7979 .css({
7980 opacity: 0.25,
7981 display: "block",
7982 position: "relative",
7983 height: cs.height,
7984 width: cs.width,
7985 margin: 0,
7986 left: 0,
7987 top: 0
7988 })
7989 .addClass("ui-resizable-ghost")
7990 .addClass(typeof o.ghost === "string" ? o.ghost : "");
7991
7992 that.ghost.appendTo(that.helper);
7993
7994 },
7995
7996 resize: function() {
7997 var that = $(this).resizable( "instance" );
7998 if (that.ghost) {
7999 that.ghost.css({
8000 position: "relative",
8001 height: that.size.height,
8002 width: that.size.width
8003 });
8004 }
8005 },
8006
8007 stop: function() {
8008 var that = $(this).resizable( "instance" );
8009 if (that.ghost && that.helper) {
8010 that.helper.get(0).removeChild(that.ghost.get(0));
8011 }
8012 }
8013
8014 });
8015
8016 $.ui.plugin.add("resizable", "grid", {
8017
8018 resize: function() {
8019 var outerDimensions,
8020 that = $(this).resizable( "instance" ),
8021 o = that.options,
8022 cs = that.size,
8023 os = that.originalSize,
8024 op = that.originalPosition,
8025 a = that.axis,
8026 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
8027 gridX = (grid[0] || 1),
8028 gridY = (grid[1] || 1),
8029 ox = Math.round((cs.width - os.width) / gridX) * gridX,
8030 oy = Math.round((cs.height - os.height) / gridY) * gridY,
8031 newWidth = os.width + ox,
8032 newHeight = os.height + oy,
8033 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
8034 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
8035 isMinWidth = o.minWidth && (o.minWidth > newWidth),
8036 isMinHeight = o.minHeight && (o.minHeight > newHeight);
8037
8038 o.grid = grid;
8039
8040 if (isMinWidth) {
8041 newWidth += gridX;
8042 }
8043 if (isMinHeight) {
8044 newHeight += gridY;
8045 }
8046 if (isMaxWidth) {
8047 newWidth -= gridX;
8048 }
8049 if (isMaxHeight) {
8050 newHeight -= gridY;
8051 }
8052
8053 if (/^(se|s|e)$/.test(a)) {
8054 that.size.width = newWidth;
8055 that.size.height = newHeight;
8056 } else if (/^(ne)$/.test(a)) {
8057 that.size.width = newWidth;
8058 that.size.height = newHeight;
8059 that.position.top = op.top - oy;
8060 } else if (/^(sw)$/.test(a)) {
8061 that.size.width = newWidth;
8062 that.size.height = newHeight;
8063 that.position.left = op.left - ox;
8064 } else {
8065 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
8066 outerDimensions = that._getPaddingPlusBorderDimensions( this );
8067 }
8068
8069 if ( newHeight - gridY > 0 ) {
8070 that.size.height = newHeight;
8071 that.position.top = op.top - oy;
8072 } else {
8073 newHeight = gridY - outerDimensions.height;
8074 that.size.height = newHeight;
8075 that.position.top = op.top + os.height - newHeight;
8076 }
8077 if ( newWidth - gridX > 0 ) {
8078 that.size.width = newWidth;
8079 that.position.left = op.left - ox;
8080 } else {
8081 newWidth = gridX - outerDimensions.width;
8082 that.size.width = newWidth;
8083 that.position.left = op.left + os.width - newWidth;
8084 }
8085 }
8086 }
8087
8088 });
8089
8090 var resizable = $.ui.resizable;
8091
8092
8093 /*!
8094 * jQuery UI Dialog 1.11.4
8095 * http://jqueryui.com
8096 *
8097 * Copyright jQuery Foundation and other contributors
8098 * Released under the MIT license.
8099 * http://jquery.org/license
8100 *
8101 * http://api.jqueryui.com/dialog/
8102 */
8103
8104
8105 var dialog = $.widget( "ui.dialog", {
8106 version: "1.11.4",
8107 options: {
8108 appendTo: "body",
8109 autoOpen: true,
8110 buttons: [],
8111 closeOnEscape: true,
8112 closeText: "Close",
8113 dialogClass: "",
8114 draggable: true,
8115 hide: null,
8116 height: "auto",
8117 maxHeight: null,
8118 maxWidth: null,
8119 minHeight: 150,
8120 minWidth: 150,
8121 modal: false,
8122 position: {
8123 my: "center",
8124 at: "center",
8125 of: window,
8126 collision: "fit",
8127 // Ensure the titlebar is always visible
8128 using: function( pos ) {
8129 var topOffset = $( this ).css( pos ).offset().top;
8130 if ( topOffset < 0 ) {
8131 $( this ).css( "top", pos.top - topOffset );
8132 }
8133 }
8134 },
8135 resizable: true,
8136 show: null,
8137 title: null,
8138 width: 300,
8139
8140 // callbacks
8141 beforeClose: null,
8142 close: null,
8143 drag: null,
8144 dragStart: null,
8145 dragStop: null,
8146 focus: null,
8147 open: null,
8148 resize: null,
8149 resizeStart: null,
8150 resizeStop: null
8151 },
8152
8153 sizeRelatedOptions: {
8154 buttons: true,
8155 height: true,
8156 maxHeight: true,
8157 maxWidth: true,
8158 minHeight: true,
8159 minWidth: true,
8160 width: true
8161 },
8162
8163 resizableRelatedOptions: {
8164 maxHeight: true,
8165 maxWidth: true,
8166 minHeight: true,
8167 minWidth: true
8168 },
8169
8170 _create: function() {
8171 this.originalCss = {
8172 display: this.element[ 0 ].style.display,
8173 width: this.element[ 0 ].style.width,
8174 minHeight: this.element[ 0 ].style.minHeight,
8175 maxHeight: this.element[ 0 ].style.maxHeight,
8176 height: this.element[ 0 ].style.height
8177 };
8178 this.originalPosition = {
8179 parent: this.element.parent(),
8180 index: this.element.parent().children().index( this.element )
8181 };
8182 this.originalTitle = this.element.attr( "title" );
8183 this.options.title = this.options.title || this.originalTitle;
8184
8185 this._createWrapper();
8186
8187 this.element
8188 .show()
8189 .removeAttr( "title" )
8190 .addClass( "ui-dialog-content ui-widget-content" )
8191 .appendTo( this.uiDialog );
8192
8193 this._createTitlebar();
8194 this._createButtonPane();
8195
8196 if ( this.options.draggable && $.fn.draggable ) {
8197 this._makeDraggable();
8198 }
8199 if ( this.options.resizable && $.fn.resizable ) {
8200 this._makeResizable();
8201 }
8202
8203 this._isOpen = false;
8204
8205 this._trackFocus();
8206 },
8207
8208 _init: function() {
8209 if ( this.options.autoOpen ) {
8210 this.open();
8211 }
8212 },
8213
8214 _appendTo: function() {
8215 var element = this.options.appendTo;
8216 if ( element && (element.jquery || element.nodeType) ) {
8217 return $( element );
8218 }
8219 return this.document.find( element || "body" ).eq( 0 );
8220 },
8221
8222 _destroy: function() {
8223 var next,
8224 originalPosition = this.originalPosition;
8225
8226 this._untrackInstance();
8227 this._destroyOverlay();
8228
8229 this.element
8230 .removeUniqueId()
8231 .removeClass( "ui-dialog-content ui-widget-content" )
8232 .css( this.originalCss )
8233 // Without detaching first, the following becomes really slow
8234 .detach();
8235
8236 this.uiDialog.stop( true, true ).remove();
8237
8238 if ( this.originalTitle ) {
8239 this.element.attr( "title", this.originalTitle );
8240 }
8241
8242 next = originalPosition.parent.children().eq( originalPosition.index );
8243 // Don't try to place the dialog next to itself (#8613)
8244 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
8245 next.before( this.element );
8246 } else {
8247 originalPosition.parent.append( this.element );
8248 }
8249 },
8250
8251 widget: function() {
8252 return this.uiDialog;
8253 },
8254
8255 disable: $.noop,
8256 enable: $.noop,
8257
8258 close: function( event ) {
8259 var activeElement,
8260 that = this;
8261
8262 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
8263 return;
8264 }
8265
8266 this._isOpen = false;
8267 this._focusedElement = null;
8268 this._destroyOverlay();
8269 this._untrackInstance();
8270
8271 if ( !this.opener.filter( ":focusable" ).focus().length ) {
8272
8273 // support: IE9
8274 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
8275 try {
8276 activeElement = this.document[ 0 ].activeElement;
8277
8278 // Support: IE9, IE10
8279 // If the <body> is blurred, IE will switch windows, see #4520
8280 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
8281
8282 // Hiding a focused element doesn't trigger blur in WebKit
8283 // so in case we have nothing to focus on, explicitly blur the active element
8284 // https://bugs.webkit.org/show_bug.cgi?id=47182
8285 $( activeElement ).blur();
8286 }
8287 } catch ( error ) {}
8288 }
8289
8290 this._hide( this.uiDialog, this.options.hide, function() {
8291 that._trigger( "close", event );
8292 });
8293 },
8294
8295 isOpen: function() {
8296 return this._isOpen;
8297 },
8298
8299 moveToTop: function() {
8300 this._moveToTop();
8301 },
8302
8303 _moveToTop: function( event, silent ) {
8304 var moved = false,
8305 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
8306 return +$( this ).css( "z-index" );
8307 }).get(),
8308 zIndexMax = Math.max.apply( null, zIndices );
8309
8310 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
8311 this.uiDialog.css( "z-index", zIndexMax + 1 );
8312 moved = true;
8313 }
8314
8315 if ( moved && !silent ) {
8316 this._trigger( "focus", event );
8317 }
8318 return moved;
8319 },
8320
8321 open: function() {
8322 var that = this;
8323 if ( this._isOpen ) {
8324 if ( this._moveToTop() ) {
8325 this._focusTabbable();
8326 }
8327 return;
8328 }
8329
8330 this._isOpen = true;
8331 this.opener = $( this.document[ 0 ].activeElement );
8332
8333 this._size();
8334 this._position();
8335 this._createOverlay();
8336 this._moveToTop( null, true );
8337
8338 // Ensure the overlay is moved to the top with the dialog, but only when
8339 // opening. The overlay shouldn't move after the dialog is open so that
8340 // modeless dialogs opened after the modal dialog stack properly.
8341 if ( this.overlay ) {
8342 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
8343 }
8344
8345 this._show( this.uiDialog, this.options.show, function() {
8346 that._focusTabbable();
8347 that._trigger( "focus" );
8348 });
8349
8350 // Track the dialog immediately upon openening in case a focus event
8351 // somehow occurs outside of the dialog before an element inside the
8352 // dialog is focused (#10152)
8353 this._makeFocusTarget();
8354
8355 this._trigger( "open" );
8356 },
8357
8358 _focusTabbable: function() {
8359 // Set focus to the first match:
8360 // 1. An element that was focused previously
8361 // 2. First element inside the dialog matching [autofocus]
8362 // 3. Tabbable element inside the content element
8363 // 4. Tabbable element inside the buttonpane
8364 // 5. The close button
8365 // 6. The dialog itself
8366 var hasFocus = this._focusedElement;
8367 if ( !hasFocus ) {
8368 hasFocus = this.element.find( "[autofocus]" );
8369 }
8370 if ( !hasFocus.length ) {
8371 hasFocus = this.element.find( ":tabbable" );
8372 }
8373 if ( !hasFocus.length ) {
8374 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
8375 }
8376 if ( !hasFocus.length ) {
8377 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
8378 }
8379 if ( !hasFocus.length ) {
8380 hasFocus = this.uiDialog;
8381 }
8382 hasFocus.eq( 0 ).focus();
8383 },
8384
8385 _keepFocus: function( event ) {
8386 function checkFocus() {
8387 var activeElement = this.document[0].activeElement,
8388 isActive = this.uiDialog[0] === activeElement ||
8389 $.contains( this.uiDialog[0], activeElement );
8390 if ( !isActive ) {
8391 this._focusTabbable();
8392 }
8393 }
8394 event.preventDefault();
8395 checkFocus.call( this );
8396 // support: IE
8397 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
8398 // so we check again later
8399 this._delay( checkFocus );
8400 },
8401
8402 _createWrapper: function() {
8403 this.uiDialog = $("<div>")
8404 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
8405 this.options.dialogClass )
8406 .hide()
8407 .attr({
8408 // Setting tabIndex makes the div focusable
8409 tabIndex: -1,
8410 role: "dialog"
8411 })
8412 .appendTo( this._appendTo() );
8413
8414 this._on( this.uiDialog, {
8415 keydown: function( event ) {
8416 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
8417 event.keyCode === $.ui.keyCode.ESCAPE ) {
8418 event.preventDefault();
8419 this.close( event );
8420 return;
8421 }
8422
8423 // prevent tabbing out of dialogs
8424 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
8425 return;
8426 }
8427 var tabbables = this.uiDialog.find( ":tabbable" ),
8428 first = tabbables.filter( ":first" ),
8429 last = tabbables.filter( ":last" );
8430
8431 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
8432 this._delay(function() {
8433 first.focus();
8434 });
8435 event.preventDefault();
8436 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
8437 this._delay(function() {
8438 last.focus();
8439 });
8440 event.preventDefault();
8441 }
8442 },
8443 mousedown: function( event ) {
8444 if ( this._moveToTop( event ) ) {
8445 this._focusTabbable();
8446 }
8447 }
8448 });
8449
8450 // We assume that any existing aria-describedby attribute means
8451 // that the dialog content is marked up properly
8452 // otherwise we brute force the content as the description
8453 if ( !this.element.find( "[aria-describedby]" ).length ) {
8454 this.uiDialog.attr({
8455 "aria-describedby": this.element.uniqueId().attr( "id" )
8456 });
8457 }
8458 },
8459
8460 _createTitlebar: function() {
8461 var uiDialogTitle;
8462
8463 this.uiDialogTitlebar = $( "<div>" )
8464 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
8465 .prependTo( this.uiDialog );
8466 this._on( this.uiDialogTitlebar, {
8467 mousedown: function( event ) {
8468 // Don't prevent click on close button (#8838)
8469 // Focusing a dialog that is partially scrolled out of view
8470 // causes the browser to scroll it into view, preventing the click event
8471 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
8472 // Dialog isn't getting focus when dragging (#8063)
8473 this.uiDialog.focus();
8474 }
8475 }
8476 });
8477
8478 // support: IE
8479 // Use type="button" to prevent enter keypresses in textboxes from closing the
8480 // dialog in IE (#9312)
8481 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
8482 .button({
8483 label: this.options.closeText,
8484 icons: {
8485 primary: "ui-icon-closethick"
8486 },
8487 text: false
8488 })
8489 .addClass( "ui-dialog-titlebar-close" )
8490 .appendTo( this.uiDialogTitlebar );
8491 this._on( this.uiDialogTitlebarClose, {
8492 click: function( event ) {
8493 event.preventDefault();
8494 this.close( event );
8495 }
8496 });
8497
8498 uiDialogTitle = $( "<span>" )
8499 .uniqueId()
8500 .addClass( "ui-dialog-title" )
8501 .prependTo( this.uiDialogTitlebar );
8502 this._title( uiDialogTitle );
8503
8504 this.uiDialog.attr({
8505 "aria-labelledby": uiDialogTitle.attr( "id" )
8506 });
8507 },
8508
8509 _title: function( title ) {
8510 if ( !this.options.title ) {
8511 title.html( "&#160;" );
8512 }
8513 title.text( this.options.title );
8514 },
8515
8516 _createButtonPane: function() {
8517 this.uiDialogButtonPane = $( "<div>" )
8518 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
8519
8520 this.uiButtonSet = $( "<div>" )
8521 .addClass( "ui-dialog-buttonset" )
8522 .appendTo( this.uiDialogButtonPane );
8523
8524 this._createButtons();
8525 },
8526
8527 _createButtons: function() {
8528 var that = this,
8529 buttons = this.options.buttons;
8530
8531 // if we already have a button pane, remove it
8532 this.uiDialogButtonPane.remove();
8533 this.uiButtonSet.empty();
8534
8535 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
8536 this.uiDialog.removeClass( "ui-dialog-buttons" );
8537 return;
8538 }
8539
8540 $.each( buttons, function( name, props ) {
8541 var click, buttonOptions;
8542 props = $.isFunction( props ) ?
8543 { click: props, text: name } :
8544 props;
8545 // Default to a non-submitting button
8546 props = $.extend( { type: "button" }, props );
8547 // Change the context for the click callback to be the main element
8548 click = props.click;
8549 props.click = function() {
8550 click.apply( that.element[ 0 ], arguments );
8551 };
8552 buttonOptions = {
8553 icons: props.icons,
8554 text: props.showText
8555 };
8556 delete props.icons;
8557 delete props.showText;
8558 $( "<button></button>", props )
8559 .button( buttonOptions )
8560 .appendTo( that.uiButtonSet );
8561 });
8562 this.uiDialog.addClass( "ui-dialog-buttons" );
8563 this.uiDialogButtonPane.appendTo( this.uiDialog );
8564 },
8565
8566 _makeDraggable: function() {
8567 var that = this,
8568 options = this.options;
8569
8570 function filteredUi( ui ) {
8571 return {
8572 position: ui.position,
8573 offset: ui.offset
8574 };
8575 }
8576
8577 this.uiDialog.draggable({
8578 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
8579 handle: ".ui-dialog-titlebar",
8580 containment: "document",
8581 start: function( event, ui ) {
8582 $( this ).addClass( "ui-dialog-dragging" );
8583 that._blockFrames();
8584 that._trigger( "dragStart", event, filteredUi( ui ) );
8585 },
8586 drag: function( event, ui ) {
8587 that._trigger( "drag", event, filteredUi( ui ) );
8588 },
8589 stop: function( event, ui ) {
8590 var left = ui.offset.left - that.document.scrollLeft(),
8591 top = ui.offset.top - that.document.scrollTop();
8592
8593 options.position = {
8594 my: "left top",
8595 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8596 "top" + (top >= 0 ? "+" : "") + top,
8597 of: that.window
8598 };
8599 $( this ).removeClass( "ui-dialog-dragging" );
8600 that._unblockFrames();
8601 that._trigger( "dragStop", event, filteredUi( ui ) );
8602 }
8603 });
8604 },
8605
8606 _makeResizable: function() {
8607 var that = this,
8608 options = this.options,
8609 handles = options.resizable,
8610 // .ui-resizable has position: relative defined in the stylesheet
8611 // but dialogs have to use absolute or fixed positioning
8612 position = this.uiDialog.css("position"),
8613 resizeHandles = typeof handles === "string" ?
8614 handles :
8615 "n,e,s,w,se,sw,ne,nw";
8616
8617 function filteredUi( ui ) {
8618 return {
8619 originalPosition: ui.originalPosition,
8620 originalSize: ui.originalSize,
8621 position: ui.position,
8622 size: ui.size
8623 };
8624 }
8625
8626 this.uiDialog.resizable({
8627 cancel: ".ui-dialog-content",
8628 containment: "document",
8629 alsoResize: this.element,
8630 maxWidth: options.maxWidth,
8631 maxHeight: options.maxHeight,
8632 minWidth: options.minWidth,
8633 minHeight: this._minHeight(),
8634 handles: resizeHandles,
8635 start: function( event, ui ) {
8636 $( this ).addClass( "ui-dialog-resizing" );
8637 that._blockFrames();
8638 that._trigger( "resizeStart", event, filteredUi( ui ) );
8639 },
8640 resize: function( event, ui ) {
8641 that._trigger( "resize", event, filteredUi( ui ) );
8642 },
8643 stop: function( event, ui ) {
8644 var offset = that.uiDialog.offset(),
8645 left = offset.left - that.document.scrollLeft(),
8646 top = offset.top - that.document.scrollTop();
8647
8648 options.height = that.uiDialog.height();
8649 options.width = that.uiDialog.width();
8650 options.position = {
8651 my: "left top",
8652 at: "left" + (left >= 0 ? "+" : "") + left + " " +
8653 "top" + (top >= 0 ? "+" : "") + top,
8654 of: that.window
8655 };
8656 $( this ).removeClass( "ui-dialog-resizing" );
8657 that._unblockFrames();
8658 that._trigger( "resizeStop", event, filteredUi( ui ) );
8659 }
8660 })
8661 .css( "position", position );
8662 },
8663
8664 _trackFocus: function() {
8665 this._on( this.widget(), {
8666 focusin: function( event ) {
8667 this._makeFocusTarget();
8668 this._focusedElement = $( event.target );
8669 }
8670 });
8671 },
8672
8673 _makeFocusTarget: function() {
8674 this._untrackInstance();
8675 this._trackingInstances().unshift( this );
8676 },
8677
8678 _untrackInstance: function() {
8679 var instances = this._trackingInstances(),
8680 exists = $.inArray( this, instances );
8681 if ( exists !== -1 ) {
8682 instances.splice( exists, 1 );
8683 }
8684 },
8685
8686 _trackingInstances: function() {
8687 var instances = this.document.data( "ui-dialog-instances" );
8688 if ( !instances ) {
8689 instances = [];
8690 this.document.data( "ui-dialog-instances", instances );
8691 }
8692 return instances;
8693 },
8694
8695 _minHeight: function() {
8696 var options = this.options;
8697
8698 return options.height === "auto" ?
8699 options.minHeight :
8700 Math.min( options.minHeight, options.height );
8701 },
8702
8703 _position: function() {
8704 // Need to show the dialog to get the actual offset in the position plugin
8705 var isVisible = this.uiDialog.is( ":visible" );
8706 if ( !isVisible ) {
8707 this.uiDialog.show();
8708 }
8709 this.uiDialog.position( this.options.position );
8710 if ( !isVisible ) {
8711 this.uiDialog.hide();
8712 }
8713 },
8714
8715 _setOptions: function( options ) {
8716 var that = this,
8717 resize = false,
8718 resizableOptions = {};
8719
8720 $.each( options, function( key, value ) {
8721 that._setOption( key, value );
8722
8723 if ( key in that.sizeRelatedOptions ) {
8724 resize = true;
8725 }
8726 if ( key in that.resizableRelatedOptions ) {
8727 resizableOptions[ key ] = value;
8728 }
8729 });
8730
8731 if ( resize ) {
8732 this._size();
8733 this._position();
8734 }
8735 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8736 this.uiDialog.resizable( "option", resizableOptions );
8737 }
8738 },
8739
8740 _setOption: function( key, value ) {
8741 var isDraggable, isResizable,
8742 uiDialog = this.uiDialog;
8743
8744 if ( key === "dialogClass" ) {
8745 uiDialog
8746 .removeClass( this.options.dialogClass )
8747 .addClass( value );
8748 }
8749
8750 if ( key === "disabled" ) {
8751 return;
8752 }
8753
8754 this._super( key, value );
8755
8756 if ( key === "appendTo" ) {
8757 this.uiDialog.appendTo( this._appendTo() );
8758 }
8759
8760 if ( key === "buttons" ) {
8761 this._createButtons();
8762 }
8763
8764 if ( key === "closeText" ) {
8765 this.uiDialogTitlebarClose.button({
8766 // Ensure that we always pass a string
8767 label: "" + value
8768 });
8769 }
8770
8771 if ( key === "draggable" ) {
8772 isDraggable = uiDialog.is( ":data(ui-draggable)" );
8773 if ( isDraggable && !value ) {
8774 uiDialog.draggable( "destroy" );
8775 }
8776
8777 if ( !isDraggable && value ) {
8778 this._makeDraggable();
8779 }
8780 }
8781
8782 if ( key === "position" ) {
8783 this._position();
8784 }
8785
8786 if ( key === "resizable" ) {
8787 // currently resizable, becoming non-resizable
8788 isResizable = uiDialog.is( ":data(ui-resizable)" );
8789 if ( isResizable && !value ) {
8790 uiDialog.resizable( "destroy" );
8791 }
8792
8793 // currently resizable, changing handles
8794 if ( isResizable && typeof value === "string" ) {
8795 uiDialog.resizable( "option", "handles", value );
8796 }
8797
8798 // currently non-resizable, becoming resizable
8799 if ( !isResizable && value !== false ) {
8800 this._makeResizable();
8801 }
8802 }
8803
8804 if ( key === "title" ) {
8805 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
8806 }
8807 },
8808
8809 _size: function() {
8810 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
8811 // divs will both have width and height set, so we need to reset them
8812 var nonContentHeight, minContentHeight, maxContentHeight,
8813 options = this.options;
8814
8815 // Reset content sizing
8816 this.element.show().css({
8817 width: "auto",
8818 minHeight: 0,
8819 maxHeight: "none",
8820 height: 0
8821 });
8822
8823 if ( options.minWidth > options.width ) {
8824 options.width = options.minWidth;
8825 }
8826
8827 // reset wrapper sizing
8828 // determine the height of all the non-content elements
8829 nonContentHeight = this.uiDialog.css({
8830 height: "auto",
8831 width: options.width
8832 })
8833 .outerHeight();
8834 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
8835 maxContentHeight = typeof options.maxHeight === "number" ?
8836 Math.max( 0, options.maxHeight - nonContentHeight ) :
8837 "none";
8838
8839 if ( options.height === "auto" ) {
8840 this.element.css({
8841 minHeight: minContentHeight,
8842 maxHeight: maxContentHeight,
8843 height: "auto"
8844 });
8845 } else {
8846 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
8847 }
8848
8849 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
8850 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
8851 }
8852 },
8853
8854 _blockFrames: function() {
8855 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
8856 var iframe = $( this );
8857
8858 return $( "<div>" )
8859 .css({
8860 position: "absolute",
8861 width: iframe.outerWidth(),
8862 height: iframe.outerHeight()
8863 })
8864 .appendTo( iframe.parent() )
8865 .offset( iframe.offset() )[0];
8866 });
8867 },
8868
8869 _unblockFrames: function() {
8870 if ( this.iframeBlocks ) {
8871 this.iframeBlocks.remove();
8872 delete this.iframeBlocks;
8873 }
8874 },
8875
8876 _allowInteraction: function( event ) {
8877 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
8878 return true;
8879 }
8880
8881 // TODO: Remove hack when datepicker implements
8882 // the .ui-front logic (#8989)
8883 return !!$( event.target ).closest( ".ui-datepicker" ).length;
8884 },
8885
8886 _createOverlay: function() {
8887 if ( !this.options.modal ) {
8888 return;
8889 }
8890
8891 // We use a delay in case the overlay is created from an
8892 // event that we're going to be cancelling (#2804)
8893 var isOpening = true;
8894 this._delay(function() {
8895 isOpening = false;
8896 });
8897
8898 if ( !this.document.data( "ui-dialog-overlays" ) ) {
8899
8900 // Prevent use of anchors and inputs
8901 // Using _on() for an event handler shared across many instances is
8902 // safe because the dialogs stack and must be closed in reverse order
8903 this._on( this.document, {
8904 focusin: function( event ) {
8905 if ( isOpening ) {
8906 return;
8907 }
8908
8909 if ( !this._allowInteraction( event ) ) {
8910 event.preventDefault();
8911 this._trackingInstances()[ 0 ]._focusTabbable();
8912 }
8913 }
8914 });
8915 }
8916
8917 this.overlay = $( "<div>" )
8918 .addClass( "ui-widget-overlay ui-front" )
8919 .appendTo( this._appendTo() );
8920 this._on( this.overlay, {
8921 mousedown: "_keepFocus"
8922 });
8923 this.document.data( "ui-dialog-overlays",
8924 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
8925 },
8926
8927 _destroyOverlay: function() {
8928 if ( !this.options.modal ) {
8929 return;
8930 }
8931
8932 if ( this.overlay ) {
8933 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
8934
8935 if ( !overlays ) {
8936 this.document
8937 .unbind( "focusin" )
8938 .removeData( "ui-dialog-overlays" );
8939 } else {
8940 this.document.data( "ui-dialog-overlays", overlays );
8941 }
8942
8943 this.overlay.remove();
8944 this.overlay = null;
8945 }
8946 }
8947 });
8948
8949
8950 /*!
8951 * jQuery UI Droppable 1.11.4
8952 * http://jqueryui.com
8953 *
8954 * Copyright jQuery Foundation and other contributors
8955 * Released under the MIT license.
8956 * http://jquery.org/license
8957 *
8958 * http://api.jqueryui.com/droppable/
8959 */
8960
8961
8962 $.widget( "ui.droppable", {
8963 version: "1.11.4",
8964 widgetEventPrefix: "drop",
8965 options: {
8966 accept: "*",
8967 activeClass: false,
8968 addClasses: true,
8969 greedy: false,
8970 hoverClass: false,
8971 scope: "default",
8972 tolerance: "intersect",
8973
8974 // callbacks
8975 activate: null,
8976 deactivate: null,
8977 drop: null,
8978 out: null,
8979 over: null
8980 },
8981 _create: function() {
8982
8983 var proportions,
8984 o = this.options,
8985 accept = o.accept;
8986
8987 this.isover = false;
8988 this.isout = true;
8989
8990 this.accept = $.isFunction( accept ) ? accept : function( d ) {
8991 return d.is( accept );
8992 };
8993
8994 this.proportions = function( /* valueToWrite */ ) {
8995 if ( arguments.length ) {
8996 // Store the droppable's proportions
8997 proportions = arguments[ 0 ];
8998 } else {
8999 // Retrieve or derive the droppable's proportions
9000 return proportions ?
9001 proportions :
9002 proportions = {
9003 width: this.element[ 0 ].offsetWidth,
9004 height: this.element[ 0 ].offsetHeight
9005 };
9006 }
9007 };
9008
9009 this._addToManager( o.scope );
9010
9011 o.addClasses && this.element.addClass( "ui-droppable" );
9012
9013 },
9014
9015 _addToManager: function( scope ) {
9016 // Add the reference and positions to the manager
9017 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
9018 $.ui.ddmanager.droppables[ scope ].push( this );
9019 },
9020
9021 _splice: function( drop ) {
9022 var i = 0;
9023 for ( ; i < drop.length; i++ ) {
9024 if ( drop[ i ] === this ) {
9025 drop.splice( i, 1 );
9026 }
9027 }
9028 },
9029
9030 _destroy: function() {
9031 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9032
9033 this._splice( drop );
9034
9035 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
9036 },
9037
9038 _setOption: function( key, value ) {
9039
9040 if ( key === "accept" ) {
9041 this.accept = $.isFunction( value ) ? value : function( d ) {
9042 return d.is( value );
9043 };
9044 } else if ( key === "scope" ) {
9045 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
9046
9047 this._splice( drop );
9048 this._addToManager( value );
9049 }
9050
9051 this._super( key, value );
9052 },
9053
9054 _activate: function( event ) {
9055 var draggable = $.ui.ddmanager.current;
9056 if ( this.options.activeClass ) {
9057 this.element.addClass( this.options.activeClass );
9058 }
9059 if ( draggable ){
9060 this._trigger( "activate", event, this.ui( draggable ) );
9061 }
9062 },
9063
9064 _deactivate: function( event ) {
9065 var draggable = $.ui.ddmanager.current;
9066 if ( this.options.activeClass ) {
9067 this.element.removeClass( this.options.activeClass );
9068 }
9069 if ( draggable ){
9070 this._trigger( "deactivate", event, this.ui( draggable ) );
9071 }
9072 },
9073
9074 _over: function( event ) {
9075
9076 var draggable = $.ui.ddmanager.current;
9077
9078 // Bail if draggable and droppable are same element
9079 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9080 return;
9081 }
9082
9083 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9084 if ( this.options.hoverClass ) {
9085 this.element.addClass( this.options.hoverClass );
9086 }
9087 this._trigger( "over", event, this.ui( draggable ) );
9088 }
9089
9090 },
9091
9092 _out: function( event ) {
9093
9094 var draggable = $.ui.ddmanager.current;
9095
9096 // Bail if draggable and droppable are same element
9097 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9098 return;
9099 }
9100
9101 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9102 if ( this.options.hoverClass ) {
9103 this.element.removeClass( this.options.hoverClass );
9104 }
9105 this._trigger( "out", event, this.ui( draggable ) );
9106 }
9107
9108 },
9109
9110 _drop: function( event, custom ) {
9111
9112 var draggable = custom || $.ui.ddmanager.current,
9113 childrenIntersection = false;
9114
9115 // Bail if draggable and droppable are same element
9116 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
9117 return false;
9118 }
9119
9120 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
9121 var inst = $( this ).droppable( "instance" );
9122 if (
9123 inst.options.greedy &&
9124 !inst.options.disabled &&
9125 inst.options.scope === draggable.options.scope &&
9126 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
9127 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
9128 ) { childrenIntersection = true; return false; }
9129 });
9130 if ( childrenIntersection ) {
9131 return false;
9132 }
9133
9134 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9135 if ( this.options.activeClass ) {
9136 this.element.removeClass( this.options.activeClass );
9137 }
9138 if ( this.options.hoverClass ) {
9139 this.element.removeClass( this.options.hoverClass );
9140 }
9141 this._trigger( "drop", event, this.ui( draggable ) );
9142 return this.element;
9143 }
9144
9145 return false;
9146
9147 },
9148
9149 ui: function( c ) {
9150 return {
9151 draggable: ( c.currentItem || c.element ),
9152 helper: c.helper,
9153 position: c.position,
9154 offset: c.positionAbs
9155 };
9156 }
9157
9158 });
9159
9160 $.ui.intersect = (function() {
9161 function isOverAxis( x, reference, size ) {
9162 return ( x >= reference ) && ( x < ( reference + size ) );
9163 }
9164
9165 return function( draggable, droppable, toleranceMode, event ) {
9166
9167 if ( !droppable.offset ) {
9168 return false;
9169 }
9170
9171 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
9172 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
9173 x2 = x1 + draggable.helperProportions.width,
9174 y2 = y1 + draggable.helperProportions.height,
9175 l = droppable.offset.left,
9176 t = droppable.offset.top,
9177 r = l + droppable.proportions().width,
9178 b = t + droppable.proportions().height;
9179
9180 switch ( toleranceMode ) {
9181 case "fit":
9182 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
9183 case "intersect":
9184 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
9185 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
9186 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
9187 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
9188 case "pointer":
9189 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
9190 case "touch":
9191 return (
9192 ( y1 >= t && y1 <= b ) || // Top edge touching
9193 ( y2 >= t && y2 <= b ) || // Bottom edge touching
9194 ( y1 < t && y2 > b ) // Surrounded vertically
9195 ) && (
9196 ( x1 >= l && x1 <= r ) || // Left edge touching
9197 ( x2 >= l && x2 <= r ) || // Right edge touching
9198 ( x1 < l && x2 > r ) // Surrounded horizontally
9199 );
9200 default:
9201 return false;
9202 }
9203 };
9204 })();
9205
9206 /*
9207 This manager tracks offsets of draggables and droppables
9208 */
9209 $.ui.ddmanager = {
9210 current: null,
9211 droppables: { "default": [] },
9212 prepareOffsets: function( t, event ) {
9213
9214 var i, j,
9215 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
9216 type = event ? event.type : null, // workaround for #2317
9217 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
9218
9219 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
9220
9221 // No disabled and non-accepted
9222 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
9223 continue;
9224 }
9225
9226 // Filter out elements in the current dragged item
9227 for ( j = 0; j < list.length; j++ ) {
9228 if ( list[ j ] === m[ i ].element[ 0 ] ) {
9229 m[ i ].proportions().height = 0;
9230 continue droppablesLoop;
9231 }
9232 }
9233
9234 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
9235 if ( !m[ i ].visible ) {
9236 continue;
9237 }
9238
9239 // Activate the droppable if used directly from draggables
9240 if ( type === "mousedown" ) {
9241 m[ i ]._activate.call( m[ i ], event );
9242 }
9243
9244 m[ i ].offset = m[ i ].element.offset();
9245 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
9246
9247 }
9248
9249 },
9250 drop: function( draggable, event ) {
9251
9252 var dropped = false;
9253 // Create a copy of the droppables in case the list changes during the drop (#9116)
9254 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
9255
9256 if ( !this.options ) {
9257 return;
9258 }
9259 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
9260 dropped = this._drop.call( this, event ) || dropped;
9261 }
9262
9263 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
9264 this.isout = true;
9265 this.isover = false;
9266 this._deactivate.call( this, event );
9267 }
9268
9269 });
9270 return dropped;
9271
9272 },
9273 dragStart: function( draggable, event ) {
9274 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
9275 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
9276 if ( !draggable.options.refreshPositions ) {
9277 $.ui.ddmanager.prepareOffsets( draggable, event );
9278 }
9279 });
9280 },
9281 drag: function( draggable, event ) {
9282
9283 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
9284 if ( draggable.options.refreshPositions ) {
9285 $.ui.ddmanager.prepareOffsets( draggable, event );
9286 }
9287
9288 // Run through all droppables and check their positions based on specific tolerance options
9289 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
9290
9291 if ( this.options.disabled || this.greedyChild || !this.visible ) {
9292 return;
9293 }
9294
9295 var parentInstance, scope, parent,
9296 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
9297 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
9298 if ( !c ) {
9299 return;
9300 }
9301
9302 if ( this.options.greedy ) {
9303 // find droppable parents with same scope
9304 scope = this.options.scope;
9305 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
9306 return $( this ).droppable( "instance" ).options.scope === scope;
9307 });
9308
9309 if ( parent.length ) {
9310 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
9311 parentInstance.greedyChild = ( c === "isover" );
9312 }
9313 }
9314
9315 // we just moved into a greedy child
9316 if ( parentInstance && c === "isover" ) {
9317 parentInstance.isover = false;
9318 parentInstance.isout = true;
9319 parentInstance._out.call( parentInstance, event );
9320 }
9321
9322 this[ c ] = true;
9323 this[c === "isout" ? "isover" : "isout"] = false;
9324 this[c === "isover" ? "_over" : "_out"].call( this, event );
9325
9326 // we just moved out of a greedy child
9327 if ( parentInstance && c === "isout" ) {
9328 parentInstance.isout = false;
9329 parentInstance.isover = true;
9330 parentInstance._over.call( parentInstance, event );
9331 }
9332 });
9333
9334 },
9335 dragStop: function( draggable, event ) {
9336 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
9337 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
9338 if ( !draggable.options.refreshPositions ) {
9339 $.ui.ddmanager.prepareOffsets( draggable, event );
9340 }
9341 }
9342 };
9343
9344 var droppable = $.ui.droppable;
9345
9346
9347 /*!
9348 * jQuery UI Effects 1.11.4
9349 * http://jqueryui.com
9350 *
9351 * Copyright jQuery Foundation and other contributors
9352 * Released under the MIT license.
9353 * http://jquery.org/license
9354 *
9355 * http://api.jqueryui.com/category/effects-core/
9356 */
9357
9358
9359 var dataSpace = "ui-effects-",
9360
9361 // Create a local jQuery because jQuery Color relies on it and the
9362 // global may not exist with AMD and a custom build (#10199)
9363 jQuery = $;
9364
9365 $.effects = {
9366 effect: {}
9367 };
9368
9369 /*!
9370 * jQuery Color Animations v2.1.2
9371 * https://github.com/jquery/jquery-color
9372 *
9373 * Copyright 2014 jQuery Foundation and other contributors
9374 * Released under the MIT license.
9375 * http://jquery.org/license
9376 *
9377 * Date: Wed Jan 16 08:47:09 2013 -0600
9378 */
9379 (function( jQuery, undefined ) {
9380
9381 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
9382
9383 // plusequals test for += 100 -= 100
9384 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
9385 // a set of RE's that can match strings and generate color tuples.
9386 stringParsers = [ {
9387 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9388 parse: function( execResult ) {
9389 return [
9390 execResult[ 1 ],
9391 execResult[ 2 ],
9392 execResult[ 3 ],
9393 execResult[ 4 ]
9394 ];
9395 }
9396 }, {
9397 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9398 parse: function( execResult ) {
9399 return [
9400 execResult[ 1 ] * 2.55,
9401 execResult[ 2 ] * 2.55,
9402 execResult[ 3 ] * 2.55,
9403 execResult[ 4 ]
9404 ];
9405 }
9406 }, {
9407 // this regex ignores A-F because it's compared against an already lowercased string
9408 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
9409 parse: function( execResult ) {
9410 return [
9411 parseInt( execResult[ 1 ], 16 ),
9412 parseInt( execResult[ 2 ], 16 ),
9413 parseInt( execResult[ 3 ], 16 )
9414 ];
9415 }
9416 }, {
9417 // this regex ignores A-F because it's compared against an already lowercased string
9418 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
9419 parse: function( execResult ) {
9420 return [
9421 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
9422 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
9423 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
9424 ];
9425 }
9426 }, {
9427 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
9428 space: "hsla",
9429 parse: function( execResult ) {
9430 return [
9431 execResult[ 1 ],
9432 execResult[ 2 ] / 100,
9433 execResult[ 3 ] / 100,
9434 execResult[ 4 ]
9435 ];
9436 }
9437 } ],
9438
9439 // jQuery.Color( )
9440 color = jQuery.Color = function( color, green, blue, alpha ) {
9441 return new jQuery.Color.fn.parse( color, green, blue, alpha );
9442 },
9443 spaces = {
9444 rgba: {
9445 props: {
9446 red: {
9447 idx: 0,
9448 type: "byte"
9449 },
9450 green: {
9451 idx: 1,
9452 type: "byte"
9453 },
9454 blue: {
9455 idx: 2,
9456 type: "byte"
9457 }
9458 }
9459 },
9460
9461 hsla: {
9462 props: {
9463 hue: {
9464 idx: 0,
9465 type: "degrees"
9466 },
9467 saturation: {
9468 idx: 1,
9469 type: "percent"
9470 },
9471 lightness: {
9472 idx: 2,
9473 type: "percent"
9474 }
9475 }
9476 }
9477 },
9478 propTypes = {
9479 "byte": {
9480 floor: true,
9481 max: 255
9482 },
9483 "percent": {
9484 max: 1
9485 },
9486 "degrees": {
9487 mod: 360,
9488 floor: true
9489 }
9490 },
9491 support = color.support = {},
9492
9493 // element for support tests
9494 supportElem = jQuery( "<p>" )[ 0 ],
9495
9496 // colors = jQuery.Color.names
9497 colors,
9498
9499 // local aliases of functions called often
9500 each = jQuery.each;
9501
9502 // determine rgba support immediately
9503 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
9504 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
9505
9506 // define cache name and alpha properties
9507 // for rgba and hsla spaces
9508 each( spaces, function( spaceName, space ) {
9509 space.cache = "_" + spaceName;
9510 space.props.alpha = {
9511 idx: 3,
9512 type: "percent",
9513 def: 1
9514 };
9515 });
9516
9517 function clamp( value, prop, allowEmpty ) {
9518 var type = propTypes[ prop.type ] || {};
9519
9520 if ( value == null ) {
9521 return (allowEmpty || !prop.def) ? null : prop.def;
9522 }
9523
9524 // ~~ is an short way of doing floor for positive numbers
9525 value = type.floor ? ~~value : parseFloat( value );
9526
9527 // IE will pass in empty strings as value for alpha,
9528 // which will hit this case
9529 if ( isNaN( value ) ) {
9530 return prop.def;
9531 }
9532
9533 if ( type.mod ) {
9534 // we add mod before modding to make sure that negatives values
9535 // get converted properly: -10 -> 350
9536 return (value + type.mod) % type.mod;
9537 }
9538
9539 // for now all property types without mod have min and max
9540 return 0 > value ? 0 : type.max < value ? type.max : value;
9541 }
9542
9543 function stringParse( string ) {
9544 var inst = color(),
9545 rgba = inst._rgba = [];
9546
9547 string = string.toLowerCase();
9548
9549 each( stringParsers, function( i, parser ) {
9550 var parsed,
9551 match = parser.re.exec( string ),
9552 values = match && parser.parse( match ),
9553 spaceName = parser.space || "rgba";
9554
9555 if ( values ) {
9556 parsed = inst[ spaceName ]( values );
9557
9558 // if this was an rgba parse the assignment might happen twice
9559 // oh well....
9560 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
9561 rgba = inst._rgba = parsed._rgba;
9562
9563 // exit each( stringParsers ) here because we matched
9564 return false;
9565 }
9566 });
9567
9568 // Found a stringParser that handled it
9569 if ( rgba.length ) {
9570
9571 // if this came from a parsed string, force "transparent" when alpha is 0
9572 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
9573 if ( rgba.join() === "0,0,0,0" ) {
9574 jQuery.extend( rgba, colors.transparent );
9575 }
9576 return inst;
9577 }
9578
9579 // named colors
9580 return colors[ string ];
9581 }
9582
9583 color.fn = jQuery.extend( color.prototype, {
9584 parse: function( red, green, blue, alpha ) {
9585 if ( red === undefined ) {
9586 this._rgba = [ null, null, null, null ];
9587 return this;
9588 }
9589 if ( red.jquery || red.nodeType ) {
9590 red = jQuery( red ).css( green );
9591 green = undefined;
9592 }
9593
9594 var inst = this,
9595 type = jQuery.type( red ),
9596 rgba = this._rgba = [];
9597
9598 // more than 1 argument specified - assume ( red, green, blue, alpha )
9599 if ( green !== undefined ) {
9600 red = [ red, green, blue, alpha ];
9601 type = "array";
9602 }
9603
9604 if ( type === "string" ) {
9605 return this.parse( stringParse( red ) || colors._default );
9606 }
9607
9608 if ( type === "array" ) {
9609 each( spaces.rgba.props, function( key, prop ) {
9610 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
9611 });
9612 return this;
9613 }
9614
9615 if ( type === "object" ) {
9616 if ( red instanceof color ) {
9617 each( spaces, function( spaceName, space ) {
9618 if ( red[ space.cache ] ) {
9619 inst[ space.cache ] = red[ space.cache ].slice();
9620 }
9621 });
9622 } else {
9623 each( spaces, function( spaceName, space ) {
9624 var cache = space.cache;
9625 each( space.props, function( key, prop ) {
9626
9627 // if the cache doesn't exist, and we know how to convert
9628 if ( !inst[ cache ] && space.to ) {
9629
9630 // if the value was null, we don't need to copy it
9631 // if the key was alpha, we don't need to copy it either
9632 if ( key === "alpha" || red[ key ] == null ) {
9633 return;
9634 }
9635 inst[ cache ] = space.to( inst._rgba );
9636 }
9637
9638 // this is the only case where we allow nulls for ALL properties.
9639 // call clamp with alwaysAllowEmpty
9640 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
9641 });
9642
9643 // everything defined but alpha?
9644 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
9645 // use the default of 1
9646 inst[ cache ][ 3 ] = 1;
9647 if ( space.from ) {
9648 inst._rgba = space.from( inst[ cache ] );
9649 }
9650 }
9651 });
9652 }
9653 return this;
9654 }
9655 },
9656 is: function( compare ) {
9657 var is = color( compare ),
9658 same = true,
9659 inst = this;
9660
9661 each( spaces, function( _, space ) {
9662 var localCache,
9663 isCache = is[ space.cache ];
9664 if (isCache) {
9665 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
9666 each( space.props, function( _, prop ) {
9667 if ( isCache[ prop.idx ] != null ) {
9668 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
9669 return same;
9670 }
9671 });
9672 }
9673 return same;
9674 });
9675 return same;
9676 },
9677 _space: function() {
9678 var used = [],
9679 inst = this;
9680 each( spaces, function( spaceName, space ) {
9681 if ( inst[ space.cache ] ) {
9682 used.push( spaceName );
9683 }
9684 });
9685 return used.pop();
9686 },
9687 transition: function( other, distance ) {
9688 var end = color( other ),
9689 spaceName = end._space(),
9690 space = spaces[ spaceName ],
9691 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
9692 start = startColor[ space.cache ] || space.to( startColor._rgba ),
9693 result = start.slice();
9694
9695 end = end[ space.cache ];
9696 each( space.props, function( key, prop ) {
9697 var index = prop.idx,
9698 startValue = start[ index ],
9699 endValue = end[ index ],
9700 type = propTypes[ prop.type ] || {};
9701
9702 // if null, don't override start value
9703 if ( endValue === null ) {
9704 return;
9705 }
9706 // if null - use end
9707 if ( startValue === null ) {
9708 result[ index ] = endValue;
9709 } else {
9710 if ( type.mod ) {
9711 if ( endValue - startValue > type.mod / 2 ) {
9712 startValue += type.mod;
9713 } else if ( startValue - endValue > type.mod / 2 ) {
9714 startValue -= type.mod;
9715 }
9716 }
9717 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
9718 }
9719 });
9720 return this[ spaceName ]( result );
9721 },
9722 blend: function( opaque ) {
9723 // if we are already opaque - return ourself
9724 if ( this._rgba[ 3 ] === 1 ) {
9725 return this;
9726 }
9727
9728 var rgb = this._rgba.slice(),
9729 a = rgb.pop(),
9730 blend = color( opaque )._rgba;
9731
9732 return color( jQuery.map( rgb, function( v, i ) {
9733 return ( 1 - a ) * blend[ i ] + a * v;
9734 }));
9735 },
9736 toRgbaString: function() {
9737 var prefix = "rgba(",
9738 rgba = jQuery.map( this._rgba, function( v, i ) {
9739 return v == null ? ( i > 2 ? 1 : 0 ) : v;
9740 });
9741
9742 if ( rgba[ 3 ] === 1 ) {
9743 rgba.pop();
9744 prefix = "rgb(";
9745 }
9746
9747 return prefix + rgba.join() + ")";
9748 },
9749 toHslaString: function() {
9750 var prefix = "hsla(",
9751 hsla = jQuery.map( this.hsla(), function( v, i ) {
9752 if ( v == null ) {
9753 v = i > 2 ? 1 : 0;
9754 }
9755
9756 // catch 1 and 2
9757 if ( i && i < 3 ) {
9758 v = Math.round( v * 100 ) + "%";
9759 }
9760 return v;
9761 });
9762
9763 if ( hsla[ 3 ] === 1 ) {
9764 hsla.pop();
9765 prefix = "hsl(";
9766 }
9767 return prefix + hsla.join() + ")";
9768 },
9769 toHexString: function( includeAlpha ) {
9770 var rgba = this._rgba.slice(),
9771 alpha = rgba.pop();
9772
9773 if ( includeAlpha ) {
9774 rgba.push( ~~( alpha * 255 ) );
9775 }
9776
9777 return "#" + jQuery.map( rgba, function( v ) {
9778
9779 // default to 0 when nulls exist
9780 v = ( v || 0 ).toString( 16 );
9781 return v.length === 1 ? "0" + v : v;
9782 }).join("");
9783 },
9784 toString: function() {
9785 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
9786 }
9787 });
9788 color.fn.parse.prototype = color.fn;
9789
9790 // hsla conversions adapted from:
9791 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
9792
9793 function hue2rgb( p, q, h ) {
9794 h = ( h + 1 ) % 1;
9795 if ( h * 6 < 1 ) {
9796 return p + ( q - p ) * h * 6;
9797 }
9798 if ( h * 2 < 1) {
9799 return q;
9800 }
9801 if ( h * 3 < 2 ) {
9802 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
9803 }
9804 return p;
9805 }
9806
9807 spaces.hsla.to = function( rgba ) {
9808 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
9809 return [ null, null, null, rgba[ 3 ] ];
9810 }
9811 var r = rgba[ 0 ] / 255,
9812 g = rgba[ 1 ] / 255,
9813 b = rgba[ 2 ] / 255,
9814 a = rgba[ 3 ],
9815 max = Math.max( r, g, b ),
9816 min = Math.min( r, g, b ),
9817 diff = max - min,
9818 add = max + min,
9819 l = add * 0.5,
9820 h, s;
9821
9822 if ( min === max ) {
9823 h = 0;
9824 } else if ( r === max ) {
9825 h = ( 60 * ( g - b ) / diff ) + 360;
9826 } else if ( g === max ) {
9827 h = ( 60 * ( b - r ) / diff ) + 120;
9828 } else {
9829 h = ( 60 * ( r - g ) / diff ) + 240;
9830 }
9831
9832 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
9833 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
9834 if ( diff === 0 ) {
9835 s = 0;
9836 } else if ( l <= 0.5 ) {
9837 s = diff / add;
9838 } else {
9839 s = diff / ( 2 - add );
9840 }
9841 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
9842 };
9843
9844 spaces.hsla.from = function( hsla ) {
9845 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
9846 return [ null, null, null, hsla[ 3 ] ];
9847 }
9848 var h = hsla[ 0 ] / 360,
9849 s = hsla[ 1 ],
9850 l = hsla[ 2 ],
9851 a = hsla[ 3 ],
9852 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
9853 p = 2 * l - q;
9854
9855 return [
9856 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
9857 Math.round( hue2rgb( p, q, h ) * 255 ),
9858 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
9859 a
9860 ];
9861 };
9862
9863 each( spaces, function( spaceName, space ) {
9864 var props = space.props,
9865 cache = space.cache,
9866 to = space.to,
9867 from = space.from;
9868
9869 // makes rgba() and hsla()
9870 color.fn[ spaceName ] = function( value ) {
9871
9872 // generate a cache for this space if it doesn't exist
9873 if ( to && !this[ cache ] ) {
9874 this[ cache ] = to( this._rgba );
9875 }
9876 if ( value === undefined ) {
9877 return this[ cache ].slice();
9878 }
9879
9880 var ret,
9881 type = jQuery.type( value ),
9882 arr = ( type === "array" || type === "object" ) ? value : arguments,
9883 local = this[ cache ].slice();
9884
9885 each( props, function( key, prop ) {
9886 var val = arr[ type === "object" ? key : prop.idx ];
9887 if ( val == null ) {
9888 val = local[ prop.idx ];
9889 }
9890 local[ prop.idx ] = clamp( val, prop );
9891 });
9892
9893 if ( from ) {
9894 ret = color( from( local ) );
9895 ret[ cache ] = local;
9896 return ret;
9897 } else {
9898 return color( local );
9899 }
9900 };
9901
9902 // makes red() green() blue() alpha() hue() saturation() lightness()
9903 each( props, function( key, prop ) {
9904 // alpha is included in more than one space
9905 if ( color.fn[ key ] ) {
9906 return;
9907 }
9908 color.fn[ key ] = function( value ) {
9909 var vtype = jQuery.type( value ),
9910 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
9911 local = this[ fn ](),
9912 cur = local[ prop.idx ],
9913 match;
9914
9915 if ( vtype === "undefined" ) {
9916 return cur;
9917 }
9918
9919 if ( vtype === "function" ) {
9920 value = value.call( this, cur );
9921 vtype = jQuery.type( value );
9922 }
9923 if ( value == null && prop.empty ) {
9924 return this;
9925 }
9926 if ( vtype === "string" ) {
9927 match = rplusequals.exec( value );
9928 if ( match ) {
9929 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
9930 }
9931 }
9932 local[ prop.idx ] = value;
9933 return this[ fn ]( local );
9934 };
9935 });
9936 });
9937
9938 // add cssHook and .fx.step function for each named hook.
9939 // accept a space separated string of properties
9940 color.hook = function( hook ) {
9941 var hooks = hook.split( " " );
9942 each( hooks, function( i, hook ) {
9943 jQuery.cssHooks[ hook ] = {
9944 set: function( elem, value ) {
9945 var parsed, curElem,
9946 backgroundColor = "";
9947
9948 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
9949 value = color( parsed || value );
9950 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
9951 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
9952 while (
9953 (backgroundColor === "" || backgroundColor === "transparent") &&
9954 curElem && curElem.style
9955 ) {
9956 try {
9957 backgroundColor = jQuery.css( curElem, "backgroundColor" );
9958 curElem = curElem.parentNode;
9959 } catch ( e ) {
9960 }
9961 }
9962
9963 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
9964 backgroundColor :
9965 "_default" );
9966 }
9967
9968 value = value.toRgbaString();
9969 }
9970 try {
9971 elem.style[ hook ] = value;
9972 } catch ( e ) {
9973 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
9974 }
9975 }
9976 };
9977 jQuery.fx.step[ hook ] = function( fx ) {
9978 if ( !fx.colorInit ) {
9979 fx.start = color( fx.elem, hook );
9980 fx.end = color( fx.end );
9981 fx.colorInit = true;
9982 }
9983 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
9984 };
9985 });
9986
9987 };
9988
9989 color.hook( stepHooks );
9990
9991 jQuery.cssHooks.borderColor = {
9992 expand: function( value ) {
9993 var expanded = {};
9994
9995 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
9996 expanded[ "border" + part + "Color" ] = value;
9997 });
9998 return expanded;
9999 }
10000 };
10001
10002 // Basic color names only.
10003 // Usage of any of the other color names requires adding yourself or including
10004 // jquery.color.svg-names.js.
10005 colors = jQuery.Color.names = {
10006 // 4.1. Basic color keywords
10007 aqua: "#00ffff",
10008 black: "#000000",
10009 blue: "#0000ff",
10010 fuchsia: "#ff00ff",
10011 gray: "#808080",
10012 green: "#008000",
10013 lime: "#00ff00",
10014 maroon: "#800000",
10015 navy: "#000080",
10016 olive: "#808000",
10017 purple: "#800080",
10018 red: "#ff0000",
10019 silver: "#c0c0c0",
10020 teal: "#008080",
10021 white: "#ffffff",
10022 yellow: "#ffff00",
10023
10024 // 4.2.3. "transparent" color keyword
10025 transparent: [ null, null, null, 0 ],
10026
10027 _default: "#ffffff"
10028 };
10029
10030 })( jQuery );
10031
10032 /******************************************************************************/
10033 /****************************** CLASS ANIMATIONS ******************************/
10034 /******************************************************************************/
10035 (function() {
10036
10037 var classAnimationActions = [ "add", "remove", "toggle" ],
10038 shorthandStyles = {
10039 border: 1,
10040 borderBottom: 1,
10041 borderColor: 1,
10042 borderLeft: 1,
10043 borderRight: 1,
10044 borderTop: 1,
10045 borderWidth: 1,
10046 margin: 1,
10047 padding: 1
10048 };
10049
10050 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
10051 $.fx.step[ prop ] = function( fx ) {
10052 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
10053 jQuery.style( fx.elem, prop, fx.end );
10054 fx.setAttr = true;
10055 }
10056 };
10057 });
10058
10059 function getElementStyles( elem ) {
10060 var key, len,
10061 style = elem.ownerDocument.defaultView ?
10062 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
10063 elem.currentStyle,
10064 styles = {};
10065
10066 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
10067 len = style.length;
10068 while ( len-- ) {
10069 key = style[ len ];
10070 if ( typeof style[ key ] === "string" ) {
10071 styles[ $.camelCase( key ) ] = style[ key ];
10072 }
10073 }
10074 // support: Opera, IE <9
10075 } else {
10076 for ( key in style ) {
10077 if ( typeof style[ key ] === "string" ) {
10078 styles[ key ] = style[ key ];
10079 }
10080 }
10081 }
10082
10083 return styles;
10084 }
10085
10086 function styleDifference( oldStyle, newStyle ) {
10087 var diff = {},
10088 name, value;
10089
10090 for ( name in newStyle ) {
10091 value = newStyle[ name ];
10092 if ( oldStyle[ name ] !== value ) {
10093 if ( !shorthandStyles[ name ] ) {
10094 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
10095 diff[ name ] = value;
10096 }
10097 }
10098 }
10099 }
10100
10101 return diff;
10102 }
10103
10104 // support: jQuery <1.8
10105 if ( !$.fn.addBack ) {
10106 $.fn.addBack = function( selector ) {
10107 return this.add( selector == null ?
10108 this.prevObject : this.prevObject.filter( selector )
10109 );
10110 };
10111 }
10112
10113 $.effects.animateClass = function( value, duration, easing, callback ) {
10114 var o = $.speed( duration, easing, callback );
10115
10116 return this.queue( function() {
10117 var animated = $( this ),
10118 baseClass = animated.attr( "class" ) || "",
10119 applyClassChange,
10120 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
10121
10122 // map the animated objects to store the original styles.
10123 allAnimations = allAnimations.map(function() {
10124 var el = $( this );
10125 return {
10126 el: el,
10127 start: getElementStyles( this )
10128 };
10129 });
10130
10131 // apply class change
10132 applyClassChange = function() {
10133 $.each( classAnimationActions, function(i, action) {
10134 if ( value[ action ] ) {
10135 animated[ action + "Class" ]( value[ action ] );
10136 }
10137 });
10138 };
10139 applyClassChange();
10140
10141 // map all animated objects again - calculate new styles and diff
10142 allAnimations = allAnimations.map(function() {
10143 this.end = getElementStyles( this.el[ 0 ] );
10144 this.diff = styleDifference( this.start, this.end );
10145 return this;
10146 });
10147
10148 // apply original class
10149 animated.attr( "class", baseClass );
10150
10151 // map all animated objects again - this time collecting a promise
10152 allAnimations = allAnimations.map(function() {
10153 var styleInfo = this,
10154 dfd = $.Deferred(),
10155 opts = $.extend({}, o, {
10156 queue: false,
10157 complete: function() {
10158 dfd.resolve( styleInfo );
10159 }
10160 });
10161
10162 this.el.animate( this.diff, opts );
10163 return dfd.promise();
10164 });
10165
10166 // once all animations have completed:
10167 $.when.apply( $, allAnimations.get() ).done(function() {
10168
10169 // set the final class
10170 applyClassChange();
10171
10172 // for each animated element,
10173 // clear all css properties that were animated
10174 $.each( arguments, function() {
10175 var el = this.el;
10176 $.each( this.diff, function(key) {
10177 el.css( key, "" );
10178 });
10179 });
10180
10181 // this is guarnteed to be there if you use jQuery.speed()
10182 // it also handles dequeuing the next anim...
10183 o.complete.call( animated[ 0 ] );
10184 });
10185 });
10186 };
10187
10188 $.fn.extend({
10189 addClass: (function( orig ) {
10190 return function( classNames, speed, easing, callback ) {
10191 return speed ?
10192 $.effects.animateClass.call( this,
10193 { add: classNames }, speed, easing, callback ) :
10194 orig.apply( this, arguments );
10195 };
10196 })( $.fn.addClass ),
10197
10198 removeClass: (function( orig ) {
10199 return function( classNames, speed, easing, callback ) {
10200 return arguments.length > 1 ?
10201 $.effects.animateClass.call( this,
10202 { remove: classNames }, speed, easing, callback ) :
10203 orig.apply( this, arguments );
10204 };
10205 })( $.fn.removeClass ),
10206
10207 toggleClass: (function( orig ) {
10208 return function( classNames, force, speed, easing, callback ) {
10209 if ( typeof force === "boolean" || force === undefined ) {
10210 if ( !speed ) {
10211 // without speed parameter
10212 return orig.apply( this, arguments );
10213 } else {
10214 return $.effects.animateClass.call( this,
10215 (force ? { add: classNames } : { remove: classNames }),
10216 speed, easing, callback );
10217 }
10218 } else {
10219 // without force parameter
10220 return $.effects.animateClass.call( this,
10221 { toggle: classNames }, force, speed, easing );
10222 }
10223 };
10224 })( $.fn.toggleClass ),
10225
10226 switchClass: function( remove, add, speed, easing, callback) {
10227 return $.effects.animateClass.call( this, {
10228 add: add,
10229 remove: remove
10230 }, speed, easing, callback );
10231 }
10232 });
10233
10234 })();
10235
10236 /******************************************************************************/
10237 /*********************************** EFFECTS **********************************/
10238 /******************************************************************************/
10239
10240 (function() {
10241
10242 $.extend( $.effects, {
10243 version: "1.11.4",
10244
10245 // Saves a set of properties in a data storage
10246 save: function( element, set ) {
10247 for ( var i = 0; i < set.length; i++ ) {
10248 if ( set[ i ] !== null ) {
10249 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
10250 }
10251 }
10252 },
10253
10254 // Restores a set of previously saved properties from a data storage
10255 restore: function( element, set ) {
10256 var val, i;
10257 for ( i = 0; i < set.length; i++ ) {
10258 if ( set[ i ] !== null ) {
10259 val = element.data( dataSpace + set[ i ] );
10260 // support: jQuery 1.6.2
10261 // http://bugs.jquery.com/ticket/9917
10262 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
10263 // We can't differentiate between "" and 0 here, so we just assume
10264 // empty string since it's likely to be a more common value...
10265 if ( val === undefined ) {
10266 val = "";
10267 }
10268 element.css( set[ i ], val );
10269 }
10270 }
10271 },
10272
10273 setMode: function( el, mode ) {
10274 if (mode === "toggle") {
10275 mode = el.is( ":hidden" ) ? "show" : "hide";
10276 }
10277 return mode;
10278 },
10279
10280 // Translates a [top,left] array into a baseline value
10281 // this should be a little more flexible in the future to handle a string & hash
10282 getBaseline: function( origin, original ) {
10283 var y, x;
10284 switch ( origin[ 0 ] ) {
10285 case "top": y = 0; break;
10286 case "middle": y = 0.5; break;
10287 case "bottom": y = 1; break;
10288 default: y = origin[ 0 ] / original.height;
10289 }
10290 switch ( origin[ 1 ] ) {
10291 case "left": x = 0; break;
10292 case "center": x = 0.5; break;
10293 case "right": x = 1; break;
10294 default: x = origin[ 1 ] / original.width;
10295 }
10296 return {
10297 x: x,
10298 y: y
10299 };
10300 },
10301
10302 // Wraps the element around a wrapper that copies position properties
10303 createWrapper: function( element ) {
10304
10305 // if the element is already wrapped, return it
10306 if ( element.parent().is( ".ui-effects-wrapper" )) {
10307 return element.parent();
10308 }
10309
10310 // wrap the element
10311 var props = {
10312 width: element.outerWidth(true),
10313 height: element.outerHeight(true),
10314 "float": element.css( "float" )
10315 },
10316 wrapper = $( "<div></div>" )
10317 .addClass( "ui-effects-wrapper" )
10318 .css({
10319 fontSize: "100%",
10320 background: "transparent",
10321 border: "none",
10322 margin: 0,
10323 padding: 0
10324 }),
10325 // Store the size in case width/height are defined in % - Fixes #5245
10326 size = {
10327 width: element.width(),
10328 height: element.height()
10329 },
10330 active = document.activeElement;
10331
10332 // support: Firefox
10333 // Firefox incorrectly exposes anonymous content
10334 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
10335 try {
10336 active.id;
10337 } catch ( e ) {
10338 active = document.body;
10339 }
10340
10341 element.wrap( wrapper );
10342
10343 // Fixes #7595 - Elements lose focus when wrapped.
10344 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10345 $( active ).focus();
10346 }
10347
10348 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
10349
10350 // transfer positioning properties to the wrapper
10351 if ( element.css( "position" ) === "static" ) {
10352 wrapper.css({ position: "relative" });
10353 element.css({ position: "relative" });
10354 } else {
10355 $.extend( props, {
10356 position: element.css( "position" ),
10357 zIndex: element.css( "z-index" )
10358 });
10359 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
10360 props[ pos ] = element.css( pos );
10361 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
10362 props[ pos ] = "auto";
10363 }
10364 });
10365 element.css({
10366 position: "relative",
10367 top: 0,
10368 left: 0,
10369 right: "auto",
10370 bottom: "auto"
10371 });
10372 }
10373 element.css(size);
10374
10375 return wrapper.css( props ).show();
10376 },
10377
10378 removeWrapper: function( element ) {
10379 var active = document.activeElement;
10380
10381 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
10382 element.parent().replaceWith( element );
10383
10384 // Fixes #7595 - Elements lose focus when wrapped.
10385 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
10386 $( active ).focus();
10387 }
10388 }
10389
10390 return element;
10391 },
10392
10393 setTransition: function( element, list, factor, value ) {
10394 value = value || {};
10395 $.each( list, function( i, x ) {
10396 var unit = element.cssUnit( x );
10397 if ( unit[ 0 ] > 0 ) {
10398 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
10399 }
10400 });
10401 return value;
10402 }
10403 });
10404
10405 // return an effect options object for the given parameters:
10406 function _normalizeArguments( effect, options, speed, callback ) {
10407
10408 // allow passing all options as the first parameter
10409 if ( $.isPlainObject( effect ) ) {
10410 options = effect;
10411 effect = effect.effect;
10412 }
10413
10414 // convert to an object
10415 effect = { effect: effect };
10416
10417 // catch (effect, null, ...)
10418 if ( options == null ) {
10419 options = {};
10420 }
10421
10422 // catch (effect, callback)
10423 if ( $.isFunction( options ) ) {
10424 callback = options;
10425 speed = null;
10426 options = {};
10427 }
10428
10429 // catch (effect, speed, ?)
10430 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
10431 callback = speed;
10432 speed = options;
10433 options = {};
10434 }
10435
10436 // catch (effect, options, callback)
10437 if ( $.isFunction( speed ) ) {
10438 callback = speed;
10439 speed = null;
10440 }
10441
10442 // add options to effect
10443 if ( options ) {
10444 $.extend( effect, options );
10445 }
10446
10447 speed = speed || options.duration;
10448 effect.duration = $.fx.off ? 0 :
10449 typeof speed === "number" ? speed :
10450 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
10451 $.fx.speeds._default;
10452
10453 effect.complete = callback || options.complete;
10454
10455 return effect;
10456 }
10457
10458 function standardAnimationOption( option ) {
10459 // Valid standard speeds (nothing, number, named speed)
10460 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
10461 return true;
10462 }
10463
10464 // Invalid strings - treat as "normal" speed
10465 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
10466 return true;
10467 }
10468
10469 // Complete callback
10470 if ( $.isFunction( option ) ) {
10471 return true;
10472 }
10473
10474 // Options hash (but not naming an effect)
10475 if ( typeof option === "object" && !option.effect ) {
10476 return true;
10477 }
10478
10479 // Didn't match any standard API
10480 return false;
10481 }
10482
10483 $.fn.extend({
10484 effect: function( /* effect, options, speed, callback */ ) {
10485 var args = _normalizeArguments.apply( this, arguments ),
10486 mode = args.mode,
10487 queue = args.queue,
10488 effectMethod = $.effects.effect[ args.effect ];
10489
10490 if ( $.fx.off || !effectMethod ) {
10491 // delegate to the original method (e.g., .show()) if possible
10492 if ( mode ) {
10493 return this[ mode ]( args.duration, args.complete );
10494 } else {
10495 return this.each( function() {
10496 if ( args.complete ) {
10497 args.complete.call( this );
10498 }
10499 });
10500 }
10501 }
10502
10503 function run( next ) {
10504 var elem = $( this ),
10505 complete = args.complete,
10506 mode = args.mode;
10507
10508 function done() {
10509 if ( $.isFunction( complete ) ) {
10510 complete.call( elem[0] );
10511 }
10512 if ( $.isFunction( next ) ) {
10513 next();
10514 }
10515 }
10516
10517 // If the element already has the correct final state, delegate to
10518 // the core methods so the internal tracking of "olddisplay" works.
10519 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
10520 elem[ mode ]();
10521 done();
10522 } else {
10523 effectMethod.call( elem[0], args, done );
10524 }
10525 }
10526
10527 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
10528 },
10529
10530 show: (function( orig ) {
10531 return function( option ) {
10532 if ( standardAnimationOption( option ) ) {
10533 return orig.apply( this, arguments );
10534 } else {
10535 var args = _normalizeArguments.apply( this, arguments );
10536 args.mode = "show";
10537 return this.effect.call( this, args );
10538 }
10539 };
10540 })( $.fn.show ),
10541
10542 hide: (function( orig ) {
10543 return function( option ) {
10544 if ( standardAnimationOption( option ) ) {
10545 return orig.apply( this, arguments );
10546 } else {
10547 var args = _normalizeArguments.apply( this, arguments );
10548 args.mode = "hide";
10549 return this.effect.call( this, args );
10550 }
10551 };
10552 })( $.fn.hide ),
10553
10554 toggle: (function( orig ) {
10555 return function( option ) {
10556 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
10557 return orig.apply( this, arguments );
10558 } else {
10559 var args = _normalizeArguments.apply( this, arguments );
10560 args.mode = "toggle";
10561 return this.effect.call( this, args );
10562 }
10563 };
10564 })( $.fn.toggle ),
10565
10566 // helper functions
10567 cssUnit: function(key) {
10568 var style = this.css( key ),
10569 val = [];
10570
10571 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
10572 if ( style.indexOf( unit ) > 0 ) {
10573 val = [ parseFloat( style ), unit ];
10574 }
10575 });
10576 return val;
10577 }
10578 });
10579
10580 })();
10581
10582 /******************************************************************************/
10583 /*********************************** EASING ***********************************/
10584 /******************************************************************************/
10585
10586 (function() {
10587
10588 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
10589
10590 var baseEasings = {};
10591
10592 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
10593 baseEasings[ name ] = function( p ) {
10594 return Math.pow( p, i + 2 );
10595 };
10596 });
10597
10598 $.extend( baseEasings, {
10599 Sine: function( p ) {
10600 return 1 - Math.cos( p * Math.PI / 2 );
10601 },
10602 Circ: function( p ) {
10603 return 1 - Math.sqrt( 1 - p * p );
10604 },
10605 Elastic: function( p ) {
10606 return p === 0 || p === 1 ? p :
10607 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
10608 },
10609 Back: function( p ) {
10610 return p * p * ( 3 * p - 2 );
10611 },
10612 Bounce: function( p ) {
10613 var pow2,
10614 bounce = 4;
10615
10616 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
10617 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
10618 }
10619 });
10620
10621 $.each( baseEasings, function( name, easeIn ) {
10622 $.easing[ "easeIn" + name ] = easeIn;
10623 $.easing[ "easeOut" + name ] = function( p ) {
10624 return 1 - easeIn( 1 - p );
10625 };
10626 $.easing[ "easeInOut" + name ] = function( p ) {
10627 return p < 0.5 ?
10628 easeIn( p * 2 ) / 2 :
10629 1 - easeIn( p * -2 + 2 ) / 2;
10630 };
10631 });
10632
10633 })();
10634
10635 var effect = $.effects;
10636
10637
10638 /*!
10639 * jQuery UI Effects Blind 1.11.4
10640 * http://jqueryui.com
10641 *
10642 * Copyright jQuery Foundation and other contributors
10643 * Released under the MIT license.
10644 * http://jquery.org/license
10645 *
10646 * http://api.jqueryui.com/blind-effect/
10647 */
10648
10649
10650 var effectBlind = $.effects.effect.blind = function( o, done ) {
10651 // Create element
10652 var el = $( this ),
10653 rvertical = /up|down|vertical/,
10654 rpositivemotion = /up|left|vertical|horizontal/,
10655 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10656 mode = $.effects.setMode( el, o.mode || "hide" ),
10657 direction = o.direction || "up",
10658 vertical = rvertical.test( direction ),
10659 ref = vertical ? "height" : "width",
10660 ref2 = vertical ? "top" : "left",
10661 motion = rpositivemotion.test( direction ),
10662 animation = {},
10663 show = mode === "show",
10664 wrapper, distance, margin;
10665
10666 // if already wrapped, the wrapper's properties are my property. #6245
10667 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
10668 $.effects.save( el.parent(), props );
10669 } else {
10670 $.effects.save( el, props );
10671 }
10672 el.show();
10673 wrapper = $.effects.createWrapper( el ).css({
10674 overflow: "hidden"
10675 });
10676
10677 distance = wrapper[ ref ]();
10678 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
10679
10680 animation[ ref ] = show ? distance : 0;
10681 if ( !motion ) {
10682 el
10683 .css( vertical ? "bottom" : "right", 0 )
10684 .css( vertical ? "top" : "left", "auto" )
10685 .css({ position: "absolute" });
10686
10687 animation[ ref2 ] = show ? margin : distance + margin;
10688 }
10689
10690 // start at 0 if we are showing
10691 if ( show ) {
10692 wrapper.css( ref, 0 );
10693 if ( !motion ) {
10694 wrapper.css( ref2, margin + distance );
10695 }
10696 }
10697
10698 // Animate
10699 wrapper.animate( animation, {
10700 duration: o.duration,
10701 easing: o.easing,
10702 queue: false,
10703 complete: function() {
10704 if ( mode === "hide" ) {
10705 el.hide();
10706 }
10707 $.effects.restore( el, props );
10708 $.effects.removeWrapper( el );
10709 done();
10710 }
10711 });
10712 };
10713
10714
10715 /*!
10716 * jQuery UI Effects Bounce 1.11.4
10717 * http://jqueryui.com
10718 *
10719 * Copyright jQuery Foundation and other contributors
10720 * Released under the MIT license.
10721 * http://jquery.org/license
10722 *
10723 * http://api.jqueryui.com/bounce-effect/
10724 */
10725
10726
10727 var effectBounce = $.effects.effect.bounce = function( o, done ) {
10728 var el = $( this ),
10729 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10730
10731 // defaults:
10732 mode = $.effects.setMode( el, o.mode || "effect" ),
10733 hide = mode === "hide",
10734 show = mode === "show",
10735 direction = o.direction || "up",
10736 distance = o.distance,
10737 times = o.times || 5,
10738
10739 // number of internal animations
10740 anims = times * 2 + ( show || hide ? 1 : 0 ),
10741 speed = o.duration / anims,
10742 easing = o.easing,
10743
10744 // utility:
10745 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10746 motion = ( direction === "up" || direction === "left" ),
10747 i,
10748 upAnim,
10749 downAnim,
10750
10751 // we will need to re-assemble the queue to stack our animations in place
10752 queue = el.queue(),
10753 queuelen = queue.length;
10754
10755 // Avoid touching opacity to prevent clearType and PNG issues in IE
10756 if ( show || hide ) {
10757 props.push( "opacity" );
10758 }
10759
10760 $.effects.save( el, props );
10761 el.show();
10762 $.effects.createWrapper( el ); // Create Wrapper
10763
10764 // default distance for the BIGGEST bounce is the outer Distance / 3
10765 if ( !distance ) {
10766 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
10767 }
10768
10769 if ( show ) {
10770 downAnim = { opacity: 1 };
10771 downAnim[ ref ] = 0;
10772
10773 // if we are showing, force opacity 0 and set the initial position
10774 // then do the "first" animation
10775 el.css( "opacity", 0 )
10776 .css( ref, motion ? -distance * 2 : distance * 2 )
10777 .animate( downAnim, speed, easing );
10778 }
10779
10780 // start at the smallest distance if we are hiding
10781 if ( hide ) {
10782 distance = distance / Math.pow( 2, times - 1 );
10783 }
10784
10785 downAnim = {};
10786 downAnim[ ref ] = 0;
10787 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
10788 for ( i = 0; i < times; i++ ) {
10789 upAnim = {};
10790 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10791
10792 el.animate( upAnim, speed, easing )
10793 .animate( downAnim, speed, easing );
10794
10795 distance = hide ? distance * 2 : distance / 2;
10796 }
10797
10798 // Last Bounce when Hiding
10799 if ( hide ) {
10800 upAnim = { opacity: 0 };
10801 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
10802
10803 el.animate( upAnim, speed, easing );
10804 }
10805
10806 el.queue(function() {
10807 if ( hide ) {
10808 el.hide();
10809 }
10810 $.effects.restore( el, props );
10811 $.effects.removeWrapper( el );
10812 done();
10813 });
10814
10815 // inject all the animations we just queued to be first in line (after "inprogress")
10816 if ( queuelen > 1) {
10817 queue.splice.apply( queue,
10818 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
10819 }
10820 el.dequeue();
10821
10822 };
10823
10824
10825 /*!
10826 * jQuery UI Effects Clip 1.11.4
10827 * http://jqueryui.com
10828 *
10829 * Copyright jQuery Foundation and other contributors
10830 * Released under the MIT license.
10831 * http://jquery.org/license
10832 *
10833 * http://api.jqueryui.com/clip-effect/
10834 */
10835
10836
10837 var effectClip = $.effects.effect.clip = function( o, done ) {
10838 // Create element
10839 var el = $( this ),
10840 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
10841 mode = $.effects.setMode( el, o.mode || "hide" ),
10842 show = mode === "show",
10843 direction = o.direction || "vertical",
10844 vert = direction === "vertical",
10845 size = vert ? "height" : "width",
10846 position = vert ? "top" : "left",
10847 animation = {},
10848 wrapper, animate, distance;
10849
10850 // Save & Show
10851 $.effects.save( el, props );
10852 el.show();
10853
10854 // Create Wrapper
10855 wrapper = $.effects.createWrapper( el ).css({
10856 overflow: "hidden"
10857 });
10858 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
10859 distance = animate[ size ]();
10860
10861 // Shift
10862 if ( show ) {
10863 animate.css( size, 0 );
10864 animate.css( position, distance / 2 );
10865 }
10866
10867 // Create Animation Object:
10868 animation[ size ] = show ? distance : 0;
10869 animation[ position ] = show ? 0 : distance / 2;
10870
10871 // Animate
10872 animate.animate( animation, {
10873 queue: false,
10874 duration: o.duration,
10875 easing: o.easing,
10876 complete: function() {
10877 if ( !show ) {
10878 el.hide();
10879 }
10880 $.effects.restore( el, props );
10881 $.effects.removeWrapper( el );
10882 done();
10883 }
10884 });
10885
10886 };
10887
10888
10889 /*!
10890 * jQuery UI Effects Drop 1.11.4
10891 * http://jqueryui.com
10892 *
10893 * Copyright jQuery Foundation and other contributors
10894 * Released under the MIT license.
10895 * http://jquery.org/license
10896 *
10897 * http://api.jqueryui.com/drop-effect/
10898 */
10899
10900
10901 var effectDrop = $.effects.effect.drop = function( o, done ) {
10902
10903 var el = $( this ),
10904 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
10905 mode = $.effects.setMode( el, o.mode || "hide" ),
10906 show = mode === "show",
10907 direction = o.direction || "left",
10908 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
10909 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
10910 animation = {
10911 opacity: show ? 1 : 0
10912 },
10913 distance;
10914
10915 // Adjust
10916 $.effects.save( el, props );
10917 el.show();
10918 $.effects.createWrapper( el );
10919
10920 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
10921
10922 if ( show ) {
10923 el
10924 .css( "opacity", 0 )
10925 .css( ref, motion === "pos" ? -distance : distance );
10926 }
10927
10928 // Animation
10929 animation[ ref ] = ( show ?
10930 ( motion === "pos" ? "+=" : "-=" ) :
10931 ( motion === "pos" ? "-=" : "+=" ) ) +
10932 distance;
10933
10934 // Animate
10935 el.animate( animation, {
10936 queue: false,
10937 duration: o.duration,
10938 easing: o.easing,
10939 complete: function() {
10940 if ( mode === "hide" ) {
10941 el.hide();
10942 }
10943 $.effects.restore( el, props );
10944 $.effects.removeWrapper( el );
10945 done();
10946 }
10947 });
10948 };
10949
10950
10951 /*!
10952 * jQuery UI Effects Explode 1.11.4
10953 * http://jqueryui.com
10954 *
10955 * Copyright jQuery Foundation and other contributors
10956 * Released under the MIT license.
10957 * http://jquery.org/license
10958 *
10959 * http://api.jqueryui.com/explode-effect/
10960 */
10961
10962
10963 var effectExplode = $.effects.effect.explode = function( o, done ) {
10964
10965 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
10966 cells = rows,
10967 el = $( this ),
10968 mode = $.effects.setMode( el, o.mode || "hide" ),
10969 show = mode === "show",
10970
10971 // show and then visibility:hidden the element before calculating offset
10972 offset = el.show().css( "visibility", "hidden" ).offset(),
10973
10974 // width and height of a piece
10975 width = Math.ceil( el.outerWidth() / cells ),
10976 height = Math.ceil( el.outerHeight() / rows ),
10977 pieces = [],
10978
10979 // loop
10980 i, j, left, top, mx, my;
10981
10982 // children animate complete:
10983 function childComplete() {
10984 pieces.push( this );
10985 if ( pieces.length === rows * cells ) {
10986 animComplete();
10987 }
10988 }
10989
10990 // clone the element for each row and cell.
10991 for ( i = 0; i < rows ; i++ ) { // ===>
10992 top = offset.top + i * height;
10993 my = i - ( rows - 1 ) / 2 ;
10994
10995 for ( j = 0; j < cells ; j++ ) { // |||
10996 left = offset.left + j * width;
10997 mx = j - ( cells - 1 ) / 2 ;
10998
10999 // Create a clone of the now hidden main element that will be absolute positioned
11000 // within a wrapper div off the -left and -top equal to size of our pieces
11001 el
11002 .clone()
11003 .appendTo( "body" )
11004 .wrap( "<div></div>" )
11005 .css({
11006 position: "absolute",
11007 visibility: "visible",
11008 left: -j * width,
11009 top: -i * height
11010 })
11011
11012 // select the wrapper - make it overflow: hidden and absolute positioned based on
11013 // where the original was located +left and +top equal to the size of pieces
11014 .parent()
11015 .addClass( "ui-effects-explode" )
11016 .css({
11017 position: "absolute",
11018 overflow: "hidden",
11019 width: width,
11020 height: height,
11021 left: left + ( show ? mx * width : 0 ),
11022 top: top + ( show ? my * height : 0 ),
11023 opacity: show ? 0 : 1
11024 }).animate({
11025 left: left + ( show ? 0 : mx * width ),
11026 top: top + ( show ? 0 : my * height ),
11027 opacity: show ? 1 : 0
11028 }, o.duration || 500, o.easing, childComplete );
11029 }
11030 }
11031
11032 function animComplete() {
11033 el.css({
11034 visibility: "visible"
11035 });
11036 $( pieces ).remove();
11037 if ( !show ) {
11038 el.hide();
11039 }
11040 done();
11041 }
11042 };
11043
11044
11045 /*!
11046 * jQuery UI Effects Fade 1.11.4
11047 * http://jqueryui.com
11048 *
11049 * Copyright jQuery Foundation and other contributors
11050 * Released under the MIT license.
11051 * http://jquery.org/license
11052 *
11053 * http://api.jqueryui.com/fade-effect/
11054 */
11055
11056
11057 var effectFade = $.effects.effect.fade = function( o, done ) {
11058 var el = $( this ),
11059 mode = $.effects.setMode( el, o.mode || "toggle" );
11060
11061 el.animate({
11062 opacity: mode
11063 }, {
11064 queue: false,
11065 duration: o.duration,
11066 easing: o.easing,
11067 complete: done
11068 });
11069 };
11070
11071
11072 /*!
11073 * jQuery UI Effects Fold 1.11.4
11074 * http://jqueryui.com
11075 *
11076 * Copyright jQuery Foundation and other contributors
11077 * Released under the MIT license.
11078 * http://jquery.org/license
11079 *
11080 * http://api.jqueryui.com/fold-effect/
11081 */
11082
11083
11084 var effectFold = $.effects.effect.fold = function( o, done ) {
11085
11086 // Create element
11087 var el = $( this ),
11088 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11089 mode = $.effects.setMode( el, o.mode || "hide" ),
11090 show = mode === "show",
11091 hide = mode === "hide",
11092 size = o.size || 15,
11093 percent = /([0-9]+)%/.exec( size ),
11094 horizFirst = !!o.horizFirst,
11095 widthFirst = show !== horizFirst,
11096 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
11097 duration = o.duration / 2,
11098 wrapper, distance,
11099 animation1 = {},
11100 animation2 = {};
11101
11102 $.effects.save( el, props );
11103 el.show();
11104
11105 // Create Wrapper
11106 wrapper = $.effects.createWrapper( el ).css({
11107 overflow: "hidden"
11108 });
11109 distance = widthFirst ?
11110 [ wrapper.width(), wrapper.height() ] :
11111 [ wrapper.height(), wrapper.width() ];
11112
11113 if ( percent ) {
11114 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
11115 }
11116 if ( show ) {
11117 wrapper.css( horizFirst ? {
11118 height: 0,
11119 width: size
11120 } : {
11121 height: size,
11122 width: 0
11123 });
11124 }
11125
11126 // Animation
11127 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
11128 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
11129
11130 // Animate
11131 wrapper
11132 .animate( animation1, duration, o.easing )
11133 .animate( animation2, duration, o.easing, function() {
11134 if ( hide ) {
11135 el.hide();
11136 }
11137 $.effects.restore( el, props );
11138 $.effects.removeWrapper( el );
11139 done();
11140 });
11141
11142 };
11143
11144
11145 /*!
11146 * jQuery UI Effects Highlight 1.11.4
11147 * http://jqueryui.com
11148 *
11149 * Copyright jQuery Foundation and other contributors
11150 * Released under the MIT license.
11151 * http://jquery.org/license
11152 *
11153 * http://api.jqueryui.com/highlight-effect/
11154 */
11155
11156
11157 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
11158 var elem = $( this ),
11159 props = [ "backgroundImage", "backgroundColor", "opacity" ],
11160 mode = $.effects.setMode( elem, o.mode || "show" ),
11161 animation = {
11162 backgroundColor: elem.css( "backgroundColor" )
11163 };
11164
11165 if (mode === "hide") {
11166 animation.opacity = 0;
11167 }
11168
11169 $.effects.save( elem, props );
11170
11171 elem
11172 .show()
11173 .css({
11174 backgroundImage: "none",
11175 backgroundColor: o.color || "#ffff99"
11176 })
11177 .animate( animation, {
11178 queue: false,
11179 duration: o.duration,
11180 easing: o.easing,
11181 complete: function() {
11182 if ( mode === "hide" ) {
11183 elem.hide();
11184 }
11185 $.effects.restore( elem, props );
11186 done();
11187 }
11188 });
11189 };
11190
11191
11192 /*!
11193 * jQuery UI Effects Size 1.11.4
11194 * http://jqueryui.com
11195 *
11196 * Copyright jQuery Foundation and other contributors
11197 * Released under the MIT license.
11198 * http://jquery.org/license
11199 *
11200 * http://api.jqueryui.com/size-effect/
11201 */
11202
11203
11204 var effectSize = $.effects.effect.size = function( o, done ) {
11205
11206 // Create element
11207 var original, baseline, factor,
11208 el = $( this ),
11209 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
11210
11211 // Always restore
11212 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
11213
11214 // Copy for children
11215 props2 = [ "width", "height", "overflow" ],
11216 cProps = [ "fontSize" ],
11217 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
11218 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
11219
11220 // Set options
11221 mode = $.effects.setMode( el, o.mode || "effect" ),
11222 restore = o.restore || mode !== "effect",
11223 scale = o.scale || "both",
11224 origin = o.origin || [ "middle", "center" ],
11225 position = el.css( "position" ),
11226 props = restore ? props0 : props1,
11227 zero = {
11228 height: 0,
11229 width: 0,
11230 outerHeight: 0,
11231 outerWidth: 0
11232 };
11233
11234 if ( mode === "show" ) {
11235 el.show();
11236 }
11237 original = {
11238 height: el.height(),
11239 width: el.width(),
11240 outerHeight: el.outerHeight(),
11241 outerWidth: el.outerWidth()
11242 };
11243
11244 if ( o.mode === "toggle" && mode === "show" ) {
11245 el.from = o.to || zero;
11246 el.to = o.from || original;
11247 } else {
11248 el.from = o.from || ( mode === "show" ? zero : original );
11249 el.to = o.to || ( mode === "hide" ? zero : original );
11250 }
11251
11252 // Set scaling factor
11253 factor = {
11254 from: {
11255 y: el.from.height / original.height,
11256 x: el.from.width / original.width
11257 },
11258 to: {
11259 y: el.to.height / original.height,
11260 x: el.to.width / original.width
11261 }
11262 };
11263
11264 // Scale the css box
11265 if ( scale === "box" || scale === "both" ) {
11266
11267 // Vertical props scaling
11268 if ( factor.from.y !== factor.to.y ) {
11269 props = props.concat( vProps );
11270 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
11271 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
11272 }
11273
11274 // Horizontal props scaling
11275 if ( factor.from.x !== factor.to.x ) {
11276 props = props.concat( hProps );
11277 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
11278 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
11279 }
11280 }
11281
11282 // Scale the content
11283 if ( scale === "content" || scale === "both" ) {
11284
11285 // Vertical props scaling
11286 if ( factor.from.y !== factor.to.y ) {
11287 props = props.concat( cProps ).concat( props2 );
11288 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
11289 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
11290 }
11291 }
11292
11293 $.effects.save( el, props );
11294 el.show();
11295 $.effects.createWrapper( el );
11296 el.css( "overflow", "hidden" ).css( el.from );
11297
11298 // Adjust
11299 if (origin) { // Calculate baseline shifts
11300 baseline = $.effects.getBaseline( origin, original );
11301 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
11302 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
11303 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
11304 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
11305 }
11306 el.css( el.from ); // set top & left
11307
11308 // Animate
11309 if ( scale === "content" || scale === "both" ) { // Scale the children
11310
11311 // Add margins/font-size
11312 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
11313 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
11314 props2 = props0.concat(vProps).concat(hProps);
11315
11316 el.find( "*[width]" ).each( function() {
11317 var child = $( this ),
11318 c_original = {
11319 height: child.height(),
11320 width: child.width(),
11321 outerHeight: child.outerHeight(),
11322 outerWidth: child.outerWidth()
11323 };
11324 if (restore) {
11325 $.effects.save(child, props2);
11326 }
11327
11328 child.from = {
11329 height: c_original.height * factor.from.y,
11330 width: c_original.width * factor.from.x,
11331 outerHeight: c_original.outerHeight * factor.from.y,
11332 outerWidth: c_original.outerWidth * factor.from.x
11333 };
11334 child.to = {
11335 height: c_original.height * factor.to.y,
11336 width: c_original.width * factor.to.x,
11337 outerHeight: c_original.height * factor.to.y,
11338 outerWidth: c_original.width * factor.to.x
11339 };
11340
11341 // Vertical props scaling
11342 if ( factor.from.y !== factor.to.y ) {
11343 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
11344 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
11345 }
11346
11347 // Horizontal props scaling
11348 if ( factor.from.x !== factor.to.x ) {
11349 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
11350 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
11351 }
11352
11353 // Animate children
11354 child.css( child.from );
11355 child.animate( child.to, o.duration, o.easing, function() {
11356
11357 // Restore children
11358 if ( restore ) {
11359 $.effects.restore( child, props2 );
11360 }
11361 });
11362 });
11363 }
11364
11365 // Animate
11366 el.animate( el.to, {
11367 queue: false,
11368 duration: o.duration,
11369 easing: o.easing,
11370 complete: function() {
11371 if ( el.to.opacity === 0 ) {
11372 el.css( "opacity", el.from.opacity );
11373 }
11374 if ( mode === "hide" ) {
11375 el.hide();
11376 }
11377 $.effects.restore( el, props );
11378 if ( !restore ) {
11379
11380 // we need to calculate our new positioning based on the scaling
11381 if ( position === "static" ) {
11382 el.css({
11383 position: "relative",
11384 top: el.to.top,
11385 left: el.to.left
11386 });
11387 } else {
11388 $.each([ "top", "left" ], function( idx, pos ) {
11389 el.css( pos, function( _, str ) {
11390 var val = parseInt( str, 10 ),
11391 toRef = idx ? el.to.left : el.to.top;
11392
11393 // if original was "auto", recalculate the new value from wrapper
11394 if ( str === "auto" ) {
11395 return toRef + "px";
11396 }
11397
11398 return val + toRef + "px";
11399 });
11400 });
11401 }
11402 }
11403
11404 $.effects.removeWrapper( el );
11405 done();
11406 }
11407 });
11408
11409 };
11410
11411
11412 /*!
11413 * jQuery UI Effects Scale 1.11.4
11414 * http://jqueryui.com
11415 *
11416 * Copyright jQuery Foundation and other contributors
11417 * Released under the MIT license.
11418 * http://jquery.org/license
11419 *
11420 * http://api.jqueryui.com/scale-effect/
11421 */
11422
11423
11424 var effectScale = $.effects.effect.scale = function( o, done ) {
11425
11426 // Create element
11427 var el = $( this ),
11428 options = $.extend( true, {}, o ),
11429 mode = $.effects.setMode( el, o.mode || "effect" ),
11430 percent = parseInt( o.percent, 10 ) ||
11431 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
11432 direction = o.direction || "both",
11433 origin = o.origin,
11434 original = {
11435 height: el.height(),
11436 width: el.width(),
11437 outerHeight: el.outerHeight(),
11438 outerWidth: el.outerWidth()
11439 },
11440 factor = {
11441 y: direction !== "horizontal" ? (percent / 100) : 1,
11442 x: direction !== "vertical" ? (percent / 100) : 1
11443 };
11444
11445 // We are going to pass this effect to the size effect:
11446 options.effect = "size";
11447 options.queue = false;
11448 options.complete = done;
11449
11450 // Set default origin and restore for show/hide
11451 if ( mode !== "effect" ) {
11452 options.origin = origin || [ "middle", "center" ];
11453 options.restore = true;
11454 }
11455
11456 options.from = o.from || ( mode === "show" ? {
11457 height: 0,
11458 width: 0,
11459 outerHeight: 0,
11460 outerWidth: 0
11461 } : original );
11462 options.to = {
11463 height: original.height * factor.y,
11464 width: original.width * factor.x,
11465 outerHeight: original.outerHeight * factor.y,
11466 outerWidth: original.outerWidth * factor.x
11467 };
11468
11469 // Fade option to support puff
11470 if ( options.fade ) {
11471 if ( mode === "show" ) {
11472 options.from.opacity = 0;
11473 options.to.opacity = 1;
11474 }
11475 if ( mode === "hide" ) {
11476 options.from.opacity = 1;
11477 options.to.opacity = 0;
11478 }
11479 }
11480
11481 // Animate
11482 el.effect( options );
11483
11484 };
11485
11486
11487 /*!
11488 * jQuery UI Effects Puff 1.11.4
11489 * http://jqueryui.com
11490 *
11491 * Copyright jQuery Foundation and other contributors
11492 * Released under the MIT license.
11493 * http://jquery.org/license
11494 *
11495 * http://api.jqueryui.com/puff-effect/
11496 */
11497
11498
11499 var effectPuff = $.effects.effect.puff = function( o, done ) {
11500 var elem = $( this ),
11501 mode = $.effects.setMode( elem, o.mode || "hide" ),
11502 hide = mode === "hide",
11503 percent = parseInt( o.percent, 10 ) || 150,
11504 factor = percent / 100,
11505 original = {
11506 height: elem.height(),
11507 width: elem.width(),
11508 outerHeight: elem.outerHeight(),
11509 outerWidth: elem.outerWidth()
11510 };
11511
11512 $.extend( o, {
11513 effect: "scale",
11514 queue: false,
11515 fade: true,
11516 mode: mode,
11517 complete: done,
11518 percent: hide ? percent : 100,
11519 from: hide ?
11520 original :
11521 {
11522 height: original.height * factor,
11523 width: original.width * factor,
11524 outerHeight: original.outerHeight * factor,
11525 outerWidth: original.outerWidth * factor
11526 }
11527 });
11528
11529 elem.effect( o );
11530 };
11531
11532
11533 /*!
11534 * jQuery UI Effects Pulsate 1.11.4
11535 * http://jqueryui.com
11536 *
11537 * Copyright jQuery Foundation and other contributors
11538 * Released under the MIT license.
11539 * http://jquery.org/license
11540 *
11541 * http://api.jqueryui.com/pulsate-effect/
11542 */
11543
11544
11545 var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
11546 var elem = $( this ),
11547 mode = $.effects.setMode( elem, o.mode || "show" ),
11548 show = mode === "show",
11549 hide = mode === "hide",
11550 showhide = ( show || mode === "hide" ),
11551
11552 // showing or hiding leaves of the "last" animation
11553 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
11554 duration = o.duration / anims,
11555 animateTo = 0,
11556 queue = elem.queue(),
11557 queuelen = queue.length,
11558 i;
11559
11560 if ( show || !elem.is(":visible")) {
11561 elem.css( "opacity", 0 ).show();
11562 animateTo = 1;
11563 }
11564
11565 // anims - 1 opacity "toggles"
11566 for ( i = 1; i < anims; i++ ) {
11567 elem.animate({
11568 opacity: animateTo
11569 }, duration, o.easing );
11570 animateTo = 1 - animateTo;
11571 }
11572
11573 elem.animate({
11574 opacity: animateTo
11575 }, duration, o.easing);
11576
11577 elem.queue(function() {
11578 if ( hide ) {
11579 elem.hide();
11580 }
11581 done();
11582 });
11583
11584 // We just queued up "anims" animations, we need to put them next in the queue
11585 if ( queuelen > 1 ) {
11586 queue.splice.apply( queue,
11587 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11588 }
11589 elem.dequeue();
11590 };
11591
11592
11593 /*!
11594 * jQuery UI Effects Shake 1.11.4
11595 * http://jqueryui.com
11596 *
11597 * Copyright jQuery Foundation and other contributors
11598 * Released under the MIT license.
11599 * http://jquery.org/license
11600 *
11601 * http://api.jqueryui.com/shake-effect/
11602 */
11603
11604
11605 var effectShake = $.effects.effect.shake = function( o, done ) {
11606
11607 var el = $( this ),
11608 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
11609 mode = $.effects.setMode( el, o.mode || "effect" ),
11610 direction = o.direction || "left",
11611 distance = o.distance || 20,
11612 times = o.times || 3,
11613 anims = times * 2 + 1,
11614 speed = Math.round( o.duration / anims ),
11615 ref = (direction === "up" || direction === "down") ? "top" : "left",
11616 positiveMotion = (direction === "up" || direction === "left"),
11617 animation = {},
11618 animation1 = {},
11619 animation2 = {},
11620 i,
11621
11622 // we will need to re-assemble the queue to stack our animations in place
11623 queue = el.queue(),
11624 queuelen = queue.length;
11625
11626 $.effects.save( el, props );
11627 el.show();
11628 $.effects.createWrapper( el );
11629
11630 // Animation
11631 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
11632 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
11633 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
11634
11635 // Animate
11636 el.animate( animation, speed, o.easing );
11637
11638 // Shakes
11639 for ( i = 1; i < times; i++ ) {
11640 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
11641 }
11642 el
11643 .animate( animation1, speed, o.easing )
11644 .animate( animation, speed / 2, o.easing )
11645 .queue(function() {
11646 if ( mode === "hide" ) {
11647 el.hide();
11648 }
11649 $.effects.restore( el, props );
11650 $.effects.removeWrapper( el );
11651 done();
11652 });
11653
11654 // inject all the animations we just queued to be first in line (after "inprogress")
11655 if ( queuelen > 1) {
11656 queue.splice.apply( queue,
11657 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
11658 }
11659 el.dequeue();
11660
11661 };
11662
11663
11664 /*!
11665 * jQuery UI Effects Slide 1.11.4
11666 * http://jqueryui.com
11667 *
11668 * Copyright jQuery Foundation and other contributors
11669 * Released under the MIT license.
11670 * http://jquery.org/license
11671 *
11672 * http://api.jqueryui.com/slide-effect/
11673 */
11674
11675
11676 var effectSlide = $.effects.effect.slide = function( o, done ) {
11677
11678 // Create element
11679 var el = $( this ),
11680 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
11681 mode = $.effects.setMode( el, o.mode || "show" ),
11682 show = mode === "show",
11683 direction = o.direction || "left",
11684 ref = (direction === "up" || direction === "down") ? "top" : "left",
11685 positiveMotion = (direction === "up" || direction === "left"),
11686 distance,
11687 animation = {};
11688
11689 // Adjust
11690 $.effects.save( el, props );
11691 el.show();
11692 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
11693
11694 $.effects.createWrapper( el ).css({
11695 overflow: "hidden"
11696 });
11697
11698 if ( show ) {
11699 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
11700 }
11701
11702 // Animation
11703 animation[ ref ] = ( show ?
11704 ( positiveMotion ? "+=" : "-=") :
11705 ( positiveMotion ? "-=" : "+=")) +
11706 distance;
11707
11708 // Animate
11709 el.animate( animation, {
11710 queue: false,
11711 duration: o.duration,
11712 easing: o.easing,
11713 complete: function() {
11714 if ( mode === "hide" ) {
11715 el.hide();
11716 }
11717 $.effects.restore( el, props );
11718 $.effects.removeWrapper( el );
11719 done();
11720 }
11721 });
11722 };
11723
11724
11725 /*!
11726 * jQuery UI Effects Transfer 1.11.4
11727 * http://jqueryui.com
11728 *
11729 * Copyright jQuery Foundation and other contributors
11730 * Released under the MIT license.
11731 * http://jquery.org/license
11732 *
11733 * http://api.jqueryui.com/transfer-effect/
11734 */
11735
11736
11737 var effectTransfer = $.effects.effect.transfer = function( o, done ) {
11738 var elem = $( this ),
11739 target = $( o.to ),
11740 targetFixed = target.css( "position" ) === "fixed",
11741 body = $("body"),
11742 fixTop = targetFixed ? body.scrollTop() : 0,
11743 fixLeft = targetFixed ? body.scrollLeft() : 0,
11744 endPosition = target.offset(),
11745 animation = {
11746 top: endPosition.top - fixTop,
11747 left: endPosition.left - fixLeft,
11748 height: target.innerHeight(),
11749 width: target.innerWidth()
11750 },
11751 startPosition = elem.offset(),
11752 transfer = $( "<div class='ui-effects-transfer'></div>" )
11753 .appendTo( document.body )
11754 .addClass( o.className )
11755 .css({
11756 top: startPosition.top - fixTop,
11757 left: startPosition.left - fixLeft,
11758 height: elem.innerHeight(),
11759 width: elem.innerWidth(),
11760 position: targetFixed ? "fixed" : "absolute"
11761 })
11762 .animate( animation, o.duration, o.easing, function() {
11763 transfer.remove();
11764 done();
11765 });
11766 };
11767
11768
11769 /*!
11770 * jQuery UI Progressbar 1.11.4
11771 * http://jqueryui.com
11772 *
11773 * Copyright jQuery Foundation and other contributors
11774 * Released under the MIT license.
11775 * http://jquery.org/license
11776 *
11777 * http://api.jqueryui.com/progressbar/
11778 */
11779
11780
11781 var progressbar = $.widget( "ui.progressbar", {
11782 version: "1.11.4",
11783 options: {
11784 max: 100,
11785 value: 0,
11786
11787 change: null,
11788 complete: null
11789 },
11790
11791 min: 0,
11792
11793 _create: function() {
11794 // Constrain initial value
11795 this.oldValue = this.options.value = this._constrainedValue();
11796
11797 this.element
11798 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11799 .attr({
11800 // Only set static values, aria-valuenow and aria-valuemax are
11801 // set inside _refreshValue()
11802 role: "progressbar",
11803 "aria-valuemin": this.min
11804 });
11805
11806 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
11807 .appendTo( this.element );
11808
11809 this._refreshValue();
11810 },
11811
11812 _destroy: function() {
11813 this.element
11814 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
11815 .removeAttr( "role" )
11816 .removeAttr( "aria-valuemin" )
11817 .removeAttr( "aria-valuemax" )
11818 .removeAttr( "aria-valuenow" );
11819
11820 this.valueDiv.remove();
11821 },
11822
11823 value: function( newValue ) {
11824 if ( newValue === undefined ) {
11825 return this.options.value;
11826 }
11827
11828 this.options.value = this._constrainedValue( newValue );
11829 this._refreshValue();
11830 },
11831
11832 _constrainedValue: function( newValue ) {
11833 if ( newValue === undefined ) {
11834 newValue = this.options.value;
11835 }
11836
11837 this.indeterminate = newValue === false;
11838
11839 // sanitize value
11840 if ( typeof newValue !== "number" ) {
11841 newValue = 0;
11842 }
11843
11844 return this.indeterminate ? false :
11845 Math.min( this.options.max, Math.max( this.min, newValue ) );
11846 },
11847
11848 _setOptions: function( options ) {
11849 // Ensure "value" option is set after other values (like max)
11850 var value = options.value;
11851 delete options.value;
11852
11853 this._super( options );
11854
11855 this.options.value = this._constrainedValue( value );
11856 this._refreshValue();
11857 },
11858
11859 _setOption: function( key, value ) {
11860 if ( key === "max" ) {
11861 // Don't allow a max less than min
11862 value = Math.max( this.min, value );
11863 }
11864 if ( key === "disabled" ) {
11865 this.element
11866 .toggleClass( "ui-state-disabled", !!value )
11867 .attr( "aria-disabled", value );
11868 }
11869 this._super( key, value );
11870 },
11871
11872 _percentage: function() {
11873 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
11874 },
11875
11876 _refreshValue: function() {
11877 var value = this.options.value,
11878 percentage = this._percentage();
11879
11880 this.valueDiv
11881 .toggle( this.indeterminate || value > this.min )
11882 .toggleClass( "ui-corner-right", value === this.options.max )
11883 .width( percentage.toFixed(0) + "%" );
11884
11885 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
11886
11887 if ( this.indeterminate ) {
11888 this.element.removeAttr( "aria-valuenow" );
11889 if ( !this.overlayDiv ) {
11890 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
11891 }
11892 } else {
11893 this.element.attr({
11894 "aria-valuemax": this.options.max,
11895 "aria-valuenow": value
11896 });
11897 if ( this.overlayDiv ) {
11898 this.overlayDiv.remove();
11899 this.overlayDiv = null;
11900 }
11901 }
11902
11903 if ( this.oldValue !== value ) {
11904 this.oldValue = value;
11905 this._trigger( "change" );
11906 }
11907 if ( value === this.options.max ) {
11908 this._trigger( "complete" );
11909 }
11910 }
11911 });
11912
11913
11914 /*!
11915 * jQuery UI Selectable 1.11.4
11916 * http://jqueryui.com
11917 *
11918 * Copyright jQuery Foundation and other contributors
11919 * Released under the MIT license.
11920 * http://jquery.org/license
11921 *
11922 * http://api.jqueryui.com/selectable/
11923 */
11924
11925
11926 var selectable = $.widget("ui.selectable", $.ui.mouse, {
11927 version: "1.11.4",
11928 options: {
11929 appendTo: "body",
11930 autoRefresh: true,
11931 distance: 0,
11932 filter: "*",
11933 tolerance: "touch",
11934
11935 // callbacks
11936 selected: null,
11937 selecting: null,
11938 start: null,
11939 stop: null,
11940 unselected: null,
11941 unselecting: null
11942 },
11943 _create: function() {
11944 var selectees,
11945 that = this;
11946
11947 this.element.addClass("ui-selectable");
11948
11949 this.dragged = false;
11950
11951 // cache selectee children based on filter
11952 this.refresh = function() {
11953 selectees = $(that.options.filter, that.element[0]);
11954 selectees.addClass("ui-selectee");
11955 selectees.each(function() {
11956 var $this = $(this),
11957 pos = $this.offset();
11958 $.data(this, "selectable-item", {
11959 element: this,
11960 $element: $this,
11961 left: pos.left,
11962 top: pos.top,
11963 right: pos.left + $this.outerWidth(),
11964 bottom: pos.top + $this.outerHeight(),
11965 startselected: false,
11966 selected: $this.hasClass("ui-selected"),
11967 selecting: $this.hasClass("ui-selecting"),
11968 unselecting: $this.hasClass("ui-unselecting")
11969 });
11970 });
11971 };
11972 this.refresh();
11973
11974 this.selectees = selectees.addClass("ui-selectee");
11975
11976 this._mouseInit();
11977
11978 this.helper = $("<div class='ui-selectable-helper'></div>");
11979 },
11980
11981 _destroy: function() {
11982 this.selectees
11983 .removeClass("ui-selectee")
11984 .removeData("selectable-item");
11985 this.element
11986 .removeClass("ui-selectable ui-selectable-disabled");
11987 this._mouseDestroy();
11988 },
11989
11990 _mouseStart: function(event) {
11991 var that = this,
11992 options = this.options;
11993
11994 this.opos = [ event.pageX, event.pageY ];
11995
11996 if (this.options.disabled) {
11997 return;
11998 }
11999
12000 this.selectees = $(options.filter, this.element[0]);
12001
12002 this._trigger("start", event);
12003
12004 $(options.appendTo).append(this.helper);
12005 // position helper (lasso)
12006 this.helper.css({
12007 "left": event.pageX,
12008 "top": event.pageY,
12009 "width": 0,
12010 "height": 0
12011 });
12012
12013 if (options.autoRefresh) {
12014 this.refresh();
12015 }
12016
12017 this.selectees.filter(".ui-selected").each(function() {
12018 var selectee = $.data(this, "selectable-item");
12019 selectee.startselected = true;
12020 if (!event.metaKey && !event.ctrlKey) {
12021 selectee.$element.removeClass("ui-selected");
12022 selectee.selected = false;
12023 selectee.$element.addClass("ui-unselecting");
12024 selectee.unselecting = true;
12025 // selectable UNSELECTING callback
12026 that._trigger("unselecting", event, {
12027 unselecting: selectee.element
12028 });
12029 }
12030 });
12031
12032 $(event.target).parents().addBack().each(function() {
12033 var doSelect,
12034 selectee = $.data(this, "selectable-item");
12035 if (selectee) {
12036 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
12037 selectee.$element
12038 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
12039 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
12040 selectee.unselecting = !doSelect;
12041 selectee.selecting = doSelect;
12042 selectee.selected = doSelect;
12043 // selectable (UN)SELECTING callback
12044 if (doSelect) {
12045 that._trigger("selecting", event, {
12046 selecting: selectee.element
12047 });
12048 } else {
12049 that._trigger("unselecting", event, {
12050 unselecting: selectee.element
12051 });
12052 }
12053 return false;
12054 }
12055 });
12056
12057 },
12058
12059 _mouseDrag: function(event) {
12060
12061 this.dragged = true;
12062
12063 if (this.options.disabled) {
12064 return;
12065 }
12066
12067 var tmp,
12068 that = this,
12069 options = this.options,
12070 x1 = this.opos[0],
12071 y1 = this.opos[1],
12072 x2 = event.pageX,
12073 y2 = event.pageY;
12074
12075 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
12076 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
12077 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
12078
12079 this.selectees.each(function() {
12080 var selectee = $.data(this, "selectable-item"),
12081 hit = false;
12082
12083 //prevent helper from being selected if appendTo: selectable
12084 if (!selectee || selectee.element === that.element[0]) {
12085 return;
12086 }
12087
12088 if (options.tolerance === "touch") {
12089 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
12090 } else if (options.tolerance === "fit") {
12091 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
12092 }
12093
12094 if (hit) {
12095 // SELECT
12096 if (selectee.selected) {
12097 selectee.$element.removeClass("ui-selected");
12098 selectee.selected = false;
12099 }
12100 if (selectee.unselecting) {
12101 selectee.$element.removeClass("ui-unselecting");
12102 selectee.unselecting = false;
12103 }
12104 if (!selectee.selecting) {
12105 selectee.$element.addClass("ui-selecting");
12106 selectee.selecting = true;
12107 // selectable SELECTING callback
12108 that._trigger("selecting", event, {
12109 selecting: selectee.element
12110 });
12111 }
12112 } else {
12113 // UNSELECT
12114 if (selectee.selecting) {
12115 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
12116 selectee.$element.removeClass("ui-selecting");
12117 selectee.selecting = false;
12118 selectee.$element.addClass("ui-selected");
12119 selectee.selected = true;
12120 } else {
12121 selectee.$element.removeClass("ui-selecting");
12122 selectee.selecting = false;
12123 if (selectee.startselected) {
12124 selectee.$element.addClass("ui-unselecting");
12125 selectee.unselecting = true;
12126 }
12127 // selectable UNSELECTING callback
12128 that._trigger("unselecting", event, {
12129 unselecting: selectee.element
12130 });
12131 }
12132 }
12133 if (selectee.selected) {
12134 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
12135 selectee.$element.removeClass("ui-selected");
12136 selectee.selected = false;
12137
12138 selectee.$element.addClass("ui-unselecting");
12139 selectee.unselecting = true;
12140 // selectable UNSELECTING callback
12141 that._trigger("unselecting", event, {
12142 unselecting: selectee.element
12143 });
12144 }
12145 }
12146 }
12147 });
12148
12149 return false;
12150 },
12151
12152 _mouseStop: function(event) {
12153 var that = this;
12154
12155 this.dragged = false;
12156
12157 $(".ui-unselecting", this.element[0]).each(function() {
12158 var selectee = $.data(this, "selectable-item");
12159 selectee.$element.removeClass("ui-unselecting");
12160 selectee.unselecting = false;
12161 selectee.startselected = false;
12162 that._trigger("unselected", event, {
12163 unselected: selectee.element
12164 });
12165 });
12166 $(".ui-selecting", this.element[0]).each(function() {
12167 var selectee = $.data(this, "selectable-item");
12168 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
12169 selectee.selecting = false;
12170 selectee.selected = true;
12171 selectee.startselected = true;
12172 that._trigger("selected", event, {
12173 selected: selectee.element
12174 });
12175 });
12176 this._trigger("stop", event);
12177
12178 this.helper.remove();
12179
12180 return false;
12181 }
12182
12183 });
12184
12185
12186 /*!
12187 * jQuery UI Selectmenu 1.11.4
12188 * http://jqueryui.com
12189 *
12190 * Copyright jQuery Foundation and other contributors
12191 * Released under the MIT license.
12192 * http://jquery.org/license
12193 *
12194 * http://api.jqueryui.com/selectmenu
12195 */
12196
12197
12198 var selectmenu = $.widget( "ui.selectmenu", {
12199 version: "1.11.4",
12200 defaultElement: "<select>",
12201 options: {
12202 appendTo: null,
12203 disabled: null,
12204 icons: {
12205 button: "ui-icon-triangle-1-s"
12206 },
12207 position: {
12208 my: "left top",
12209 at: "left bottom",
12210 collision: "none"
12211 },
12212 width: null,
12213
12214 // callbacks
12215 change: null,
12216 close: null,
12217 focus: null,
12218 open: null,
12219 select: null
12220 },
12221
12222 _create: function() {
12223 var selectmenuId = this.element.uniqueId().attr( "id" );
12224 this.ids = {
12225 element: selectmenuId,
12226 button: selectmenuId + "-button",
12227 menu: selectmenuId + "-menu"
12228 };
12229
12230 this._drawButton();
12231 this._drawMenu();
12232
12233 if ( this.options.disabled ) {
12234 this.disable();
12235 }
12236 },
12237
12238 _drawButton: function() {
12239 var that = this;
12240
12241 // Associate existing label with the new button
12242 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
12243 this._on( this.label, {
12244 click: function( event ) {
12245 this.button.focus();
12246 event.preventDefault();
12247 }
12248 });
12249
12250 // Hide original select element
12251 this.element.hide();
12252
12253 // Create button
12254 this.button = $( "<span>", {
12255 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
12256 tabindex: this.options.disabled ? -1 : 0,
12257 id: this.ids.button,
12258 role: "combobox",
12259 "aria-expanded": "false",
12260 "aria-autocomplete": "list",
12261 "aria-owns": this.ids.menu,
12262 "aria-haspopup": "true"
12263 })
12264 .insertAfter( this.element );
12265
12266 $( "<span>", {
12267 "class": "ui-icon " + this.options.icons.button
12268 })
12269 .prependTo( this.button );
12270
12271 this.buttonText = $( "<span>", {
12272 "class": "ui-selectmenu-text"
12273 })
12274 .appendTo( this.button );
12275
12276 this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
12277 this._resizeButton();
12278
12279 this._on( this.button, this._buttonEvents );
12280 this.button.one( "focusin", function() {
12281
12282 // Delay rendering the menu items until the button receives focus.
12283 // The menu may have already been rendered via a programmatic open.
12284 if ( !that.menuItems ) {
12285 that._refreshMenu();
12286 }
12287 });
12288 this._hoverable( this.button );
12289 this._focusable( this.button );
12290 },
12291
12292 _drawMenu: function() {
12293 var that = this;
12294
12295 // Create menu
12296 this.menu = $( "<ul>", {
12297 "aria-hidden": "true",
12298 "aria-labelledby": this.ids.button,
12299 id: this.ids.menu
12300 });
12301
12302 // Wrap menu
12303 this.menuWrap = $( "<div>", {
12304 "class": "ui-selectmenu-menu ui-front"
12305 })
12306 .append( this.menu )
12307 .appendTo( this._appendTo() );
12308
12309 // Initialize menu widget
12310 this.menuInstance = this.menu
12311 .menu({
12312 role: "listbox",
12313 select: function( event, ui ) {
12314 event.preventDefault();
12315
12316 // support: IE8
12317 // If the item was selected via a click, the text selection
12318 // will be destroyed in IE
12319 that._setSelection();
12320
12321 that._select( ui.item.data( "ui-selectmenu-item" ), event );
12322 },
12323 focus: function( event, ui ) {
12324 var item = ui.item.data( "ui-selectmenu-item" );
12325
12326 // Prevent inital focus from firing and check if its a newly focused item
12327 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
12328 that._trigger( "focus", event, { item: item } );
12329 if ( !that.isOpen ) {
12330 that._select( item, event );
12331 }
12332 }
12333 that.focusIndex = item.index;
12334
12335 that.button.attr( "aria-activedescendant",
12336 that.menuItems.eq( item.index ).attr( "id" ) );
12337 }
12338 })
12339 .menu( "instance" );
12340
12341 // Adjust menu styles to dropdown
12342 this.menu
12343 .addClass( "ui-corner-bottom" )
12344 .removeClass( "ui-corner-all" );
12345
12346 // Don't close the menu on mouseleave
12347 this.menuInstance._off( this.menu, "mouseleave" );
12348
12349 // Cancel the menu's collapseAll on document click
12350 this.menuInstance._closeOnDocumentClick = function() {
12351 return false;
12352 };
12353
12354 // Selects often contain empty items, but never contain dividers
12355 this.menuInstance._isDivider = function() {
12356 return false;
12357 };
12358 },
12359
12360 refresh: function() {
12361 this._refreshMenu();
12362 this._setText( this.buttonText, this._getSelectedItem().text() );
12363 if ( !this.options.width ) {
12364 this._resizeButton();
12365 }
12366 },
12367
12368 _refreshMenu: function() {
12369 this.menu.empty();
12370
12371 var item,
12372 options = this.element.find( "option" );
12373
12374 if ( !options.length ) {
12375 return;
12376 }
12377
12378 this._parseOptions( options );
12379 this._renderMenu( this.menu, this.items );
12380
12381 this.menuInstance.refresh();
12382 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
12383
12384 item = this._getSelectedItem();
12385
12386 // Update the menu to have the correct item focused
12387 this.menuInstance.focus( null, item );
12388 this._setAria( item.data( "ui-selectmenu-item" ) );
12389
12390 // Set disabled state
12391 this._setOption( "disabled", this.element.prop( "disabled" ) );
12392 },
12393
12394 open: function( event ) {
12395 if ( this.options.disabled ) {
12396 return;
12397 }
12398
12399 // If this is the first time the menu is being opened, render the items
12400 if ( !this.menuItems ) {
12401 this._refreshMenu();
12402 } else {
12403
12404 // Menu clears focus on close, reset focus to selected item
12405 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
12406 this.menuInstance.focus( null, this._getSelectedItem() );
12407 }
12408
12409 this.isOpen = true;
12410 this._toggleAttr();
12411 this._resizeMenu();
12412 this._position();
12413
12414 this._on( this.document, this._documentClick );
12415
12416 this._trigger( "open", event );
12417 },
12418
12419 _position: function() {
12420 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
12421 },
12422
12423 close: function( event ) {
12424 if ( !this.isOpen ) {
12425 return;
12426 }
12427
12428 this.isOpen = false;
12429 this._toggleAttr();
12430
12431 this.range = null;
12432 this._off( this.document );
12433
12434 this._trigger( "close", event );
12435 },
12436
12437 widget: function() {
12438 return this.button;
12439 },
12440
12441 menuWidget: function() {
12442 return this.menu;
12443 },
12444
12445 _renderMenu: function( ul, items ) {
12446 var that = this,
12447 currentOptgroup = "";
12448
12449 $.each( items, function( index, item ) {
12450 if ( item.optgroup !== currentOptgroup ) {
12451 $( "<li>", {
12452 "class": "ui-selectmenu-optgroup ui-menu-divider" +
12453 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
12454 " ui-state-disabled" :
12455 "" ),
12456 text: item.optgroup
12457 })
12458 .appendTo( ul );
12459
12460 currentOptgroup = item.optgroup;
12461 }
12462
12463 that._renderItemData( ul, item );
12464 });
12465 },
12466
12467 _renderItemData: function( ul, item ) {
12468 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
12469 },
12470
12471 _renderItem: function( ul, item ) {
12472 var li = $( "<li>" );
12473
12474 if ( item.disabled ) {
12475 li.addClass( "ui-state-disabled" );
12476 }
12477 this._setText( li, item.label );
12478
12479 return li.appendTo( ul );
12480 },
12481
12482 _setText: function( element, value ) {
12483 if ( value ) {
12484 element.text( value );
12485 } else {
12486 element.html( "&#160;" );
12487 }
12488 },
12489
12490 _move: function( direction, event ) {
12491 var item, next,
12492 filter = ".ui-menu-item";
12493
12494 if ( this.isOpen ) {
12495 item = this.menuItems.eq( this.focusIndex );
12496 } else {
12497 item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
12498 filter += ":not(.ui-state-disabled)";
12499 }
12500
12501 if ( direction === "first" || direction === "last" ) {
12502 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
12503 } else {
12504 next = item[ direction + "All" ]( filter ).eq( 0 );
12505 }
12506
12507 if ( next.length ) {
12508 this.menuInstance.focus( event, next );
12509 }
12510 },
12511
12512 _getSelectedItem: function() {
12513 return this.menuItems.eq( this.element[ 0 ].selectedIndex );
12514 },
12515
12516 _toggle: function( event ) {
12517 this[ this.isOpen ? "close" : "open" ]( event );
12518 },
12519
12520 _setSelection: function() {
12521 var selection;
12522
12523 if ( !this.range ) {
12524 return;
12525 }
12526
12527 if ( window.getSelection ) {
12528 selection = window.getSelection();
12529 selection.removeAllRanges();
12530 selection.addRange( this.range );
12531
12532 // support: IE8
12533 } else {
12534 this.range.select();
12535 }
12536
12537 // support: IE
12538 // Setting the text selection kills the button focus in IE, but
12539 // restoring the focus doesn't kill the selection.
12540 this.button.focus();
12541 },
12542
12543 _documentClick: {
12544 mousedown: function( event ) {
12545 if ( !this.isOpen ) {
12546 return;
12547 }
12548
12549 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
12550 this.close( event );
12551 }
12552 }
12553 },
12554
12555 _buttonEvents: {
12556
12557 // Prevent text selection from being reset when interacting with the selectmenu (#10144)
12558 mousedown: function() {
12559 var selection;
12560
12561 if ( window.getSelection ) {
12562 selection = window.getSelection();
12563 if ( selection.rangeCount ) {
12564 this.range = selection.getRangeAt( 0 );
12565 }
12566
12567 // support: IE8
12568 } else {
12569 this.range = document.selection.createRange();
12570 }
12571 },
12572
12573 click: function( event ) {
12574 this._setSelection();
12575 this._toggle( event );
12576 },
12577
12578 keydown: function( event ) {
12579 var preventDefault = true;
12580 switch ( event.keyCode ) {
12581 case $.ui.keyCode.TAB:
12582 case $.ui.keyCode.ESCAPE:
12583 this.close( event );
12584 preventDefault = false;
12585 break;
12586 case $.ui.keyCode.ENTER:
12587 if ( this.isOpen ) {
12588 this._selectFocusedItem( event );
12589 }
12590 break;
12591 case $.ui.keyCode.UP:
12592 if ( event.altKey ) {
12593 this._toggle( event );
12594 } else {
12595 this._move( "prev", event );
12596 }
12597 break;
12598 case $.ui.keyCode.DOWN:
12599 if ( event.altKey ) {
12600 this._toggle( event );
12601 } else {
12602 this._move( "next", event );
12603 }
12604 break;
12605 case $.ui.keyCode.SPACE:
12606 if ( this.isOpen ) {
12607 this._selectFocusedItem( event );
12608 } else {
12609 this._toggle( event );
12610 }
12611 break;
12612 case $.ui.keyCode.LEFT:
12613 this._move( "prev", event );
12614 break;
12615 case $.ui.keyCode.RIGHT:
12616 this._move( "next", event );
12617 break;
12618 case $.ui.keyCode.HOME:
12619 case $.ui.keyCode.PAGE_UP:
12620 this._move( "first", event );
12621 break;
12622 case $.ui.keyCode.END:
12623 case $.ui.keyCode.PAGE_DOWN:
12624 this._move( "last", event );
12625 break;
12626 default:
12627 this.menu.trigger( event );
12628 preventDefault = false;
12629 }
12630
12631 if ( preventDefault ) {
12632 event.preventDefault();
12633 }
12634 }
12635 },
12636
12637 _selectFocusedItem: function( event ) {
12638 var item = this.menuItems.eq( this.focusIndex );
12639 if ( !item.hasClass( "ui-state-disabled" ) ) {
12640 this._select( item.data( "ui-selectmenu-item" ), event );
12641 }
12642 },
12643
12644 _select: function( item, event ) {
12645 var oldIndex = this.element[ 0 ].selectedIndex;
12646
12647 // Change native select element
12648 this.element[ 0 ].selectedIndex = item.index;
12649 this._setText( this.buttonText, item.label );
12650 this._setAria( item );
12651 this._trigger( "select", event, { item: item } );
12652
12653 if ( item.index !== oldIndex ) {
12654 this._trigger( "change", event, { item: item } );
12655 }
12656
12657 this.close( event );
12658 },
12659
12660 _setAria: function( item ) {
12661 var id = this.menuItems.eq( item.index ).attr( "id" );
12662
12663 this.button.attr({
12664 "aria-labelledby": id,
12665 "aria-activedescendant": id
12666 });
12667 this.menu.attr( "aria-activedescendant", id );
12668 },
12669
12670 _setOption: function( key, value ) {
12671 if ( key === "icons" ) {
12672 this.button.find( "span.ui-icon" )
12673 .removeClass( this.options.icons.button )
12674 .addClass( value.button );
12675 }
12676
12677 this._super( key, value );
12678
12679 if ( key === "appendTo" ) {
12680 this.menuWrap.appendTo( this._appendTo() );
12681 }
12682
12683 if ( key === "disabled" ) {
12684 this.menuInstance.option( "disabled", value );
12685 this.button
12686 .toggleClass( "ui-state-disabled", value )
12687 .attr( "aria-disabled", value );
12688
12689 this.element.prop( "disabled", value );
12690 if ( value ) {
12691 this.button.attr( "tabindex", -1 );
12692 this.close();
12693 } else {
12694 this.button.attr( "tabindex", 0 );
12695 }
12696 }
12697
12698 if ( key === "width" ) {
12699 this._resizeButton();
12700 }
12701 },
12702
12703 _appendTo: function() {
12704 var element = this.options.appendTo;
12705
12706 if ( element ) {
12707 element = element.jquery || element.nodeType ?
12708 $( element ) :
12709 this.document.find( element ).eq( 0 );
12710 }
12711
12712 if ( !element || !element[ 0 ] ) {
12713 element = this.element.closest( ".ui-front" );
12714 }
12715
12716 if ( !element.length ) {
12717 element = this.document[ 0 ].body;
12718 }
12719
12720 return element;
12721 },
12722
12723 _toggleAttr: function() {
12724 this.button
12725 .toggleClass( "ui-corner-top", this.isOpen )
12726 .toggleClass( "ui-corner-all", !this.isOpen )
12727 .attr( "aria-expanded", this.isOpen );
12728 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
12729 this.menu.attr( "aria-hidden", !this.isOpen );
12730 },
12731
12732 _resizeButton: function() {
12733 var width = this.options.width;
12734
12735 if ( !width ) {
12736 width = this.element.show().outerWidth();
12737 this.element.hide();
12738 }
12739
12740 this.button.outerWidth( width );
12741 },
12742
12743 _resizeMenu: function() {
12744 this.menu.outerWidth( Math.max(
12745 this.button.outerWidth(),
12746
12747 // support: IE10
12748 // IE10 wraps long text (possibly a rounding bug)
12749 // so we add 1px to avoid the wrapping
12750 this.menu.width( "" ).outerWidth() + 1
12751 ) );
12752 },
12753
12754 _getCreateOptions: function() {
12755 return { disabled: this.element.prop( "disabled" ) };
12756 },
12757
12758 _parseOptions: function( options ) {
12759 var data = [];
12760 options.each(function( index, item ) {
12761 var option = $( item ),
12762 optgroup = option.parent( "optgroup" );
12763 data.push({
12764 element: option,
12765 index: index,
12766 value: option.val(),
12767 label: option.text(),
12768 optgroup: optgroup.attr( "label" ) || "",
12769 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
12770 });
12771 });
12772 this.items = data;
12773 },
12774
12775 _destroy: function() {
12776 this.menuWrap.remove();
12777 this.button.remove();
12778 this.element.show();
12779 this.element.removeUniqueId();
12780 this.label.attr( "for", this.ids.element );
12781 }
12782 });
12783
12784
12785 /*!
12786 * jQuery UI Slider 1.11.4
12787 * http://jqueryui.com
12788 *
12789 * Copyright jQuery Foundation and other contributors
12790 * Released under the MIT license.
12791 * http://jquery.org/license
12792 *
12793 * http://api.jqueryui.com/slider/
12794 */
12795
12796
12797 var slider = $.widget( "ui.slider", $.ui.mouse, {
12798 version: "1.11.4",
12799 widgetEventPrefix: "slide",
12800
12801 options: {
12802 animate: false,
12803 distance: 0,
12804 max: 100,
12805 min: 0,
12806 orientation: "horizontal",
12807 range: false,
12808 step: 1,
12809 value: 0,
12810 values: null,
12811
12812 // callbacks
12813 change: null,
12814 slide: null,
12815 start: null,
12816 stop: null
12817 },
12818
12819 // number of pages in a slider
12820 // (how many times can you page up/down to go through the whole range)
12821 numPages: 5,
12822
12823 _create: function() {
12824 this._keySliding = false;
12825 this._mouseSliding = false;
12826 this._animateOff = true;
12827 this._handleIndex = null;
12828 this._detectOrientation();
12829 this._mouseInit();
12830 this._calculateNewMax();
12831
12832 this.element
12833 .addClass( "ui-slider" +
12834 " ui-slider-" + this.orientation +
12835 " ui-widget" +
12836 " ui-widget-content" +
12837 " ui-corner-all");
12838
12839 this._refresh();
12840 this._setOption( "disabled", this.options.disabled );
12841
12842 this._animateOff = false;
12843 },
12844
12845 _refresh: function() {
12846 this._createRange();
12847 this._createHandles();
12848 this._setupEvents();
12849 this._refreshValue();
12850 },
12851
12852 _createHandles: function() {
12853 var i, handleCount,
12854 options = this.options,
12855 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
12856 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
12857 handles = [];
12858
12859 handleCount = ( options.values && options.values.length ) || 1;
12860
12861 if ( existingHandles.length > handleCount ) {
12862 existingHandles.slice( handleCount ).remove();
12863 existingHandles = existingHandles.slice( 0, handleCount );
12864 }
12865
12866 for ( i = existingHandles.length; i < handleCount; i++ ) {
12867 handles.push( handle );
12868 }
12869
12870 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
12871
12872 this.handle = this.handles.eq( 0 );
12873
12874 this.handles.each(function( i ) {
12875 $( this ).data( "ui-slider-handle-index", i );
12876 });
12877 },
12878
12879 _createRange: function() {
12880 var options = this.options,
12881 classes = "";
12882
12883 if ( options.range ) {
12884 if ( options.range === true ) {
12885 if ( !options.values ) {
12886 options.values = [ this._valueMin(), this._valueMin() ];
12887 } else if ( options.values.length && options.values.length !== 2 ) {
12888 options.values = [ options.values[0], options.values[0] ];
12889 } else if ( $.isArray( options.values ) ) {
12890 options.values = options.values.slice(0);
12891 }
12892 }
12893
12894 if ( !this.range || !this.range.length ) {
12895 this.range = $( "<div></div>" )
12896 .appendTo( this.element );
12897
12898 classes = "ui-slider-range" +
12899 // note: this isn't the most fittingly semantic framework class for this element,
12900 // but worked best visually with a variety of themes
12901 " ui-widget-header ui-corner-all";
12902 } else {
12903 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
12904 // Handle range switching from true to min/max
12905 .css({
12906 "left": "",
12907 "bottom": ""
12908 });
12909 }
12910
12911 this.range.addClass( classes +
12912 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
12913 } else {
12914 if ( this.range ) {
12915 this.range.remove();
12916 }
12917 this.range = null;
12918 }
12919 },
12920
12921 _setupEvents: function() {
12922 this._off( this.handles );
12923 this._on( this.handles, this._handleEvents );
12924 this._hoverable( this.handles );
12925 this._focusable( this.handles );
12926 },
12927
12928 _destroy: function() {
12929 this.handles.remove();
12930 if ( this.range ) {
12931 this.range.remove();
12932 }
12933
12934 this.element
12935 .removeClass( "ui-slider" +
12936 " ui-slider-horizontal" +
12937 " ui-slider-vertical" +
12938 " ui-widget" +
12939 " ui-widget-content" +
12940 " ui-corner-all" );
12941
12942 this._mouseDestroy();
12943 },
12944
12945 _mouseCapture: function( event ) {
12946 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
12947 that = this,
12948 o = this.options;
12949
12950 if ( o.disabled ) {
12951 return false;
12952 }
12953
12954 this.elementSize = {
12955 width: this.element.outerWidth(),
12956 height: this.element.outerHeight()
12957 };
12958 this.elementOffset = this.element.offset();
12959
12960 position = { x: event.pageX, y: event.pageY };
12961 normValue = this._normValueFromMouse( position );
12962 distance = this._valueMax() - this._valueMin() + 1;
12963 this.handles.each(function( i ) {
12964 var thisDistance = Math.abs( normValue - that.values(i) );
12965 if (( distance > thisDistance ) ||
12966 ( distance === thisDistance &&
12967 (i === that._lastChangedValue || that.values(i) === o.min ))) {
12968 distance = thisDistance;
12969 closestHandle = $( this );
12970 index = i;
12971 }
12972 });
12973
12974 allowed = this._start( event, index );
12975 if ( allowed === false ) {
12976 return false;
12977 }
12978 this._mouseSliding = true;
12979
12980 this._handleIndex = index;
12981
12982 closestHandle
12983 .addClass( "ui-state-active" )
12984 .focus();
12985
12986 offset = closestHandle.offset();
12987 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
12988 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
12989 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
12990 top: event.pageY - offset.top -
12991 ( closestHandle.height() / 2 ) -
12992 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
12993 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
12994 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
12995 };
12996
12997 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
12998 this._slide( event, index, normValue );
12999 }
13000 this._animateOff = true;
13001 return true;
13002 },
13003
13004 _mouseStart: function() {
13005 return true;
13006 },
13007
13008 _mouseDrag: function( event ) {
13009 var position = { x: event.pageX, y: event.pageY },
13010 normValue = this._normValueFromMouse( position );
13011
13012 this._slide( event, this._handleIndex, normValue );
13013
13014 return false;
13015 },
13016
13017 _mouseStop: function( event ) {
13018 this.handles.removeClass( "ui-state-active" );
13019 this._mouseSliding = false;
13020
13021 this._stop( event, this._handleIndex );
13022 this._change( event, this._handleIndex );
13023
13024 this._handleIndex = null;
13025 this._clickOffset = null;
13026 this._animateOff = false;
13027
13028 return false;
13029 },
13030
13031 _detectOrientation: function() {
13032 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
13033 },
13034
13035 _normValueFromMouse: function( position ) {
13036 var pixelTotal,
13037 pixelMouse,
13038 percentMouse,
13039 valueTotal,
13040 valueMouse;
13041
13042 if ( this.orientation === "horizontal" ) {
13043 pixelTotal = this.elementSize.width;
13044 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
13045 } else {
13046 pixelTotal = this.elementSize.height;
13047 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
13048 }
13049
13050 percentMouse = ( pixelMouse / pixelTotal );
13051 if ( percentMouse > 1 ) {
13052 percentMouse = 1;
13053 }
13054 if ( percentMouse < 0 ) {
13055 percentMouse = 0;
13056 }
13057 if ( this.orientation === "vertical" ) {
13058 percentMouse = 1 - percentMouse;
13059 }
13060
13061 valueTotal = this._valueMax() - this._valueMin();
13062 valueMouse = this._valueMin() + percentMouse * valueTotal;
13063
13064 return this._trimAlignValue( valueMouse );
13065 },
13066
13067 _start: function( event, index ) {
13068 var uiHash = {
13069 handle: this.handles[ index ],
13070 value: this.value()
13071 };
13072 if ( this.options.values && this.options.values.length ) {
13073 uiHash.value = this.values( index );
13074 uiHash.values = this.values();
13075 }
13076 return this._trigger( "start", event, uiHash );
13077 },
13078
13079 _slide: function( event, index, newVal ) {
13080 var otherVal,
13081 newValues,
13082 allowed;
13083
13084 if ( this.options.values && this.options.values.length ) {
13085 otherVal = this.values( index ? 0 : 1 );
13086
13087 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
13088 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
13089 ) {
13090 newVal = otherVal;
13091 }
13092
13093 if ( newVal !== this.values( index ) ) {
13094 newValues = this.values();
13095 newValues[ index ] = newVal;
13096 // A slide can be canceled by returning false from the slide callback
13097 allowed = this._trigger( "slide", event, {
13098 handle: this.handles[ index ],
13099 value: newVal,
13100 values: newValues
13101 } );
13102 otherVal = this.values( index ? 0 : 1 );
13103 if ( allowed !== false ) {
13104 this.values( index, newVal );
13105 }
13106 }
13107 } else {
13108 if ( newVal !== this.value() ) {
13109 // A slide can be canceled by returning false from the slide callback
13110 allowed = this._trigger( "slide", event, {
13111 handle: this.handles[ index ],
13112 value: newVal
13113 } );
13114 if ( allowed !== false ) {
13115 this.value( newVal );
13116 }
13117 }
13118 }
13119 },
13120
13121 _stop: function( event, index ) {
13122 var uiHash = {
13123 handle: this.handles[ index ],
13124 value: this.value()
13125 };
13126 if ( this.options.values && this.options.values.length ) {
13127 uiHash.value = this.values( index );
13128 uiHash.values = this.values();
13129 }
13130
13131 this._trigger( "stop", event, uiHash );
13132 },
13133
13134 _change: function( event, index ) {
13135 if ( !this._keySliding && !this._mouseSliding ) {
13136 var uiHash = {
13137 handle: this.handles[ index ],
13138 value: this.value()
13139 };
13140 if ( this.options.values && this.options.values.length ) {
13141 uiHash.value = this.values( index );
13142 uiHash.values = this.values();
13143 }
13144
13145 //store the last changed value index for reference when handles overlap
13146 this._lastChangedValue = index;
13147
13148 this._trigger( "change", event, uiHash );
13149 }
13150 },
13151
13152 value: function( newValue ) {
13153 if ( arguments.length ) {
13154 this.options.value = this._trimAlignValue( newValue );
13155 this._refreshValue();
13156 this._change( null, 0 );
13157 return;
13158 }
13159
13160 return this._value();
13161 },
13162
13163 values: function( index, newValue ) {
13164 var vals,
13165 newValues,
13166 i;
13167
13168 if ( arguments.length > 1 ) {
13169 this.options.values[ index ] = this._trimAlignValue( newValue );
13170 this._refreshValue();
13171 this._change( null, index );
13172 return;
13173 }
13174
13175 if ( arguments.length ) {
13176 if ( $.isArray( arguments[ 0 ] ) ) {
13177 vals = this.options.values;
13178 newValues = arguments[ 0 ];
13179 for ( i = 0; i < vals.length; i += 1 ) {
13180 vals[ i ] = this._trimAlignValue( newValues[ i ] );
13181 this._change( null, i );
13182 }
13183 this._refreshValue();
13184 } else {
13185 if ( this.options.values && this.options.values.length ) {
13186 return this._values( index );
13187 } else {
13188 return this.value();
13189 }
13190 }
13191 } else {
13192 return this._values();
13193 }
13194 },
13195
13196 _setOption: function( key, value ) {
13197 var i,
13198 valsLength = 0;
13199
13200 if ( key === "range" && this.options.range === true ) {
13201 if ( value === "min" ) {
13202 this.options.value = this._values( 0 );
13203 this.options.values = null;
13204 } else if ( value === "max" ) {
13205 this.options.value = this._values( this.options.values.length - 1 );
13206 this.options.values = null;
13207 }
13208 }
13209
13210 if ( $.isArray( this.options.values ) ) {
13211 valsLength = this.options.values.length;
13212 }
13213
13214 if ( key === "disabled" ) {
13215 this.element.toggleClass( "ui-state-disabled", !!value );
13216 }
13217
13218 this._super( key, value );
13219
13220 switch ( key ) {
13221 case "orientation":
13222 this._detectOrientation();
13223 this.element
13224 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
13225 .addClass( "ui-slider-" + this.orientation );
13226 this._refreshValue();
13227
13228 // Reset positioning from previous orientation
13229 this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
13230 break;
13231 case "value":
13232 this._animateOff = true;
13233 this._refreshValue();
13234 this._change( null, 0 );
13235 this._animateOff = false;
13236 break;
13237 case "values":
13238 this._animateOff = true;
13239 this._refreshValue();
13240 for ( i = 0; i < valsLength; i += 1 ) {
13241 this._change( null, i );
13242 }
13243 this._animateOff = false;
13244 break;
13245 case "step":
13246 case "min":
13247 case "max":
13248 this._animateOff = true;
13249 this._calculateNewMax();
13250 this._refreshValue();
13251 this._animateOff = false;
13252 break;
13253 case "range":
13254 this._animateOff = true;
13255 this._refresh();
13256 this._animateOff = false;
13257 break;
13258 }
13259 },
13260
13261 //internal value getter
13262 // _value() returns value trimmed by min and max, aligned by step
13263 _value: function() {
13264 var val = this.options.value;
13265 val = this._trimAlignValue( val );
13266
13267 return val;
13268 },
13269
13270 //internal values getter
13271 // _values() returns array of values trimmed by min and max, aligned by step
13272 // _values( index ) returns single value trimmed by min and max, aligned by step
13273 _values: function( index ) {
13274 var val,
13275 vals,
13276 i;
13277
13278 if ( arguments.length ) {
13279 val = this.options.values[ index ];
13280 val = this._trimAlignValue( val );
13281
13282 return val;
13283 } else if ( this.options.values && this.options.values.length ) {
13284 // .slice() creates a copy of the array
13285 // this copy gets trimmed by min and max and then returned
13286 vals = this.options.values.slice();
13287 for ( i = 0; i < vals.length; i += 1) {
13288 vals[ i ] = this._trimAlignValue( vals[ i ] );
13289 }
13290
13291 return vals;
13292 } else {
13293 return [];
13294 }
13295 },
13296
13297 // returns the step-aligned value that val is closest to, between (inclusive) min and max
13298 _trimAlignValue: function( val ) {
13299 if ( val <= this._valueMin() ) {
13300 return this._valueMin();
13301 }
13302 if ( val >= this._valueMax() ) {
13303 return this._valueMax();
13304 }
13305 var step = ( this.options.step > 0 ) ? this.options.step : 1,
13306 valModStep = (val - this._valueMin()) % step,
13307 alignValue = val - valModStep;
13308
13309 if ( Math.abs(valModStep) * 2 >= step ) {
13310 alignValue += ( valModStep > 0 ) ? step : ( -step );
13311 }
13312
13313 // Since JavaScript has problems with large floats, round
13314 // the final value to 5 digits after the decimal point (see #4124)
13315 return parseFloat( alignValue.toFixed(5) );
13316 },
13317
13318 _calculateNewMax: function() {
13319 var max = this.options.max,
13320 min = this._valueMin(),
13321 step = this.options.step,
13322 aboveMin = Math.floor( ( +( max - min ).toFixed( this._precision() ) ) / step ) * step;
13323 max = aboveMin + min;
13324 this.max = parseFloat( max.toFixed( this._precision() ) );
13325 },
13326
13327 _precision: function() {
13328 var precision = this._precisionOf( this.options.step );
13329 if ( this.options.min !== null ) {
13330 precision = Math.max( precision, this._precisionOf( this.options.min ) );
13331 }
13332 return precision;
13333 },
13334
13335 _precisionOf: function( num ) {
13336 var str = num.toString(),
13337 decimal = str.indexOf( "." );
13338 return decimal === -1 ? 0 : str.length - decimal - 1;
13339 },
13340
13341 _valueMin: function() {
13342 return this.options.min;
13343 },
13344
13345 _valueMax: function() {
13346 return this.max;
13347 },
13348
13349 _refreshValue: function() {
13350 var lastValPercent, valPercent, value, valueMin, valueMax,
13351 oRange = this.options.range,
13352 o = this.options,
13353 that = this,
13354 animate = ( !this._animateOff ) ? o.animate : false,
13355 _set = {};
13356
13357 if ( this.options.values && this.options.values.length ) {
13358 this.handles.each(function( i ) {
13359 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
13360 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13361 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13362 if ( that.options.range === true ) {
13363 if ( that.orientation === "horizontal" ) {
13364 if ( i === 0 ) {
13365 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
13366 }
13367 if ( i === 1 ) {
13368 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13369 }
13370 } else {
13371 if ( i === 0 ) {
13372 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
13373 }
13374 if ( i === 1 ) {
13375 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
13376 }
13377 }
13378 }
13379 lastValPercent = valPercent;
13380 });
13381 } else {
13382 value = this.value();
13383 valueMin = this._valueMin();
13384 valueMax = this._valueMax();
13385 valPercent = ( valueMax !== valueMin ) ?
13386 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
13387 0;
13388 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
13389 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
13390
13391 if ( oRange === "min" && this.orientation === "horizontal" ) {
13392 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
13393 }
13394 if ( oRange === "max" && this.orientation === "horizontal" ) {
13395 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13396 }
13397 if ( oRange === "min" && this.orientation === "vertical" ) {
13398 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
13399 }
13400 if ( oRange === "max" && this.orientation === "vertical" ) {
13401 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
13402 }
13403 }
13404 },
13405
13406 _handleEvents: {
13407 keydown: function( event ) {
13408 var allowed, curVal, newVal, step,
13409 index = $( event.target ).data( "ui-slider-handle-index" );
13410
13411 switch ( event.keyCode ) {
13412 case $.ui.keyCode.HOME:
13413 case $.ui.keyCode.END:
13414 case $.ui.keyCode.PAGE_UP:
13415 case $.ui.keyCode.PAGE_DOWN:
13416 case $.ui.keyCode.UP:
13417 case $.ui.keyCode.RIGHT:
13418 case $.ui.keyCode.DOWN:
13419 case $.ui.keyCode.LEFT:
13420 event.preventDefault();
13421 if ( !this._keySliding ) {
13422 this._keySliding = true;
13423 $( event.target ).addClass( "ui-state-active" );
13424 allowed = this._start( event, index );
13425 if ( allowed === false ) {
13426 return;
13427 }
13428 }
13429 break;
13430 }
13431
13432 step = this.options.step;
13433 if ( this.options.values && this.options.values.length ) {
13434 curVal = newVal = this.values( index );
13435 } else {
13436 curVal = newVal = this.value();
13437 }
13438
13439 switch ( event.keyCode ) {
13440 case $.ui.keyCode.HOME:
13441 newVal = this._valueMin();
13442 break;
13443 case $.ui.keyCode.END:
13444 newVal = this._valueMax();
13445 break;
13446 case $.ui.keyCode.PAGE_UP:
13447 newVal = this._trimAlignValue(
13448 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
13449 );
13450 break;
13451 case $.ui.keyCode.PAGE_DOWN:
13452 newVal = this._trimAlignValue(
13453 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
13454 break;
13455 case $.ui.keyCode.UP:
13456 case $.ui.keyCode.RIGHT:
13457 if ( curVal === this._valueMax() ) {
13458 return;
13459 }
13460 newVal = this._trimAlignValue( curVal + step );
13461 break;
13462 case $.ui.keyCode.DOWN:
13463 case $.ui.keyCode.LEFT:
13464 if ( curVal === this._valueMin() ) {
13465 return;
13466 }
13467 newVal = this._trimAlignValue( curVal - step );
13468 break;
13469 }
13470
13471 this._slide( event, index, newVal );
13472 },
13473 keyup: function( event ) {
13474 var index = $( event.target ).data( "ui-slider-handle-index" );
13475
13476 if ( this._keySliding ) {
13477 this._keySliding = false;
13478 this._stop( event, index );
13479 this._change( event, index );
13480 $( event.target ).removeClass( "ui-state-active" );
13481 }
13482 }
13483 }
13484 });
13485
13486
13487 /*!
13488 * jQuery UI Sortable 1.11.4
13489 * http://jqueryui.com
13490 *
13491 * Copyright jQuery Foundation and other contributors
13492 * Released under the MIT license.
13493 * http://jquery.org/license
13494 *
13495 * http://api.jqueryui.com/sortable/
13496 */
13497
13498
13499 var sortable = $.widget("ui.sortable", $.ui.mouse, {
13500 version: "1.11.4",
13501 widgetEventPrefix: "sort",
13502 ready: false,
13503 options: {
13504 appendTo: "parent",
13505 axis: false,
13506 connectWith: false,
13507 containment: false,
13508 cursor: "auto",
13509 cursorAt: false,
13510 dropOnEmpty: true,
13511 forcePlaceholderSize: false,
13512 forceHelperSize: false,
13513 grid: false,
13514 handle: false,
13515 helper: "original",
13516 items: "> *",
13517 opacity: false,
13518 placeholder: false,
13519 revert: false,
13520 scroll: true,
13521 scrollSensitivity: 20,
13522 scrollSpeed: 20,
13523 scope: "default",
13524 tolerance: "intersect",
13525 zIndex: 1000,
13526
13527 // callbacks
13528 activate: null,
13529 beforeStop: null,
13530 change: null,
13531 deactivate: null,
13532 out: null,
13533 over: null,
13534 receive: null,
13535 remove: null,
13536 sort: null,
13537 start: null,
13538 stop: null,
13539 update: null
13540 },
13541
13542 _isOverAxis: function( x, reference, size ) {
13543 return ( x >= reference ) && ( x < ( reference + size ) );
13544 },
13545
13546 _isFloating: function( item ) {
13547 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
13548 },
13549
13550 _create: function() {
13551 this.containerCache = {};
13552 this.element.addClass("ui-sortable");
13553
13554 //Get the items
13555 this.refresh();
13556
13557 //Let's determine the parent's offset
13558 this.offset = this.element.offset();
13559
13560 //Initialize mouse events for interaction
13561 this._mouseInit();
13562
13563 this._setHandleClassName();
13564
13565 //We're ready to go
13566 this.ready = true;
13567
13568 },
13569
13570 _setOption: function( key, value ) {
13571 this._super( key, value );
13572
13573 if ( key === "handle" ) {
13574 this._setHandleClassName();
13575 }
13576 },
13577
13578 _setHandleClassName: function() {
13579 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
13580 $.each( this.items, function() {
13581 ( this.instance.options.handle ?
13582 this.item.find( this.instance.options.handle ) : this.item )
13583 .addClass( "ui-sortable-handle" );
13584 });
13585 },
13586
13587 _destroy: function() {
13588 this.element
13589 .removeClass( "ui-sortable ui-sortable-disabled" )
13590 .find( ".ui-sortable-handle" )
13591 .removeClass( "ui-sortable-handle" );
13592 this._mouseDestroy();
13593
13594 for ( var i = this.items.length - 1; i >= 0; i-- ) {
13595 this.items[i].item.removeData(this.widgetName + "-item");
13596 }
13597
13598 return this;
13599 },
13600
13601 _mouseCapture: function(event, overrideHandle) {
13602 var currentItem = null,
13603 validHandle = false,
13604 that = this;
13605
13606 if (this.reverting) {
13607 return false;
13608 }
13609
13610 if(this.options.disabled || this.options.type === "static") {
13611 return false;
13612 }
13613
13614 //We have to refresh the items data once first
13615 this._refreshItems(event);
13616
13617 //Find out if the clicked node (or one of its parents) is a actual item in this.items
13618 $(event.target).parents().each(function() {
13619 if($.data(this, that.widgetName + "-item") === that) {
13620 currentItem = $(this);
13621 return false;
13622 }
13623 });
13624 if($.data(event.target, that.widgetName + "-item") === that) {
13625 currentItem = $(event.target);
13626 }
13627
13628 if(!currentItem) {
13629 return false;
13630 }
13631 if(this.options.handle && !overrideHandle) {
13632 $(this.options.handle, currentItem).find("*").addBack().each(function() {
13633 if(this === event.target) {
13634 validHandle = true;
13635 }
13636 });
13637 if(!validHandle) {
13638 return false;
13639 }
13640 }
13641
13642 this.currentItem = currentItem;
13643 this._removeCurrentsFromItems();
13644 return true;
13645
13646 },
13647
13648 _mouseStart: function(event, overrideHandle, noActivation) {
13649
13650 var i, body,
13651 o = this.options;
13652
13653 this.currentContainer = this;
13654
13655 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
13656 this.refreshPositions();
13657
13658 //Create and append the visible helper
13659 this.helper = this._createHelper(event);
13660
13661 //Cache the helper size
13662 this._cacheHelperProportions();
13663
13664 /*
13665 * - Position generation -
13666 * This block generates everything position related - it's the core of draggables.
13667 */
13668
13669 //Cache the margins of the original element
13670 this._cacheMargins();
13671
13672 //Get the next scrolling parent
13673 this.scrollParent = this.helper.scrollParent();
13674
13675 //The element's absolute position on the page minus margins
13676 this.offset = this.currentItem.offset();
13677 this.offset = {
13678 top: this.offset.top - this.margins.top,
13679 left: this.offset.left - this.margins.left
13680 };
13681
13682 $.extend(this.offset, {
13683 click: { //Where the click happened, relative to the element
13684 left: event.pageX - this.offset.left,
13685 top: event.pageY - this.offset.top
13686 },
13687 parent: this._getParentOffset(),
13688 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
13689 });
13690
13691 // Only after we got the offset, we can change the helper's position to absolute
13692 // TODO: Still need to figure out a way to make relative sorting possible
13693 this.helper.css("position", "absolute");
13694 this.cssPosition = this.helper.css("position");
13695
13696 //Generate the original position
13697 this.originalPosition = this._generatePosition(event);
13698 this.originalPageX = event.pageX;
13699 this.originalPageY = event.pageY;
13700
13701 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
13702 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
13703
13704 //Cache the former DOM position
13705 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
13706
13707 //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
13708 if(this.helper[0] !== this.currentItem[0]) {
13709 this.currentItem.hide();
13710 }
13711
13712 //Create the placeholder
13713 this._createPlaceholder();
13714
13715 //Set a containment if given in the options
13716 if(o.containment) {
13717 this._setContainment();
13718 }
13719
13720 if( o.cursor && o.cursor !== "auto" ) { // cursor option
13721 body = this.document.find( "body" );
13722
13723 // support: IE
13724 this.storedCursor = body.css( "cursor" );
13725 body.css( "cursor", o.cursor );
13726
13727 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
13728 }
13729
13730 if(o.opacity) { // opacity option
13731 if (this.helper.css("opacity")) {
13732 this._storedOpacity = this.helper.css("opacity");
13733 }
13734 this.helper.css("opacity", o.opacity);
13735 }
13736
13737 if(o.zIndex) { // zIndex option
13738 if (this.helper.css("zIndex")) {
13739 this._storedZIndex = this.helper.css("zIndex");
13740 }
13741 this.helper.css("zIndex", o.zIndex);
13742 }
13743
13744 //Prepare scrolling
13745 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13746 this.overflowOffset = this.scrollParent.offset();
13747 }
13748
13749 //Call callbacks
13750 this._trigger("start", event, this._uiHash());
13751
13752 //Recache the helper size
13753 if(!this._preserveHelperProportions) {
13754 this._cacheHelperProportions();
13755 }
13756
13757
13758 //Post "activate" events to possible containers
13759 if( !noActivation ) {
13760 for ( i = this.containers.length - 1; i >= 0; i-- ) {
13761 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
13762 }
13763 }
13764
13765 //Prepare possible droppables
13766 if($.ui.ddmanager) {
13767 $.ui.ddmanager.current = this;
13768 }
13769
13770 if ($.ui.ddmanager && !o.dropBehaviour) {
13771 $.ui.ddmanager.prepareOffsets(this, event);
13772 }
13773
13774 this.dragging = true;
13775
13776 this.helper.addClass("ui-sortable-helper");
13777 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
13778 return true;
13779
13780 },
13781
13782 _mouseDrag: function(event) {
13783 var i, item, itemElement, intersection,
13784 o = this.options,
13785 scrolled = false;
13786
13787 //Compute the helpers position
13788 this.position = this._generatePosition(event);
13789 this.positionAbs = this._convertPositionTo("absolute");
13790
13791 if (!this.lastPositionAbs) {
13792 this.lastPositionAbs = this.positionAbs;
13793 }
13794
13795 //Do scrolling
13796 if(this.options.scroll) {
13797 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") {
13798
13799 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
13800 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
13801 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
13802 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
13803 }
13804
13805 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
13806 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
13807 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
13808 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
13809 }
13810
13811 } else {
13812
13813 if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) {
13814 scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed);
13815 } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) {
13816 scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed);
13817 }
13818
13819 if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) {
13820 scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed);
13821 } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) {
13822 scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed);
13823 }
13824
13825 }
13826
13827 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
13828 $.ui.ddmanager.prepareOffsets(this, event);
13829 }
13830 }
13831
13832 //Regenerate the absolute position used for position checks
13833 this.positionAbs = this._convertPositionTo("absolute");
13834
13835 //Set the helper position
13836 if(!this.options.axis || this.options.axis !== "y") {
13837 this.helper[0].style.left = this.position.left+"px";
13838 }
13839 if(!this.options.axis || this.options.axis !== "x") {
13840 this.helper[0].style.top = this.position.top+"px";
13841 }
13842
13843 //Rearrange
13844 for (i = this.items.length - 1; i >= 0; i--) {
13845
13846 //Cache variables and intersection, continue if no intersection
13847 item = this.items[i];
13848 itemElement = item.item[0];
13849 intersection = this._intersectsWithPointer(item);
13850 if (!intersection) {
13851 continue;
13852 }
13853
13854 // Only put the placeholder inside the current Container, skip all
13855 // items from other containers. This works because when moving
13856 // an item from one container to another the
13857 // currentContainer is switched before the placeholder is moved.
13858 //
13859 // Without this, moving items in "sub-sortables" can cause
13860 // the placeholder to jitter between the outer and inner container.
13861 if (item.instance !== this.currentContainer) {
13862 continue;
13863 }
13864
13865 // cannot intersect with itself
13866 // no useless actions that have been done before
13867 // no action if the item moved is the parent of the item checked
13868 if (itemElement !== this.currentItem[0] &&
13869 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
13870 !$.contains(this.placeholder[0], itemElement) &&
13871 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
13872 ) {
13873
13874 this.direction = intersection === 1 ? "down" : "up";
13875
13876 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
13877 this._rearrange(event, item);
13878 } else {
13879 break;
13880 }
13881
13882 this._trigger("change", event, this._uiHash());
13883 break;
13884 }
13885 }
13886
13887 //Post events to containers
13888 this._contactContainers(event);
13889
13890 //Interconnect with droppables
13891 if($.ui.ddmanager) {
13892 $.ui.ddmanager.drag(this, event);
13893 }
13894
13895 //Call callbacks
13896 this._trigger("sort", event, this._uiHash());
13897
13898 this.lastPositionAbs = this.positionAbs;
13899 return false;
13900
13901 },
13902
13903 _mouseStop: function(event, noPropagation) {
13904
13905 if(!event) {
13906 return;
13907 }
13908
13909 //If we are using droppables, inform the manager about the drop
13910 if ($.ui.ddmanager && !this.options.dropBehaviour) {
13911 $.ui.ddmanager.drop(this, event);
13912 }
13913
13914 if(this.options.revert) {
13915 var that = this,
13916 cur = this.placeholder.offset(),
13917 axis = this.options.axis,
13918 animation = {};
13919
13920 if ( !axis || axis === "x" ) {
13921 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft);
13922 }
13923 if ( !axis || axis === "y" ) {
13924 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop);
13925 }
13926 this.reverting = true;
13927 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
13928 that._clear(event);
13929 });
13930 } else {
13931 this._clear(event, noPropagation);
13932 }
13933
13934 return false;
13935
13936 },
13937
13938 cancel: function() {
13939
13940 if(this.dragging) {
13941
13942 this._mouseUp({ target: null });
13943
13944 if(this.options.helper === "original") {
13945 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
13946 } else {
13947 this.currentItem.show();
13948 }
13949
13950 //Post deactivating events to containers
13951 for (var i = this.containers.length - 1; i >= 0; i--){
13952 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
13953 if(this.containers[i].containerCache.over) {
13954 this.containers[i]._trigger("out", null, this._uiHash(this));
13955 this.containers[i].containerCache.over = 0;
13956 }
13957 }
13958
13959 }
13960
13961 if (this.placeholder) {
13962 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
13963 if(this.placeholder[0].parentNode) {
13964 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
13965 }
13966 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
13967 this.helper.remove();
13968 }
13969
13970 $.extend(this, {
13971 helper: null,
13972 dragging: false,
13973 reverting: false,
13974 _noFinalSort: null
13975 });
13976
13977 if(this.domPosition.prev) {
13978 $(this.domPosition.prev).after(this.currentItem);
13979 } else {
13980 $(this.domPosition.parent).prepend(this.currentItem);
13981 }
13982 }
13983
13984 return this;
13985
13986 },
13987
13988 serialize: function(o) {
13989
13990 var items = this._getItemsAsjQuery(o && o.connected),
13991 str = [];
13992 o = o || {};
13993
13994 $(items).each(function() {
13995 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
13996 if (res) {
13997 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
13998 }
13999 });
14000
14001 if(!str.length && o.key) {
14002 str.push(o.key + "=");
14003 }
14004
14005 return str.join("&");
14006
14007 },
14008
14009 toArray: function(o) {
14010
14011 var items = this._getItemsAsjQuery(o && o.connected),
14012 ret = [];
14013
14014 o = o || {};
14015
14016 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
14017 return ret;
14018
14019 },
14020
14021 /* Be careful with the following core functions */
14022 _intersectsWith: function(item) {
14023
14024 var x1 = this.positionAbs.left,
14025 x2 = x1 + this.helperProportions.width,
14026 y1 = this.positionAbs.top,
14027 y2 = y1 + this.helperProportions.height,
14028 l = item.left,
14029 r = l + item.width,
14030 t = item.top,
14031 b = t + item.height,
14032 dyClick = this.offset.click.top,
14033 dxClick = this.offset.click.left,
14034 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
14035 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
14036 isOverElement = isOverElementHeight && isOverElementWidth;
14037
14038 if ( this.options.tolerance === "pointer" ||
14039 this.options.forcePointerForContainers ||
14040 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
14041 ) {
14042 return isOverElement;
14043 } else {
14044
14045 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
14046 x2 - (this.helperProportions.width / 2) < r && // Left Half
14047 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
14048 y2 - (this.helperProportions.height / 2) < b ); // Top Half
14049
14050 }
14051 },
14052
14053 _intersectsWithPointer: function(item) {
14054
14055 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
14056 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
14057 isOverElement = isOverElementHeight && isOverElementWidth,
14058 verticalDirection = this._getDragVerticalDirection(),
14059 horizontalDirection = this._getDragHorizontalDirection();
14060
14061 if (!isOverElement) {
14062 return false;
14063 }
14064
14065 return this.floating ?
14066 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
14067 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
14068
14069 },
14070
14071 _intersectsWithSides: function(item) {
14072
14073 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
14074 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
14075 verticalDirection = this._getDragVerticalDirection(),
14076 horizontalDirection = this._getDragHorizontalDirection();
14077
14078 if (this.floating && horizontalDirection) {
14079 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
14080 } else {
14081 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
14082 }
14083
14084 },
14085
14086 _getDragVerticalDirection: function() {
14087 var delta = this.positionAbs.top - this.lastPositionAbs.top;
14088 return delta !== 0 && (delta > 0 ? "down" : "up");
14089 },
14090
14091 _getDragHorizontalDirection: function() {
14092 var delta = this.positionAbs.left - this.lastPositionAbs.left;
14093 return delta !== 0 && (delta > 0 ? "right" : "left");
14094 },
14095
14096 refresh: function(event) {
14097 this._refreshItems(event);
14098 this._setHandleClassName();
14099 this.refreshPositions();
14100 return this;
14101 },
14102
14103 _connectWith: function() {
14104 var options = this.options;
14105 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
14106 },
14107
14108 _getItemsAsjQuery: function(connected) {
14109
14110 var i, j, cur, inst,
14111 items = [],
14112 queries = [],
14113 connectWith = this._connectWith();
14114
14115 if(connectWith && connected) {
14116 for (i = connectWith.length - 1; i >= 0; i--){
14117 cur = $(connectWith[i], this.document[0]);
14118 for ( j = cur.length - 1; j >= 0; j--){
14119 inst = $.data(cur[j], this.widgetFullName);
14120 if(inst && inst !== this && !inst.options.disabled) {
14121 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
14122 }
14123 }
14124 }
14125 }
14126
14127 queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
14128
14129 function addItems() {
14130 items.push( this );
14131 }
14132 for (i = queries.length - 1; i >= 0; i--){
14133 queries[i][0].each( addItems );
14134 }
14135
14136 return $(items);
14137
14138 },
14139
14140 _removeCurrentsFromItems: function() {
14141
14142 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
14143
14144 this.items = $.grep(this.items, function (item) {
14145 for (var j=0; j < list.length; j++) {
14146 if(list[j] === item.item[0]) {
14147 return false;
14148 }
14149 }
14150 return true;
14151 });
14152
14153 },
14154
14155 _refreshItems: function(event) {
14156
14157 this.items = [];
14158 this.containers = [this];
14159
14160 var i, j, cur, inst, targetData, _queries, item, queriesLength,
14161 items = this.items,
14162 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
14163 connectWith = this._connectWith();
14164
14165 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
14166 for (i = connectWith.length - 1; i >= 0; i--){
14167 cur = $(connectWith[i], this.document[0]);
14168 for (j = cur.length - 1; j >= 0; j--){
14169 inst = $.data(cur[j], this.widgetFullName);
14170 if(inst && inst !== this && !inst.options.disabled) {
14171 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
14172 this.containers.push(inst);
14173 }
14174 }
14175 }
14176 }
14177
14178 for (i = queries.length - 1; i >= 0; i--) {
14179 targetData = queries[i][1];
14180 _queries = queries[i][0];
14181
14182 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
14183 item = $(_queries[j]);
14184
14185 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
14186
14187 items.push({
14188 item: item,
14189 instance: targetData,
14190 width: 0, height: 0,
14191 left: 0, top: 0
14192 });
14193 }
14194 }
14195
14196 },
14197
14198 refreshPositions: function(fast) {
14199
14200 // Determine whether items are being displayed horizontally
14201 this.floating = this.items.length ?
14202 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
14203 false;
14204
14205 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
14206 if(this.offsetParent && this.helper) {
14207 this.offset.parent = this._getParentOffset();
14208 }
14209
14210 var i, item, t, p;
14211
14212 for (i = this.items.length - 1; i >= 0; i--){
14213 item = this.items[i];
14214
14215 //We ignore calculating positions of all connected containers when we're not over them
14216 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
14217 continue;
14218 }
14219
14220 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
14221
14222 if (!fast) {
14223 item.width = t.outerWidth();
14224 item.height = t.outerHeight();
14225 }
14226
14227 p = t.offset();
14228 item.left = p.left;
14229 item.top = p.top;
14230 }
14231
14232 if(this.options.custom && this.options.custom.refreshContainers) {
14233 this.options.custom.refreshContainers.call(this);
14234 } else {
14235 for (i = this.containers.length - 1; i >= 0; i--){
14236 p = this.containers[i].element.offset();
14237 this.containers[i].containerCache.left = p.left;
14238 this.containers[i].containerCache.top = p.top;
14239 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
14240 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
14241 }
14242 }
14243
14244 return this;
14245 },
14246
14247 _createPlaceholder: function(that) {
14248 that = that || this;
14249 var className,
14250 o = that.options;
14251
14252 if(!o.placeholder || o.placeholder.constructor === String) {
14253 className = o.placeholder;
14254 o.placeholder = {
14255 element: function() {
14256
14257 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
14258 element = $( "<" + nodeName + ">", that.document[0] )
14259 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
14260 .removeClass("ui-sortable-helper");
14261
14262 if ( nodeName === "tbody" ) {
14263 that._createTrPlaceholder(
14264 that.currentItem.find( "tr" ).eq( 0 ),
14265 $( "<tr>", that.document[ 0 ] ).appendTo( element )
14266 );
14267 } else if ( nodeName === "tr" ) {
14268 that._createTrPlaceholder( that.currentItem, element );
14269 } else if ( nodeName === "img" ) {
14270 element.attr( "src", that.currentItem.attr( "src" ) );
14271 }
14272
14273 if ( !className ) {
14274 element.css( "visibility", "hidden" );
14275 }
14276
14277 return element;
14278 },
14279 update: function(container, p) {
14280
14281 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
14282 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
14283 if(className && !o.forcePlaceholderSize) {
14284 return;
14285 }
14286
14287 //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
14288 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
14289 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
14290 }
14291 };
14292 }
14293
14294 //Create the placeholder
14295 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
14296
14297 //Append it after the actual current item
14298 that.currentItem.after(that.placeholder);
14299
14300 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
14301 o.placeholder.update(that, that.placeholder);
14302
14303 },
14304
14305 _createTrPlaceholder: function( sourceTr, targetTr ) {
14306 var that = this;
14307
14308 sourceTr.children().each(function() {
14309 $( "<td>&#160;</td>", that.document[ 0 ] )
14310 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
14311 .appendTo( targetTr );
14312 });
14313 },
14314
14315 _contactContainers: function(event) {
14316 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
14317 innermostContainer = null,
14318 innermostIndex = null;
14319
14320 // get innermost container that intersects with item
14321 for (i = this.containers.length - 1; i >= 0; i--) {
14322
14323 // never consider a container that's located within the item itself
14324 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
14325 continue;
14326 }
14327
14328 if(this._intersectsWith(this.containers[i].containerCache)) {
14329
14330 // if we've already found a container and it's more "inner" than this, then continue
14331 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
14332 continue;
14333 }
14334
14335 innermostContainer = this.containers[i];
14336 innermostIndex = i;
14337
14338 } else {
14339 // container doesn't intersect. trigger "out" event if necessary
14340 if(this.containers[i].containerCache.over) {
14341 this.containers[i]._trigger("out", event, this._uiHash(this));
14342 this.containers[i].containerCache.over = 0;
14343 }
14344 }
14345
14346 }
14347
14348 // if no intersecting containers found, return
14349 if(!innermostContainer) {
14350 return;
14351 }
14352
14353 // move the item into the container if it's not there already
14354 if(this.containers.length === 1) {
14355 if (!this.containers[innermostIndex].containerCache.over) {
14356 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14357 this.containers[innermostIndex].containerCache.over = 1;
14358 }
14359 } else {
14360
14361 //When entering a new container, we will find the item with the least distance and append our item near it
14362 dist = 10000;
14363 itemWithLeastDistance = null;
14364 floating = innermostContainer.floating || this._isFloating(this.currentItem);
14365 posProperty = floating ? "left" : "top";
14366 sizeProperty = floating ? "width" : "height";
14367 axis = floating ? "clientX" : "clientY";
14368
14369 for (j = this.items.length - 1; j >= 0; j--) {
14370 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
14371 continue;
14372 }
14373 if(this.items[j].item[0] === this.currentItem[0]) {
14374 continue;
14375 }
14376
14377 cur = this.items[j].item.offset()[posProperty];
14378 nearBottom = false;
14379 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
14380 nearBottom = true;
14381 }
14382
14383 if ( Math.abs( event[ axis ] - cur ) < dist ) {
14384 dist = Math.abs( event[ axis ] - cur );
14385 itemWithLeastDistance = this.items[ j ];
14386 this.direction = nearBottom ? "up": "down";
14387 }
14388 }
14389
14390 //Check if dropOnEmpty is enabled
14391 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
14392 return;
14393 }
14394
14395 if(this.currentContainer === this.containers[innermostIndex]) {
14396 if ( !this.currentContainer.containerCache.over ) {
14397 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
14398 this.currentContainer.containerCache.over = 1;
14399 }
14400 return;
14401 }
14402
14403 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
14404 this._trigger("change", event, this._uiHash());
14405 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
14406 this.currentContainer = this.containers[innermostIndex];
14407
14408 //Update the placeholder
14409 this.options.placeholder.update(this.currentContainer, this.placeholder);
14410
14411 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
14412 this.containers[innermostIndex].containerCache.over = 1;
14413 }
14414
14415
14416 },
14417
14418 _createHelper: function(event) {
14419
14420 var o = this.options,
14421 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
14422
14423 //Add the helper to the DOM if that didn't happen already
14424 if(!helper.parents("body").length) {
14425 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
14426 }
14427
14428 if(helper[0] === this.currentItem[0]) {
14429 this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
14430 }
14431
14432 if(!helper[0].style.width || o.forceHelperSize) {
14433 helper.width(this.currentItem.width());
14434 }
14435 if(!helper[0].style.height || o.forceHelperSize) {
14436 helper.height(this.currentItem.height());
14437 }
14438
14439 return helper;
14440
14441 },
14442
14443 _adjustOffsetFromHelper: function(obj) {
14444 if (typeof obj === "string") {
14445 obj = obj.split(" ");
14446 }
14447 if ($.isArray(obj)) {
14448 obj = {left: +obj[0], top: +obj[1] || 0};
14449 }
14450 if ("left" in obj) {
14451 this.offset.click.left = obj.left + this.margins.left;
14452 }
14453 if ("right" in obj) {
14454 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
14455 }
14456 if ("top" in obj) {
14457 this.offset.click.top = obj.top + this.margins.top;
14458 }
14459 if ("bottom" in obj) {
14460 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
14461 }
14462 },
14463
14464 _getParentOffset: function() {
14465
14466
14467 //Get the offsetParent and cache its position
14468 this.offsetParent = this.helper.offsetParent();
14469 var po = this.offsetParent.offset();
14470
14471 // This is a special case where we need to modify a offset calculated on start, since the following happened:
14472 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
14473 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
14474 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
14475 if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) {
14476 po.left += this.scrollParent.scrollLeft();
14477 po.top += this.scrollParent.scrollTop();
14478 }
14479
14480 // This needs to be actually done for all browsers, since pageX/pageY includes this information
14481 // with an ugly IE fix
14482 if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
14483 po = { top: 0, left: 0 };
14484 }
14485
14486 return {
14487 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
14488 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
14489 };
14490
14491 },
14492
14493 _getRelativeOffset: function() {
14494
14495 if(this.cssPosition === "relative") {
14496 var p = this.currentItem.position();
14497 return {
14498 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
14499 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
14500 };
14501 } else {
14502 return { top: 0, left: 0 };
14503 }
14504
14505 },
14506
14507 _cacheMargins: function() {
14508 this.margins = {
14509 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
14510 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
14511 };
14512 },
14513
14514 _cacheHelperProportions: function() {
14515 this.helperProportions = {
14516 width: this.helper.outerWidth(),
14517 height: this.helper.outerHeight()
14518 };
14519 },
14520
14521 _setContainment: function() {
14522
14523 var ce, co, over,
14524 o = this.options;
14525 if(o.containment === "parent") {
14526 o.containment = this.helper[0].parentNode;
14527 }
14528 if(o.containment === "document" || o.containment === "window") {
14529 this.containment = [
14530 0 - this.offset.relative.left - this.offset.parent.left,
14531 0 - this.offset.relative.top - this.offset.parent.top,
14532 o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left,
14533 (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
14534 ];
14535 }
14536
14537 if(!(/^(document|window|parent)$/).test(o.containment)) {
14538 ce = $(o.containment)[0];
14539 co = $(o.containment).offset();
14540 over = ($(ce).css("overflow") !== "hidden");
14541
14542 this.containment = [
14543 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
14544 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
14545 co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
14546 co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
14547 ];
14548 }
14549
14550 },
14551
14552 _convertPositionTo: function(d, pos) {
14553
14554 if(!pos) {
14555 pos = this.position;
14556 }
14557 var mod = d === "absolute" ? 1 : -1,
14558 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
14559 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
14560
14561 return {
14562 top: (
14563 pos.top + // The absolute mouse position
14564 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14565 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
14566 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
14567 ),
14568 left: (
14569 pos.left + // The absolute mouse position
14570 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
14571 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
14572 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
14573 )
14574 };
14575
14576 },
14577
14578 _generatePosition: function(event) {
14579
14580 var top, left,
14581 o = this.options,
14582 pageX = event.pageX,
14583 pageY = event.pageY,
14584 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
14585
14586 // This is another very weird special case that only happens for relative elements:
14587 // 1. If the css position is relative
14588 // 2. and the scroll parent is the document or similar to the offset parent
14589 // we have to refresh the relative offset during the scroll so there are no jumps
14590 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) {
14591 this.offset.relative = this._getRelativeOffset();
14592 }
14593
14594 /*
14595 * - Position constraining -
14596 * Constrain the position to a mix of grid, containment.
14597 */
14598
14599 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
14600
14601 if(this.containment) {
14602 if(event.pageX - this.offset.click.left < this.containment[0]) {
14603 pageX = this.containment[0] + this.offset.click.left;
14604 }
14605 if(event.pageY - this.offset.click.top < this.containment[1]) {
14606 pageY = this.containment[1] + this.offset.click.top;
14607 }
14608 if(event.pageX - this.offset.click.left > this.containment[2]) {
14609 pageX = this.containment[2] + this.offset.click.left;
14610 }
14611 if(event.pageY - this.offset.click.top > this.containment[3]) {
14612 pageY = this.containment[3] + this.offset.click.top;
14613 }
14614 }
14615
14616 if(o.grid) {
14617 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
14618 pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
14619
14620 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
14621 pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
14622 }
14623
14624 }
14625
14626 return {
14627 top: (
14628 pageY - // The absolute mouse position
14629 this.offset.click.top - // Click offset (relative to the element)
14630 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
14631 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
14632 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
14633 ),
14634 left: (
14635 pageX - // The absolute mouse position
14636 this.offset.click.left - // Click offset (relative to the element)
14637 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
14638 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
14639 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
14640 )
14641 };
14642
14643 },
14644
14645 _rearrange: function(event, i, a, hardRefresh) {
14646
14647 a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
14648
14649 //Various things done here to improve the performance:
14650 // 1. we create a setTimeout, that calls refreshPositions
14651 // 2. on the instance, we have a counter variable, that get's higher after every append
14652 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
14653 // 4. this lets only the last addition to the timeout stack through
14654 this.counter = this.counter ? ++this.counter : 1;
14655 var counter = this.counter;
14656
14657 this._delay(function() {
14658 if(counter === this.counter) {
14659 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
14660 }
14661 });
14662
14663 },
14664
14665 _clear: function(event, noPropagation) {
14666
14667 this.reverting = false;
14668 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
14669 // everything else normalized again
14670 var i,
14671 delayedTriggers = [];
14672
14673 // We first have to update the dom position of the actual currentItem
14674 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
14675 if(!this._noFinalSort && this.currentItem.parent().length) {
14676 this.placeholder.before(this.currentItem);
14677 }
14678 this._noFinalSort = null;
14679
14680 if(this.helper[0] === this.currentItem[0]) {
14681 for(i in this._storedCSS) {
14682 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
14683 this._storedCSS[i] = "";
14684 }
14685 }
14686 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
14687 } else {
14688 this.currentItem.show();
14689 }
14690
14691 if(this.fromOutside && !noPropagation) {
14692 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
14693 }
14694 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
14695 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
14696 }
14697
14698 // Check if the items Container has Changed and trigger appropriate
14699 // events.
14700 if (this !== this.currentContainer) {
14701 if(!noPropagation) {
14702 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
14703 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14704 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
14705 }
14706 }
14707
14708
14709 //Post events to containers
14710 function delayEvent( type, instance, container ) {
14711 return function( event ) {
14712 container._trigger( type, event, instance._uiHash( instance ) );
14713 };
14714 }
14715 for (i = this.containers.length - 1; i >= 0; i--){
14716 if (!noPropagation) {
14717 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
14718 }
14719 if(this.containers[i].containerCache.over) {
14720 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
14721 this.containers[i].containerCache.over = 0;
14722 }
14723 }
14724
14725 //Do what was originally in plugins
14726 if ( this.storedCursor ) {
14727 this.document.find( "body" ).css( "cursor", this.storedCursor );
14728 this.storedStylesheet.remove();
14729 }
14730 if(this._storedOpacity) {
14731 this.helper.css("opacity", this._storedOpacity);
14732 }
14733 if(this._storedZIndex) {
14734 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
14735 }
14736
14737 this.dragging = false;
14738
14739 if(!noPropagation) {
14740 this._trigger("beforeStop", event, this._uiHash());
14741 }
14742
14743 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
14744 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
14745
14746 if ( !this.cancelHelperRemoval ) {
14747 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
14748 this.helper.remove();
14749 }
14750 this.helper = null;
14751 }
14752
14753 if(!noPropagation) {
14754 for (i=0; i < delayedTriggers.length; i++) {
14755 delayedTriggers[i].call(this, event);
14756 } //Trigger all delayed events
14757 this._trigger("stop", event, this._uiHash());
14758 }
14759
14760 this.fromOutside = false;
14761 return !this.cancelHelperRemoval;
14762
14763 },
14764
14765 _trigger: function() {
14766 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
14767 this.cancel();
14768 }
14769 },
14770
14771 _uiHash: function(_inst) {
14772 var inst = _inst || this;
14773 return {
14774 helper: inst.helper,
14775 placeholder: inst.placeholder || $([]),
14776 position: inst.position,
14777 originalPosition: inst.originalPosition,
14778 offset: inst.positionAbs,
14779 item: inst.currentItem,
14780 sender: _inst ? _inst.element : null
14781 };
14782 }
14783
14784 });
14785
14786
14787 /*!
14788 * jQuery UI Spinner 1.11.4
14789 * http://jqueryui.com
14790 *
14791 * Copyright jQuery Foundation and other contributors
14792 * Released under the MIT license.
14793 * http://jquery.org/license
14794 *
14795 * http://api.jqueryui.com/spinner/
14796 */
14797
14798
14799 function spinner_modifier( fn ) {
14800 return function() {
14801 var previous = this.element.val();
14802 fn.apply( this, arguments );
14803 this._refresh();
14804 if ( previous !== this.element.val() ) {
14805 this._trigger( "change" );
14806 }
14807 };
14808 }
14809
14810 var spinner = $.widget( "ui.spinner", {
14811 version: "1.11.4",
14812 defaultElement: "<input>",
14813 widgetEventPrefix: "spin",
14814 options: {
14815 culture: null,
14816 icons: {
14817 down: "ui-icon-triangle-1-s",
14818 up: "ui-icon-triangle-1-n"
14819 },
14820 incremental: true,
14821 max: null,
14822 min: null,
14823 numberFormat: null,
14824 page: 10,
14825 step: 1,
14826
14827 change: null,
14828 spin: null,
14829 start: null,
14830 stop: null
14831 },
14832
14833 _create: function() {
14834 // handle string values that need to be parsed
14835 this._setOption( "max", this.options.max );
14836 this._setOption( "min", this.options.min );
14837 this._setOption( "step", this.options.step );
14838
14839 // Only format if there is a value, prevents the field from being marked
14840 // as invalid in Firefox, see #9573.
14841 if ( this.value() !== "" ) {
14842 // Format the value, but don't constrain.
14843 this._value( this.element.val(), true );
14844 }
14845
14846 this._draw();
14847 this._on( this._events );
14848 this._refresh();
14849
14850 // turning off autocomplete prevents the browser from remembering the
14851 // value when navigating through history, so we re-enable autocomplete
14852 // if the page is unloaded before the widget is destroyed. #7790
14853 this._on( this.window, {
14854 beforeunload: function() {
14855 this.element.removeAttr( "autocomplete" );
14856 }
14857 });
14858 },
14859
14860 _getCreateOptions: function() {
14861 var options = {},
14862 element = this.element;
14863
14864 $.each( [ "min", "max", "step" ], function( i, option ) {
14865 var value = element.attr( option );
14866 if ( value !== undefined && value.length ) {
14867 options[ option ] = value;
14868 }
14869 });
14870
14871 return options;
14872 },
14873
14874 _events: {
14875 keydown: function( event ) {
14876 if ( this._start( event ) && this._keydown( event ) ) {
14877 event.preventDefault();
14878 }
14879 },
14880 keyup: "_stop",
14881 focus: function() {
14882 this.previous = this.element.val();
14883 },
14884 blur: function( event ) {
14885 if ( this.cancelBlur ) {
14886 delete this.cancelBlur;
14887 return;
14888 }
14889
14890 this._stop();
14891 this._refresh();
14892 if ( this.previous !== this.element.val() ) {
14893 this._trigger( "change", event );
14894 }
14895 },
14896 mousewheel: function( event, delta ) {
14897 if ( !delta ) {
14898 return;
14899 }
14900 if ( !this.spinning && !this._start( event ) ) {
14901 return false;
14902 }
14903
14904 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
14905 clearTimeout( this.mousewheelTimer );
14906 this.mousewheelTimer = this._delay(function() {
14907 if ( this.spinning ) {
14908 this._stop( event );
14909 }
14910 }, 100 );
14911 event.preventDefault();
14912 },
14913 "mousedown .ui-spinner-button": function( event ) {
14914 var previous;
14915
14916 // We never want the buttons to have focus; whenever the user is
14917 // interacting with the spinner, the focus should be on the input.
14918 // If the input is focused then this.previous is properly set from
14919 // when the input first received focus. If the input is not focused
14920 // then we need to set this.previous based on the value before spinning.
14921 previous = this.element[0] === this.document[0].activeElement ?
14922 this.previous : this.element.val();
14923 function checkFocus() {
14924 var isActive = this.element[0] === this.document[0].activeElement;
14925 if ( !isActive ) {
14926 this.element.focus();
14927 this.previous = previous;
14928 // support: IE
14929 // IE sets focus asynchronously, so we need to check if focus
14930 // moved off of the input because the user clicked on the button.
14931 this._delay(function() {
14932 this.previous = previous;
14933 });
14934 }
14935 }
14936
14937 // ensure focus is on (or stays on) the text field
14938 event.preventDefault();
14939 checkFocus.call( this );
14940
14941 // support: IE
14942 // IE doesn't prevent moving focus even with event.preventDefault()
14943 // so we set a flag to know when we should ignore the blur event
14944 // and check (again) if focus moved off of the input.
14945 this.cancelBlur = true;
14946 this._delay(function() {
14947 delete this.cancelBlur;
14948 checkFocus.call( this );
14949 });
14950
14951 if ( this._start( event ) === false ) {
14952 return;
14953 }
14954
14955 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14956 },
14957 "mouseup .ui-spinner-button": "_stop",
14958 "mouseenter .ui-spinner-button": function( event ) {
14959 // button will add ui-state-active if mouse was down while mouseleave and kept down
14960 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
14961 return;
14962 }
14963
14964 if ( this._start( event ) === false ) {
14965 return false;
14966 }
14967 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14968 },
14969 // TODO: do we really want to consider this a stop?
14970 // shouldn't we just stop the repeater and wait until mouseup before
14971 // we trigger the stop event?
14972 "mouseleave .ui-spinner-button": "_stop"
14973 },
14974
14975 _draw: function() {
14976 var uiSpinner = this.uiSpinner = this.element
14977 .addClass( "ui-spinner-input" )
14978 .attr( "autocomplete", "off" )
14979 .wrap( this._uiSpinnerHtml() )
14980 .parent()
14981 // add buttons
14982 .append( this._buttonHtml() );
14983
14984 this.element.attr( "role", "spinbutton" );
14985
14986 // button bindings
14987 this.buttons = uiSpinner.find( ".ui-spinner-button" )
14988 .attr( "tabIndex", -1 )
14989 .button()
14990 .removeClass( "ui-corner-all" );
14991
14992 // IE 6 doesn't understand height: 50% for the buttons
14993 // unless the wrapper has an explicit height
14994 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
14995 uiSpinner.height() > 0 ) {
14996 uiSpinner.height( uiSpinner.height() );
14997 }
14998
14999 // disable spinner if element was already disabled
15000 if ( this.options.disabled ) {
15001 this.disable();
15002 }
15003 },
15004
15005 _keydown: function( event ) {
15006 var options = this.options,
15007 keyCode = $.ui.keyCode;
15008
15009 switch ( event.keyCode ) {
15010 case keyCode.UP:
15011 this._repeat( null, 1, event );
15012 return true;
15013 case keyCode.DOWN:
15014 this._repeat( null, -1, event );
15015 return true;
15016 case keyCode.PAGE_UP:
15017 this._repeat( null, options.page, event );
15018 return true;
15019 case keyCode.PAGE_DOWN:
15020 this._repeat( null, -options.page, event );
15021 return true;
15022 }
15023
15024 return false;
15025 },
15026
15027 _uiSpinnerHtml: function() {
15028 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
15029 },
15030
15031 _buttonHtml: function() {
15032 return "" +
15033 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
15034 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
15035 "</a>" +
15036 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
15037 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
15038 "</a>";
15039 },
15040
15041 _start: function( event ) {
15042 if ( !this.spinning && this._trigger( "start", event ) === false ) {
15043 return false;
15044 }
15045
15046 if ( !this.counter ) {
15047 this.counter = 1;
15048 }
15049 this.spinning = true;
15050 return true;
15051 },
15052
15053 _repeat: function( i, steps, event ) {
15054 i = i || 500;
15055
15056 clearTimeout( this.timer );
15057 this.timer = this._delay(function() {
15058 this._repeat( 40, steps, event );
15059 }, i );
15060
15061 this._spin( steps * this.options.step, event );
15062 },
15063
15064 _spin: function( step, event ) {
15065 var value = this.value() || 0;
15066
15067 if ( !this.counter ) {
15068 this.counter = 1;
15069 }
15070
15071 value = this._adjustValue( value + step * this._increment( this.counter ) );
15072
15073 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
15074 this._value( value );
15075 this.counter++;
15076 }
15077 },
15078
15079 _increment: function( i ) {
15080 var incremental = this.options.incremental;
15081
15082 if ( incremental ) {
15083 return $.isFunction( incremental ) ?
15084 incremental( i ) :
15085 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
15086 }
15087
15088 return 1;
15089 },
15090
15091 _precision: function() {
15092 var precision = this._precisionOf( this.options.step );
15093 if ( this.options.min !== null ) {
15094 precision = Math.max( precision, this._precisionOf( this.options.min ) );
15095 }
15096 return precision;
15097 },
15098
15099 _precisionOf: function( num ) {
15100 var str = num.toString(),
15101 decimal = str.indexOf( "." );
15102 return decimal === -1 ? 0 : str.length - decimal - 1;
15103 },
15104
15105 _adjustValue: function( value ) {
15106 var base, aboveMin,
15107 options = this.options;
15108
15109 // make sure we're at a valid step
15110 // - find out where we are relative to the base (min or 0)
15111 base = options.min !== null ? options.min : 0;
15112 aboveMin = value - base;
15113 // - round to the nearest step
15114 aboveMin = Math.round(aboveMin / options.step) * options.step;
15115 // - rounding is based on 0, so adjust back to our base
15116 value = base + aboveMin;
15117
15118 // fix precision from bad JS floating point math
15119 value = parseFloat( value.toFixed( this._precision() ) );
15120
15121 // clamp the value
15122 if ( options.max !== null && value > options.max) {
15123 return options.max;
15124 }
15125 if ( options.min !== null && value < options.min ) {
15126 return options.min;
15127 }
15128
15129 return value;
15130 },
15131
15132 _stop: function( event ) {
15133 if ( !this.spinning ) {
15134 return;
15135 }
15136
15137 clearTimeout( this.timer );
15138 clearTimeout( this.mousewheelTimer );
15139 this.counter = 0;
15140 this.spinning = false;
15141 this._trigger( "stop", event );
15142 },
15143
15144 _setOption: function( key, value ) {
15145 if ( key === "culture" || key === "numberFormat" ) {
15146 var prevValue = this._parse( this.element.val() );
15147 this.options[ key ] = value;
15148 this.element.val( this._format( prevValue ) );
15149 return;
15150 }
15151
15152 if ( key === "max" || key === "min" || key === "step" ) {
15153 if ( typeof value === "string" ) {
15154 value = this._parse( value );
15155 }
15156 }
15157 if ( key === "icons" ) {
15158 this.buttons.first().find( ".ui-icon" )
15159 .removeClass( this.options.icons.up )
15160 .addClass( value.up );
15161 this.buttons.last().find( ".ui-icon" )
15162 .removeClass( this.options.icons.down )
15163 .addClass( value.down );
15164 }
15165
15166 this._super( key, value );
15167
15168 if ( key === "disabled" ) {
15169 this.widget().toggleClass( "ui-state-disabled", !!value );
15170 this.element.prop( "disabled", !!value );
15171 this.buttons.button( value ? "disable" : "enable" );
15172 }
15173 },
15174
15175 _setOptions: spinner_modifier(function( options ) {
15176 this._super( options );
15177 }),
15178
15179 _parse: function( val ) {
15180 if ( typeof val === "string" && val !== "" ) {
15181 val = window.Globalize && this.options.numberFormat ?
15182 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
15183 }
15184 return val === "" || isNaN( val ) ? null : val;
15185 },
15186
15187 _format: function( value ) {
15188 if ( value === "" ) {
15189 return "";
15190 }
15191 return window.Globalize && this.options.numberFormat ?
15192 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
15193 value;
15194 },
15195
15196 _refresh: function() {
15197 this.element.attr({
15198 "aria-valuemin": this.options.min,
15199 "aria-valuemax": this.options.max,
15200 // TODO: what should we do with values that can't be parsed?
15201 "aria-valuenow": this._parse( this.element.val() )
15202 });
15203 },
15204
15205 isValid: function() {
15206 var value = this.value();
15207
15208 // null is invalid
15209 if ( value === null ) {
15210 return false;
15211 }
15212
15213 // if value gets adjusted, it's invalid
15214 return value === this._adjustValue( value );
15215 },
15216
15217 // update the value without triggering change
15218 _value: function( value, allowAny ) {
15219 var parsed;
15220 if ( value !== "" ) {
15221 parsed = this._parse( value );
15222 if ( parsed !== null ) {
15223 if ( !allowAny ) {
15224 parsed = this._adjustValue( parsed );
15225 }
15226 value = this._format( parsed );
15227 }
15228 }
15229 this.element.val( value );
15230 this._refresh();
15231 },
15232
15233 _destroy: function() {
15234 this.element
15235 .removeClass( "ui-spinner-input" )
15236 .prop( "disabled", false )
15237 .removeAttr( "autocomplete" )
15238 .removeAttr( "role" )
15239 .removeAttr( "aria-valuemin" )
15240 .removeAttr( "aria-valuemax" )
15241 .removeAttr( "aria-valuenow" );
15242 this.uiSpinner.replaceWith( this.element );
15243 },
15244
15245 stepUp: spinner_modifier(function( steps ) {
15246 this._stepUp( steps );
15247 }),
15248 _stepUp: function( steps ) {
15249 if ( this._start() ) {
15250 this._spin( (steps || 1) * this.options.step );
15251 this._stop();
15252 }
15253 },
15254
15255 stepDown: spinner_modifier(function( steps ) {
15256 this._stepDown( steps );
15257 }),
15258 _stepDown: function( steps ) {
15259 if ( this._start() ) {
15260 this._spin( (steps || 1) * -this.options.step );
15261 this._stop();
15262 }
15263 },
15264
15265 pageUp: spinner_modifier(function( pages ) {
15266 this._stepUp( (pages || 1) * this.options.page );
15267 }),
15268
15269 pageDown: spinner_modifier(function( pages ) {
15270 this._stepDown( (pages || 1) * this.options.page );
15271 }),
15272
15273 value: function( newVal ) {
15274 if ( !arguments.length ) {
15275 return this._parse( this.element.val() );
15276 }
15277 spinner_modifier( this._value ).call( this, newVal );
15278 },
15279
15280 widget: function() {
15281 return this.uiSpinner;
15282 }
15283 });
15284
15285
15286 /*!
15287 * jQuery UI Tabs 1.11.4
15288 * http://jqueryui.com
15289 *
15290 * Copyright jQuery Foundation and other contributors
15291 * Released under the MIT license.
15292 * http://jquery.org/license
15293 *
15294 * http://api.jqueryui.com/tabs/
15295 */
15296
15297
15298 var tabs = $.widget( "ui.tabs", {
15299 version: "1.11.4",
15300 delay: 300,
15301 options: {
15302 active: null,
15303 collapsible: false,
15304 event: "click",
15305 heightStyle: "content",
15306 hide: null,
15307 show: null,
15308
15309 // callbacks
15310 activate: null,
15311 beforeActivate: null,
15312 beforeLoad: null,
15313 load: null
15314 },
15315
15316 _isLocal: (function() {
15317 var rhash = /#.*$/;
15318
15319 return function( anchor ) {
15320 var anchorUrl, locationUrl;
15321
15322 // support: IE7
15323 // IE7 doesn't normalize the href property when set via script (#9317)
15324 anchor = anchor.cloneNode( false );
15325
15326 anchorUrl = anchor.href.replace( rhash, "" );
15327 locationUrl = location.href.replace( rhash, "" );
15328
15329 // decoding may throw an error if the URL isn't UTF-8 (#9518)
15330 try {
15331 anchorUrl = decodeURIComponent( anchorUrl );
15332 } catch ( error ) {}
15333 try {
15334 locationUrl = decodeURIComponent( locationUrl );
15335 } catch ( error ) {}
15336
15337 return anchor.hash.length > 1 && anchorUrl === locationUrl;
15338 };
15339 })(),
15340
15341 _create: function() {
15342 var that = this,
15343 options = this.options;
15344
15345 this.running = false;
15346
15347 this.element
15348 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
15349 .toggleClass( "ui-tabs-collapsible", options.collapsible );
15350
15351 this._processTabs();
15352 options.active = this._initialActive();
15353
15354 // Take disabling tabs via class attribute from HTML
15355 // into account and update option properly.
15356 if ( $.isArray( options.disabled ) ) {
15357 options.disabled = $.unique( options.disabled.concat(
15358 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
15359 return that.tabs.index( li );
15360 })
15361 ) ).sort();
15362 }
15363
15364 // check for length avoids error when initializing empty list
15365 if ( this.options.active !== false && this.anchors.length ) {
15366 this.active = this._findActive( options.active );
15367 } else {
15368 this.active = $();
15369 }
15370
15371 this._refresh();
15372
15373 if ( this.active.length ) {
15374 this.load( options.active );
15375 }
15376 },
15377
15378 _initialActive: function() {
15379 var active = this.options.active,
15380 collapsible = this.options.collapsible,
15381 locationHash = location.hash.substring( 1 );
15382
15383 if ( active === null ) {
15384 // check the fragment identifier in the URL
15385 if ( locationHash ) {
15386 this.tabs.each(function( i, tab ) {
15387 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
15388 active = i;
15389 return false;
15390 }
15391 });
15392 }
15393
15394 // check for a tab marked active via a class
15395 if ( active === null ) {
15396 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
15397 }
15398
15399 // no active tab, set to false
15400 if ( active === null || active === -1 ) {
15401 active = this.tabs.length ? 0 : false;
15402 }
15403 }
15404
15405 // handle numbers: negative, out of range
15406 if ( active !== false ) {
15407 active = this.tabs.index( this.tabs.eq( active ) );
15408 if ( active === -1 ) {
15409 active = collapsible ? false : 0;
15410 }
15411 }
15412
15413 // don't allow collapsible: false and active: false
15414 if ( !collapsible && active === false && this.anchors.length ) {
15415 active = 0;
15416 }
15417
15418 return active;
15419 },
15420
15421 _getCreateEventData: function() {
15422 return {
15423 tab: this.active,
15424 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
15425 };
15426 },
15427
15428 _tabKeydown: function( event ) {
15429 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
15430 selectedIndex = this.tabs.index( focusedTab ),
15431 goingForward = true;
15432
15433 if ( this._handlePageNav( event ) ) {
15434 return;
15435 }
15436
15437 switch ( event.keyCode ) {
15438 case $.ui.keyCode.RIGHT:
15439 case $.ui.keyCode.DOWN:
15440 selectedIndex++;
15441 break;
15442 case $.ui.keyCode.UP:
15443 case $.ui.keyCode.LEFT:
15444 goingForward = false;
15445 selectedIndex--;
15446 break;
15447 case $.ui.keyCode.END:
15448 selectedIndex = this.anchors.length - 1;
15449 break;
15450 case $.ui.keyCode.HOME:
15451 selectedIndex = 0;
15452 break;
15453 case $.ui.keyCode.SPACE:
15454 // Activate only, no collapsing
15455 event.preventDefault();
15456 clearTimeout( this.activating );
15457 this._activate( selectedIndex );
15458 return;
15459 case $.ui.keyCode.ENTER:
15460 // Toggle (cancel delayed activation, allow collapsing)
15461 event.preventDefault();
15462 clearTimeout( this.activating );
15463 // Determine if we should collapse or activate
15464 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
15465 return;
15466 default:
15467 return;
15468 }
15469
15470 // Focus the appropriate tab, based on which key was pressed
15471 event.preventDefault();
15472 clearTimeout( this.activating );
15473 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
15474
15475 // Navigating with control/command key will prevent automatic activation
15476 if ( !event.ctrlKey && !event.metaKey ) {
15477
15478 // Update aria-selected immediately so that AT think the tab is already selected.
15479 // Otherwise AT may confuse the user by stating that they need to activate the tab,
15480 // but the tab will already be activated by the time the announcement finishes.
15481 focusedTab.attr( "aria-selected", "false" );
15482 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
15483
15484 this.activating = this._delay(function() {
15485 this.option( "active", selectedIndex );
15486 }, this.delay );
15487 }
15488 },
15489
15490 _panelKeydown: function( event ) {
15491 if ( this._handlePageNav( event ) ) {
15492 return;
15493 }
15494
15495 // Ctrl+up moves focus to the current tab
15496 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
15497 event.preventDefault();
15498 this.active.focus();
15499 }
15500 },
15501
15502 // Alt+page up/down moves focus to the previous/next tab (and activates)
15503 _handlePageNav: function( event ) {
15504 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
15505 this._activate( this._focusNextTab( this.options.active - 1, false ) );
15506 return true;
15507 }
15508 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
15509 this._activate( this._focusNextTab( this.options.active + 1, true ) );
15510 return true;
15511 }
15512 },
15513
15514 _findNextTab: function( index, goingForward ) {
15515 var lastTabIndex = this.tabs.length - 1;
15516
15517 function constrain() {
15518 if ( index > lastTabIndex ) {
15519 index = 0;
15520 }
15521 if ( index < 0 ) {
15522 index = lastTabIndex;
15523 }
15524 return index;
15525 }
15526
15527 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
15528 index = goingForward ? index + 1 : index - 1;
15529 }
15530
15531 return index;
15532 },
15533
15534 _focusNextTab: function( index, goingForward ) {
15535 index = this._findNextTab( index, goingForward );
15536 this.tabs.eq( index ).focus();
15537 return index;
15538 },
15539
15540 _setOption: function( key, value ) {
15541 if ( key === "active" ) {
15542 // _activate() will handle invalid values and update this.options
15543 this._activate( value );
15544 return;
15545 }
15546
15547 if ( key === "disabled" ) {
15548 // don't use the widget factory's disabled handling
15549 this._setupDisabled( value );
15550 return;
15551 }
15552
15553 this._super( key, value);
15554
15555 if ( key === "collapsible" ) {
15556 this.element.toggleClass( "ui-tabs-collapsible", value );
15557 // Setting collapsible: false while collapsed; open first panel
15558 if ( !value && this.options.active === false ) {
15559 this._activate( 0 );
15560 }
15561 }
15562
15563 if ( key === "event" ) {
15564 this._setupEvents( value );
15565 }
15566
15567 if ( key === "heightStyle" ) {
15568 this._setupHeightStyle( value );
15569 }
15570 },
15571
15572 _sanitizeSelector: function( hash ) {
15573 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
15574 },
15575
15576 refresh: function() {
15577 var options = this.options,
15578 lis = this.tablist.children( ":has(a[href])" );
15579
15580 // get disabled tabs from class attribute from HTML
15581 // this will get converted to a boolean if needed in _refresh()
15582 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
15583 return lis.index( tab );
15584 });
15585
15586 this._processTabs();
15587
15588 // was collapsed or no tabs
15589 if ( options.active === false || !this.anchors.length ) {
15590 options.active = false;
15591 this.active = $();
15592 // was active, but active tab is gone
15593 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
15594 // all remaining tabs are disabled
15595 if ( this.tabs.length === options.disabled.length ) {
15596 options.active = false;
15597 this.active = $();
15598 // activate previous tab
15599 } else {
15600 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
15601 }
15602 // was active, active tab still exists
15603 } else {
15604 // make sure active index is correct
15605 options.active = this.tabs.index( this.active );
15606 }
15607
15608 this._refresh();
15609 },
15610
15611 _refresh: function() {
15612 this._setupDisabled( this.options.disabled );
15613 this._setupEvents( this.options.event );
15614 this._setupHeightStyle( this.options.heightStyle );
15615
15616 this.tabs.not( this.active ).attr({
15617 "aria-selected": "false",
15618 "aria-expanded": "false",
15619 tabIndex: -1
15620 });
15621 this.panels.not( this._getPanelForTab( this.active ) )
15622 .hide()
15623 .attr({
15624 "aria-hidden": "true"
15625 });
15626
15627 // Make sure one tab is in the tab order
15628 if ( !this.active.length ) {
15629 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
15630 } else {
15631 this.active
15632 .addClass( "ui-tabs-active ui-state-active" )
15633 .attr({
15634 "aria-selected": "true",
15635 "aria-expanded": "true",
15636 tabIndex: 0
15637 });
15638 this._getPanelForTab( this.active )
15639 .show()
15640 .attr({
15641 "aria-hidden": "false"
15642 });
15643 }
15644 },
15645
15646 _processTabs: function() {
15647 var that = this,
15648 prevTabs = this.tabs,
15649 prevAnchors = this.anchors,
15650 prevPanels = this.panels;
15651
15652 this.tablist = this._getList()
15653 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15654 .attr( "role", "tablist" )
15655
15656 // Prevent users from focusing disabled tabs via click
15657 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
15658 if ( $( this ).is( ".ui-state-disabled" ) ) {
15659 event.preventDefault();
15660 }
15661 })
15662
15663 // support: IE <9
15664 // Preventing the default action in mousedown doesn't prevent IE
15665 // from focusing the element, so if the anchor gets focused, blur.
15666 // We don't have to worry about focusing the previously focused
15667 // element since clicking on a non-focusable element should focus
15668 // the body anyway.
15669 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
15670 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
15671 this.blur();
15672 }
15673 });
15674
15675 this.tabs = this.tablist.find( "> li:has(a[href])" )
15676 .addClass( "ui-state-default ui-corner-top" )
15677 .attr({
15678 role: "tab",
15679 tabIndex: -1
15680 });
15681
15682 this.anchors = this.tabs.map(function() {
15683 return $( "a", this )[ 0 ];
15684 })
15685 .addClass( "ui-tabs-anchor" )
15686 .attr({
15687 role: "presentation",
15688 tabIndex: -1
15689 });
15690
15691 this.panels = $();
15692
15693 this.anchors.each(function( i, anchor ) {
15694 var selector, panel, panelId,
15695 anchorId = $( anchor ).uniqueId().attr( "id" ),
15696 tab = $( anchor ).closest( "li" ),
15697 originalAriaControls = tab.attr( "aria-controls" );
15698
15699 // inline tab
15700 if ( that._isLocal( anchor ) ) {
15701 selector = anchor.hash;
15702 panelId = selector.substring( 1 );
15703 panel = that.element.find( that._sanitizeSelector( selector ) );
15704 // remote tab
15705 } else {
15706 // If the tab doesn't already have aria-controls,
15707 // generate an id by using a throw-away element
15708 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
15709 selector = "#" + panelId;
15710 panel = that.element.find( selector );
15711 if ( !panel.length ) {
15712 panel = that._createPanel( panelId );
15713 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
15714 }
15715 panel.attr( "aria-live", "polite" );
15716 }
15717
15718 if ( panel.length) {
15719 that.panels = that.panels.add( panel );
15720 }
15721 if ( originalAriaControls ) {
15722 tab.data( "ui-tabs-aria-controls", originalAriaControls );
15723 }
15724 tab.attr({
15725 "aria-controls": panelId,
15726 "aria-labelledby": anchorId
15727 });
15728 panel.attr( "aria-labelledby", anchorId );
15729 });
15730
15731 this.panels
15732 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15733 .attr( "role", "tabpanel" );
15734
15735 // Avoid memory leaks (#10056)
15736 if ( prevTabs ) {
15737 this._off( prevTabs.not( this.tabs ) );
15738 this._off( prevAnchors.not( this.anchors ) );
15739 this._off( prevPanels.not( this.panels ) );
15740 }
15741 },
15742
15743 // allow overriding how to find the list for rare usage scenarios (#7715)
15744 _getList: function() {
15745 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
15746 },
15747
15748 _createPanel: function( id ) {
15749 return $( "<div>" )
15750 .attr( "id", id )
15751 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15752 .data( "ui-tabs-destroy", true );
15753 },
15754
15755 _setupDisabled: function( disabled ) {
15756 if ( $.isArray( disabled ) ) {
15757 if ( !disabled.length ) {
15758 disabled = false;
15759 } else if ( disabled.length === this.anchors.length ) {
15760 disabled = true;
15761 }
15762 }
15763
15764 // disable tabs
15765 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
15766 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
15767 $( li )
15768 .addClass( "ui-state-disabled" )
15769 .attr( "aria-disabled", "true" );
15770 } else {
15771 $( li )
15772 .removeClass( "ui-state-disabled" )
15773 .removeAttr( "aria-disabled" );
15774 }
15775 }
15776
15777 this.options.disabled = disabled;
15778 },
15779
15780 _setupEvents: function( event ) {
15781 var events = {};
15782 if ( event ) {
15783 $.each( event.split(" "), function( index, eventName ) {
15784 events[ eventName ] = "_eventHandler";
15785 });
15786 }
15787
15788 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
15789 // Always prevent the default action, even when disabled
15790 this._on( true, this.anchors, {
15791 click: function( event ) {
15792 event.preventDefault();
15793 }
15794 });
15795 this._on( this.anchors, events );
15796 this._on( this.tabs, { keydown: "_tabKeydown" } );
15797 this._on( this.panels, { keydown: "_panelKeydown" } );
15798
15799 this._focusable( this.tabs );
15800 this._hoverable( this.tabs );
15801 },
15802
15803 _setupHeightStyle: function( heightStyle ) {
15804 var maxHeight,
15805 parent = this.element.parent();
15806
15807 if ( heightStyle === "fill" ) {
15808 maxHeight = parent.height();
15809 maxHeight -= this.element.outerHeight() - this.element.height();
15810
15811 this.element.siblings( ":visible" ).each(function() {
15812 var elem = $( this ),
15813 position = elem.css( "position" );
15814
15815 if ( position === "absolute" || position === "fixed" ) {
15816 return;
15817 }
15818 maxHeight -= elem.outerHeight( true );
15819 });
15820
15821 this.element.children().not( this.panels ).each(function() {
15822 maxHeight -= $( this ).outerHeight( true );
15823 });
15824
15825 this.panels.each(function() {
15826 $( this ).height( Math.max( 0, maxHeight -
15827 $( this ).innerHeight() + $( this ).height() ) );
15828 })
15829 .css( "overflow", "auto" );
15830 } else if ( heightStyle === "auto" ) {
15831 maxHeight = 0;
15832 this.panels.each(function() {
15833 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
15834 }).height( maxHeight );
15835 }
15836 },
15837
15838 _eventHandler: function( event ) {
15839 var options = this.options,
15840 active = this.active,
15841 anchor = $( event.currentTarget ),
15842 tab = anchor.closest( "li" ),
15843 clickedIsActive = tab[ 0 ] === active[ 0 ],
15844 collapsing = clickedIsActive && options.collapsible,
15845 toShow = collapsing ? $() : this._getPanelForTab( tab ),
15846 toHide = !active.length ? $() : this._getPanelForTab( active ),
15847 eventData = {
15848 oldTab: active,
15849 oldPanel: toHide,
15850 newTab: collapsing ? $() : tab,
15851 newPanel: toShow
15852 };
15853
15854 event.preventDefault();
15855
15856 if ( tab.hasClass( "ui-state-disabled" ) ||
15857 // tab is already loading
15858 tab.hasClass( "ui-tabs-loading" ) ||
15859 // can't switch durning an animation
15860 this.running ||
15861 // click on active header, but not collapsible
15862 ( clickedIsActive && !options.collapsible ) ||
15863 // allow canceling activation
15864 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
15865 return;
15866 }
15867
15868 options.active = collapsing ? false : this.tabs.index( tab );
15869
15870 this.active = clickedIsActive ? $() : tab;
15871 if ( this.xhr ) {
15872 this.xhr.abort();
15873 }
15874
15875 if ( !toHide.length && !toShow.length ) {
15876 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
15877 }
15878
15879 if ( toShow.length ) {
15880 this.load( this.tabs.index( tab ), event );
15881 }
15882 this._toggle( event, eventData );
15883 },
15884
15885 // handles show/hide for selecting tabs
15886 _toggle: function( event, eventData ) {
15887 var that = this,
15888 toShow = eventData.newPanel,
15889 toHide = eventData.oldPanel;
15890
15891 this.running = true;
15892
15893 function complete() {
15894 that.running = false;
15895 that._trigger( "activate", event, eventData );
15896 }
15897
15898 function show() {
15899 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
15900
15901 if ( toShow.length && that.options.show ) {
15902 that._show( toShow, that.options.show, complete );
15903 } else {
15904 toShow.show();
15905 complete();
15906 }
15907 }
15908
15909 // start out by hiding, then showing, then completing
15910 if ( toHide.length && this.options.hide ) {
15911 this._hide( toHide, this.options.hide, function() {
15912 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15913 show();
15914 });
15915 } else {
15916 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15917 toHide.hide();
15918 show();
15919 }
15920
15921 toHide.attr( "aria-hidden", "true" );
15922 eventData.oldTab.attr({
15923 "aria-selected": "false",
15924 "aria-expanded": "false"
15925 });
15926 // If we're switching tabs, remove the old tab from the tab order.
15927 // If we're opening from collapsed state, remove the previous tab from the tab order.
15928 // If we're collapsing, then keep the collapsing tab in the tab order.
15929 if ( toShow.length && toHide.length ) {
15930 eventData.oldTab.attr( "tabIndex", -1 );
15931 } else if ( toShow.length ) {
15932 this.tabs.filter(function() {
15933 return $( this ).attr( "tabIndex" ) === 0;
15934 })
15935 .attr( "tabIndex", -1 );
15936 }
15937
15938 toShow.attr( "aria-hidden", "false" );
15939 eventData.newTab.attr({
15940 "aria-selected": "true",
15941 "aria-expanded": "true",
15942 tabIndex: 0
15943 });
15944 },
15945
15946 _activate: function( index ) {
15947 var anchor,
15948 active = this._findActive( index );
15949
15950 // trying to activate the already active panel
15951 if ( active[ 0 ] === this.active[ 0 ] ) {
15952 return;
15953 }
15954
15955 // trying to collapse, simulate a click on the current active header
15956 if ( !active.length ) {
15957 active = this.active;
15958 }
15959
15960 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
15961 this._eventHandler({
15962 target: anchor,
15963 currentTarget: anchor,
15964 preventDefault: $.noop
15965 });
15966 },
15967
15968 _findActive: function( index ) {
15969 return index === false ? $() : this.tabs.eq( index );
15970 },
15971
15972 _getIndex: function( index ) {
15973 // meta-function to give users option to provide a href string instead of a numerical index.
15974 if ( typeof index === "string" ) {
15975 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
15976 }
15977
15978 return index;
15979 },
15980
15981 _destroy: function() {
15982 if ( this.xhr ) {
15983 this.xhr.abort();
15984 }
15985
15986 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
15987
15988 this.tablist
15989 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15990 .removeAttr( "role" );
15991
15992 this.anchors
15993 .removeClass( "ui-tabs-anchor" )
15994 .removeAttr( "role" )
15995 .removeAttr( "tabIndex" )
15996 .removeUniqueId();
15997
15998 this.tablist.unbind( this.eventNamespace );
15999
16000 this.tabs.add( this.panels ).each(function() {
16001 if ( $.data( this, "ui-tabs-destroy" ) ) {
16002 $( this ).remove();
16003 } else {
16004 $( this )
16005 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
16006 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
16007 .removeAttr( "tabIndex" )
16008 .removeAttr( "aria-live" )
16009 .removeAttr( "aria-busy" )
16010 .removeAttr( "aria-selected" )
16011 .removeAttr( "aria-labelledby" )
16012 .removeAttr( "aria-hidden" )
16013 .removeAttr( "aria-expanded" )
16014 .removeAttr( "role" );
16015 }
16016 });
16017
16018 this.tabs.each(function() {
16019 var li = $( this ),
16020 prev = li.data( "ui-tabs-aria-controls" );
16021 if ( prev ) {
16022 li
16023 .attr( "aria-controls", prev )
16024 .removeData( "ui-tabs-aria-controls" );
16025 } else {
16026 li.removeAttr( "aria-controls" );
16027 }
16028 });
16029
16030 this.panels.show();
16031
16032 if ( this.options.heightStyle !== "content" ) {
16033 this.panels.css( "height", "" );
16034 }
16035 },
16036
16037 enable: function( index ) {
16038 var disabled = this.options.disabled;
16039 if ( disabled === false ) {
16040 return;
16041 }
16042
16043 if ( index === undefined ) {
16044 disabled = false;
16045 } else {
16046 index = this._getIndex( index );
16047 if ( $.isArray( disabled ) ) {
16048 disabled = $.map( disabled, function( num ) {
16049 return num !== index ? num : null;
16050 });
16051 } else {
16052 disabled = $.map( this.tabs, function( li, num ) {
16053 return num !== index ? num : null;
16054 });
16055 }
16056 }
16057 this._setupDisabled( disabled );
16058 },
16059
16060 disable: function( index ) {
16061 var disabled = this.options.disabled;
16062 if ( disabled === true ) {
16063 return;
16064 }
16065
16066 if ( index === undefined ) {
16067 disabled = true;
16068 } else {
16069 index = this._getIndex( index );
16070 if ( $.inArray( index, disabled ) !== -1 ) {
16071 return;
16072 }
16073 if ( $.isArray( disabled ) ) {
16074 disabled = $.merge( [ index ], disabled ).sort();
16075 } else {
16076 disabled = [ index ];
16077 }
16078 }
16079 this._setupDisabled( disabled );
16080 },
16081
16082 load: function( index, event ) {
16083 index = this._getIndex( index );
16084 var that = this,
16085 tab = this.tabs.eq( index ),
16086 anchor = tab.find( ".ui-tabs-anchor" ),
16087 panel = this._getPanelForTab( tab ),
16088 eventData = {
16089 tab: tab,
16090 panel: panel
16091 },
16092 complete = function( jqXHR, status ) {
16093 if ( status === "abort" ) {
16094 that.panels.stop( false, true );
16095 }
16096
16097 tab.removeClass( "ui-tabs-loading" );
16098 panel.removeAttr( "aria-busy" );
16099
16100 if ( jqXHR === that.xhr ) {
16101 delete that.xhr;
16102 }
16103 };
16104
16105 // not remote
16106 if ( this._isLocal( anchor[ 0 ] ) ) {
16107 return;
16108 }
16109
16110 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
16111
16112 // support: jQuery <1.8
16113 // jQuery <1.8 returns false if the request is canceled in beforeSend,
16114 // but as of 1.8, $.ajax() always returns a jqXHR object.
16115 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
16116 tab.addClass( "ui-tabs-loading" );
16117 panel.attr( "aria-busy", "true" );
16118
16119 this.xhr
16120 .done(function( response, status, jqXHR ) {
16121 // support: jQuery <1.8
16122 // http://bugs.jquery.com/ticket/11778
16123 setTimeout(function() {
16124 panel.html( response );
16125 that._trigger( "load", event, eventData );
16126
16127 complete( jqXHR, status );
16128 }, 1 );
16129 })
16130 .fail(function( jqXHR, status ) {
16131 // support: jQuery <1.8
16132 // http://bugs.jquery.com/ticket/11778
16133 setTimeout(function() {
16134 complete( jqXHR, status );
16135 }, 1 );
16136 });
16137 }
16138 },
16139
16140 _ajaxSettings: function( anchor, event, eventData ) {
16141 var that = this;
16142 return {
16143 url: anchor.attr( "href" ),
16144 beforeSend: function( jqXHR, settings ) {
16145 return that._trigger( "beforeLoad", event,
16146 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
16147 }
16148 };
16149 },
16150
16151 _getPanelForTab: function( tab ) {
16152 var id = $( tab ).attr( "aria-controls" );
16153 return this.element.find( this._sanitizeSelector( "#" + id ) );
16154 }
16155 });
16156
16157
16158 /*!
16159 * jQuery UI Tooltip 1.11.4
16160 * http://jqueryui.com
16161 *
16162 * Copyright jQuery Foundation and other contributors
16163 * Released under the MIT license.
16164 * http://jquery.org/license
16165 *
16166 * http://api.jqueryui.com/tooltip/
16167 */
16168
16169
16170 var tooltip = $.widget( "ui.tooltip", {
16171 version: "1.11.4",
16172 options: {
16173 content: function() {
16174 // support: IE<9, Opera in jQuery <1.7
16175 // .text() can't accept undefined, so coerce to a string
16176 var title = $( this ).attr( "title" ) || "";
16177 // Escape title, since we're going from an attribute to raw HTML
16178 return $( "<a>" ).text( title ).html();
16179 },
16180 hide: true,
16181 // Disabled elements have inconsistent behavior across browsers (#8661)
16182 items: "[title]:not([disabled])",
16183 position: {
16184 my: "left top+15",
16185 at: "left bottom",
16186 collision: "flipfit flip"
16187 },
16188 show: true,
16189 tooltipClass: null,
16190 track: false,
16191
16192 // callbacks
16193 close: null,
16194 open: null
16195 },
16196
16197 _addDescribedBy: function( elem, id ) {
16198 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
16199 describedby.push( id );
16200 elem
16201 .data( "ui-tooltip-id", id )
16202 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
16203 },
16204
16205 _removeDescribedBy: function( elem ) {
16206 var id = elem.data( "ui-tooltip-id" ),
16207 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
16208 index = $.inArray( id, describedby );
16209
16210 if ( index !== -1 ) {
16211 describedby.splice( index, 1 );
16212 }
16213
16214 elem.removeData( "ui-tooltip-id" );
16215 describedby = $.trim( describedby.join( " " ) );
16216 if ( describedby ) {
16217 elem.attr( "aria-describedby", describedby );
16218 } else {
16219 elem.removeAttr( "aria-describedby" );
16220 }
16221 },
16222
16223 _create: function() {
16224 this._on({
16225 mouseover: "open",
16226 focusin: "open"
16227 });
16228
16229 // IDs of generated tooltips, needed for destroy
16230 this.tooltips = {};
16231
16232 // IDs of parent tooltips where we removed the title attribute
16233 this.parents = {};
16234
16235 if ( this.options.disabled ) {
16236 this._disable();
16237 }
16238
16239 // Append the aria-live region so tooltips announce correctly
16240 this.liveRegion = $( "<div>" )
16241 .attr({
16242 role: "log",
16243 "aria-live": "assertive",
16244 "aria-relevant": "additions"
16245 })
16246 .addClass( "ui-helper-hidden-accessible" )
16247 .appendTo( this.document[ 0 ].body );
16248 },
16249
16250 _setOption: function( key, value ) {
16251 var that = this;
16252
16253 if ( key === "disabled" ) {
16254 this[ value ? "_disable" : "_enable" ]();
16255 this.options[ key ] = value;
16256 // disable element style changes
16257 return;
16258 }
16259
16260 this._super( key, value );
16261
16262 if ( key === "content" ) {
16263 $.each( this.tooltips, function( id, tooltipData ) {
16264 that._updateContent( tooltipData.element );
16265 });
16266 }
16267 },
16268
16269 _disable: function() {
16270 var that = this;
16271
16272 // close open tooltips
16273 $.each( this.tooltips, function( id, tooltipData ) {
16274 var event = $.Event( "blur" );
16275 event.target = event.currentTarget = tooltipData.element[ 0 ];
16276 that.close( event, true );
16277 });
16278
16279 // remove title attributes to prevent native tooltips
16280 this.element.find( this.options.items ).addBack().each(function() {
16281 var element = $( this );
16282 if ( element.is( "[title]" ) ) {
16283 element
16284 .data( "ui-tooltip-title", element.attr( "title" ) )
16285 .removeAttr( "title" );
16286 }
16287 });
16288 },
16289
16290 _enable: function() {
16291 // restore title attributes
16292 this.element.find( this.options.items ).addBack().each(function() {
16293 var element = $( this );
16294 if ( element.data( "ui-tooltip-title" ) ) {
16295 element.attr( "title", element.data( "ui-tooltip-title" ) );
16296 }
16297 });
16298 },
16299
16300 open: function( event ) {
16301 var that = this,
16302 target = $( event ? event.target : this.element )
16303 // we need closest here due to mouseover bubbling,
16304 // but always pointing at the same event target
16305 .closest( this.options.items );
16306
16307 // No element to show a tooltip for or the tooltip is already open
16308 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
16309 return;
16310 }
16311
16312 if ( target.attr( "title" ) ) {
16313 target.data( "ui-tooltip-title", target.attr( "title" ) );
16314 }
16315
16316 target.data( "ui-tooltip-open", true );
16317
16318 // kill parent tooltips, custom or native, for hover
16319 if ( event && event.type === "mouseover" ) {
16320 target.parents().each(function() {
16321 var parent = $( this ),
16322 blurEvent;
16323 if ( parent.data( "ui-tooltip-open" ) ) {
16324 blurEvent = $.Event( "blur" );
16325 blurEvent.target = blurEvent.currentTarget = this;
16326 that.close( blurEvent, true );
16327 }
16328 if ( parent.attr( "title" ) ) {
16329 parent.uniqueId();
16330 that.parents[ this.id ] = {
16331 element: this,
16332 title: parent.attr( "title" )
16333 };
16334 parent.attr( "title", "" );
16335 }
16336 });
16337 }
16338
16339 this._registerCloseHandlers( event, target );
16340 this._updateContent( target, event );
16341 },
16342
16343 _updateContent: function( target, event ) {
16344 var content,
16345 contentOption = this.options.content,
16346 that = this,
16347 eventType = event ? event.type : null;
16348
16349 if ( typeof contentOption === "string" ) {
16350 return this._open( event, target, contentOption );
16351 }
16352
16353 content = contentOption.call( target[0], function( response ) {
16354
16355 // IE may instantly serve a cached response for ajax requests
16356 // delay this call to _open so the other call to _open runs first
16357 that._delay(function() {
16358
16359 // Ignore async response if tooltip was closed already
16360 if ( !target.data( "ui-tooltip-open" ) ) {
16361 return;
16362 }
16363
16364 // jQuery creates a special event for focusin when it doesn't
16365 // exist natively. To improve performance, the native event
16366 // object is reused and the type is changed. Therefore, we can't
16367 // rely on the type being correct after the event finished
16368 // bubbling, so we set it back to the previous value. (#8740)
16369 if ( event ) {
16370 event.type = eventType;
16371 }
16372 this._open( event, target, response );
16373 });
16374 });
16375 if ( content ) {
16376 this._open( event, target, content );
16377 }
16378 },
16379
16380 _open: function( event, target, content ) {
16381 var tooltipData, tooltip, delayedShow, a11yContent,
16382 positionOption = $.extend( {}, this.options.position );
16383
16384 if ( !content ) {
16385 return;
16386 }
16387
16388 // Content can be updated multiple times. If the tooltip already
16389 // exists, then just update the content and bail.
16390 tooltipData = this._find( target );
16391 if ( tooltipData ) {
16392 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
16393 return;
16394 }
16395
16396 // if we have a title, clear it to prevent the native tooltip
16397 // we have to check first to avoid defining a title if none exists
16398 // (we don't want to cause an element to start matching [title])
16399 //
16400 // We use removeAttr only for key events, to allow IE to export the correct
16401 // accessible attributes. For mouse events, set to empty string to avoid
16402 // native tooltip showing up (happens only when removing inside mouseover).
16403 if ( target.is( "[title]" ) ) {
16404 if ( event && event.type === "mouseover" ) {
16405 target.attr( "title", "" );
16406 } else {
16407 target.removeAttr( "title" );
16408 }
16409 }
16410
16411 tooltipData = this._tooltip( target );
16412 tooltip = tooltipData.tooltip;
16413 this._addDescribedBy( target, tooltip.attr( "id" ) );
16414 tooltip.find( ".ui-tooltip-content" ).html( content );
16415
16416 // Support: Voiceover on OS X, JAWS on IE <= 9
16417 // JAWS announces deletions even when aria-relevant="additions"
16418 // Voiceover will sometimes re-read the entire log region's contents from the beginning
16419 this.liveRegion.children().hide();
16420 if ( content.clone ) {
16421 a11yContent = content.clone();
16422 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
16423 } else {
16424 a11yContent = content;
16425 }
16426 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
16427
16428 function position( event ) {
16429 positionOption.of = event;
16430 if ( tooltip.is( ":hidden" ) ) {
16431 return;
16432 }
16433 tooltip.position( positionOption );
16434 }
16435 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
16436 this._on( this.document, {
16437 mousemove: position
16438 });
16439 // trigger once to override element-relative positioning
16440 position( event );
16441 } else {
16442 tooltip.position( $.extend({
16443 of: target
16444 }, this.options.position ) );
16445 }
16446
16447 tooltip.hide();
16448
16449 this._show( tooltip, this.options.show );
16450 // Handle tracking tooltips that are shown with a delay (#8644). As soon
16451 // as the tooltip is visible, position the tooltip using the most recent
16452 // event.
16453 if ( this.options.show && this.options.show.delay ) {
16454 delayedShow = this.delayedShow = setInterval(function() {
16455 if ( tooltip.is( ":visible" ) ) {
16456 position( positionOption.of );
16457 clearInterval( delayedShow );
16458 }
16459 }, $.fx.interval );
16460 }
16461
16462 this._trigger( "open", event, { tooltip: tooltip } );
16463 },
16464
16465 _registerCloseHandlers: function( event, target ) {
16466 var events = {
16467 keyup: function( event ) {
16468 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
16469 var fakeEvent = $.Event(event);
16470 fakeEvent.currentTarget = target[0];
16471 this.close( fakeEvent, true );
16472 }
16473 }
16474 };
16475
16476 // Only bind remove handler for delegated targets. Non-delegated
16477 // tooltips will handle this in destroy.
16478 if ( target[ 0 ] !== this.element[ 0 ] ) {
16479 events.remove = function() {
16480 this._removeTooltip( this._find( target ).tooltip );
16481 };
16482 }
16483
16484 if ( !event || event.type === "mouseover" ) {
16485 events.mouseleave = "close";
16486 }
16487 if ( !event || event.type === "focusin" ) {
16488 events.focusout = "close";
16489 }
16490 this._on( true, target, events );
16491 },
16492
16493 close: function( event ) {
16494 var tooltip,
16495 that = this,
16496 target = $( event ? event.currentTarget : this.element ),
16497 tooltipData = this._find( target );
16498
16499 // The tooltip may already be closed
16500 if ( !tooltipData ) {
16501
16502 // We set ui-tooltip-open immediately upon open (in open()), but only set the
16503 // additional data once there's actually content to show (in _open()). So even if the
16504 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
16505 // the period between open() and _open().
16506 target.removeData( "ui-tooltip-open" );
16507 return;
16508 }
16509
16510 tooltip = tooltipData.tooltip;
16511
16512 // disabling closes the tooltip, so we need to track when we're closing
16513 // to avoid an infinite loop in case the tooltip becomes disabled on close
16514 if ( tooltipData.closing ) {
16515 return;
16516 }
16517
16518 // Clear the interval for delayed tracking tooltips
16519 clearInterval( this.delayedShow );
16520
16521 // only set title if we had one before (see comment in _open())
16522 // If the title attribute has changed since open(), don't restore
16523 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
16524 target.attr( "title", target.data( "ui-tooltip-title" ) );
16525 }
16526
16527 this._removeDescribedBy( target );
16528
16529 tooltipData.hiding = true;
16530 tooltip.stop( true );
16531 this._hide( tooltip, this.options.hide, function() {
16532 that._removeTooltip( $( this ) );
16533 });
16534
16535 target.removeData( "ui-tooltip-open" );
16536 this._off( target, "mouseleave focusout keyup" );
16537
16538 // Remove 'remove' binding only on delegated targets
16539 if ( target[ 0 ] !== this.element[ 0 ] ) {
16540 this._off( target, "remove" );
16541 }
16542 this._off( this.document, "mousemove" );
16543
16544 if ( event && event.type === "mouseleave" ) {
16545 $.each( this.parents, function( id, parent ) {
16546 $( parent.element ).attr( "title", parent.title );
16547 delete that.parents[ id ];
16548 });
16549 }
16550
16551 tooltipData.closing = true;
16552 this._trigger( "close", event, { tooltip: tooltip } );
16553 if ( !tooltipData.hiding ) {
16554 tooltipData.closing = false;
16555 }
16556 },
16557
16558 _tooltip: function( element ) {
16559 var tooltip = $( "<div>" )
16560 .attr( "role", "tooltip" )
16561 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
16562 ( this.options.tooltipClass || "" ) ),
16563 id = tooltip.uniqueId().attr( "id" );
16564
16565 $( "<div>" )
16566 .addClass( "ui-tooltip-content" )
16567 .appendTo( tooltip );
16568
16569 tooltip.appendTo( this.document[0].body );
16570
16571 return this.tooltips[ id ] = {
16572 element: element,
16573 tooltip: tooltip
16574 };
16575 },
16576
16577 _find: function( target ) {
16578 var id = target.data( "ui-tooltip-id" );
16579 return id ? this.tooltips[ id ] : null;
16580 },
16581
16582 _removeTooltip: function( tooltip ) {
16583 tooltip.remove();
16584 delete this.tooltips[ tooltip.attr( "id" ) ];
16585 },
16586
16587 _destroy: function() {
16588 var that = this;
16589
16590 // close open tooltips
16591 $.each( this.tooltips, function( id, tooltipData ) {
16592 // Delegate to close method to handle common cleanup
16593 var event = $.Event( "blur" ),
16594 element = tooltipData.element;
16595 event.target = event.currentTarget = element[ 0 ];
16596 that.close( event, true );
16597
16598 // Remove immediately; destroying an open tooltip doesn't use the
16599 // hide animation
16600 $( "#" + id ).remove();
16601
16602 // Restore the title
16603 if ( element.data( "ui-tooltip-title" ) ) {
16604 // If the title attribute has changed since open(), don't restore
16605 if ( !element.attr( "title" ) ) {
16606 element.attr( "title", element.data( "ui-tooltip-title" ) );
16607 }
16608 element.removeData( "ui-tooltip-title" );
16609 }
16610 });
16611 this.liveRegion.remove();
16612 }
16613 });
16614
16615
16616
16617 }));